From 5314f0aed984a04a99e94973f9817d5845e65a5e Mon Sep 17 00:00:00 2001 From: km1chno Date: Wed, 20 Nov 2024 10:45:51 +0100 Subject: [PATCH 1/7] feat: support bun --- .../recipes/__snapshots__/detox.test.ts.snap | 438 ++++++++++++++++++ .../recipes/__snapshots__/jest.test.ts.snap | 69 +++ .../recipes/__snapshots__/lint.test.ts.snap | 64 +++ .../__snapshots__/prettier.test.ts.snap | 62 +++ .../__snapshots__/typescript.test.ts.snap | 77 +++ __tests__/recipes/detox.test.ts | 1 + __tests__/recipes/jest.test.ts | 1 + __tests__/recipes/lint.test.ts | 1 + __tests__/recipes/prettier.test.ts | 1 + __tests__/recipes/typescript.test.ts | 1 + __tests__/runtime-version-file.test.ts | 67 +++ .../.gitignore | 24 + .../README.md | 1 + .../app.json | 41 ++ .../app/+html.tsx | 46 ++ .../app/+not-found.tsx | 33 ++ .../app/_layout.tsx | 5 + .../app/details.tsx | 17 + .../app/index.tsx | 19 + .../assets/adaptive-icon.png | Bin 0 -> 17547 bytes .../assets/favicon.png | Bin 0 -> 1466 bytes .../assets/icon.png | Bin 0 -> 22380 bytes .../assets/splash.png | Bin 0 -> 47346 bytes .../babel.config.js | 10 + .../bun.lockb | Bin 0 -> 485406 bytes .../cesconfig.json | 35 ++ .../components/Button.tsx | 41 ++ .../components/Container.tsx | 12 + .../components/EditScreenInfo.tsx | 47 ++ .../components/ScreenContent.tsx | 38 ++ .../metro.config.js | 8 + .../package.json | 55 +++ .../prettier.config.js | 7 + .../tsconfig.json | 12 + __tests__/utils.ts | 11 + src/constants.ts | 1 + src/extensions/dependencies.ts | 2 + src/extensions/projectConfig.ts | 43 ++ src/extensions/workflows.ts | 20 +- .../build-debug/build-debug-android.ejf | 19 +- src/templates/build-debug/build-debug-ios.ejf | 19 +- .../build-debug/lookup-cached-debug-build.ejf | 17 +- .../build-release/build-release-android.ejf | 21 +- .../build-release/build-release-ios.ejf | 21 +- src/templates/common/installCommand.ejs | 12 + src/templates/common/runtimeSetupStep.ejs | 13 + src/templates/detox/test-detox-android.ejf | 23 +- src/templates/detox/test-detox-ios.ejf | 23 +- src/templates/eas/eas.ejf | 21 +- src/templates/jest/jest.ejf | 21 +- src/templates/lint/lint.ejf | 23 +- .../maestro/maestro-test-android.ejf | 24 +- src/templates/maestro/maestro-test-ios.ejf | 24 +- src/templates/model.ts.ejs | 3 - src/templates/prettier/prettier.ejf | 21 +- src/templates/typescript/typescript.ejf | 21 +- 56 files changed, 1394 insertions(+), 242 deletions(-) create mode 100644 __tests__/runtime-version-file.test.ts create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/.gitignore create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/README.md create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app.json create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/+html.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/+not-found.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/_layout.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/details.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/index.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/assets/adaptive-icon.png create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/assets/favicon.png create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/assets/icon.png create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/assets/splash.png create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/babel.config.js create mode 100755 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/bun.lockb create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/cesconfig.json create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/components/Button.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/components/Container.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/components/EditScreenInfo.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/components/ScreenContent.tsx create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/metro.config.js create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/package.json create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/prettier.config.js create mode 100644 __tests__/test-projects/rn-setup-ci-create-expo-stack-bun/tsconfig.json create mode 100644 src/templates/common/installCommand.ejs create mode 100644 src/templates/common/runtimeSetupStep.ejs delete mode 100644 src/templates/model.ts.ejs diff --git a/__tests__/recipes/__snapshots__/detox.test.ts.snap b/__tests__/recipes/__snapshots__/detox.test.ts.snap index 86e21fa..a760c4c 100644 --- a/__tests__/recipes/__snapshots__/detox.test.ts.snap +++ b/__tests__/recipes/__snapshots__/detox.test.ts.snap @@ -453,6 +453,444 @@ jobs: " `; +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 1`] = ` +Object { + "dependencies": Object { + "react": "", + "react-native": "", + }, + "devDependencies": Object { + "@babel/core": "", + "@babel/preset-env": "", + "@babel/runtime": "", + "@react-native/babel-preset": "", + "@react-native/metro-config": "", + "@react-native/typescript-config": "", + "@types/jest": "", + "@types/react": "", + "@types/react-test-renderer": "", + "detox": "", + "jest": "", + "react-test-renderer": "", + "ts-jest": "", + "typescript": "", + }, + "engines": Object { + "node": ">=18", + }, + "name": "RnSetupCiYarnFlat", + "packageManager": "yarn@3.6.4", + "private": true, + "scripts": Object { + "android": "react-native run-android", + "build:release:android": "cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release -Dorg.gradle.jvmargs=-Xmx4g", + "build:release:ios": "cd ios && pod install && cd .. && xcodebuild ONLY_ACTIVE_ARCH=YES -workspace ios/RnSetupCiYarnFlat.xcworkspace -UseNewBuildSystem=YES -scheme RnSetupCiYarnFlat -configuration Release -sdk iphonesimulator -derivedDataPath ios/build -quiet", + "detox:test:android": "detox test --config-path .detoxrc-ci.js --configuration android.emu.release --cleanup", + "detox:test:ios": "detox test --config-path .detoxrc-ci.js --configuration ios.sim.release --cleanup", + "ios": "react-native run-ios", + "start": "react-native start", + }, + "version": "0.0.1", +} +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 2`] = ` +"/** @type {Detox.DetoxConfig} */ +module.exports = { + testRunner: { + args: { + $0: 'jest', + config: 'e2e/jest.config.js', + }, + jest: { + setupTimeout: 300000, + }, + }, + apps: { + 'ios.release': { + type: 'ios.app', + binaryPath: 'ios-release-build/ios-release.app', + }, + 'android.release': { + type: 'android.apk', + binaryPath: 'android-release-build/android-release.apk', + testBinaryPath: 'android-release-build/android-release-test.apk', + }, + }, + devices: { + simulator: { + type: 'ios.simulator', + device: { + type: 'iPhone 15 Pro', + }, + }, + emulator: { + type: 'android.emulator', + device: { + avdName: 'e2e_emulator', + }, + }, + }, + configurations: { + 'ios.sim.release': { + device: 'simulator', + app: 'ios.release', + }, + 'android.emu.release': { + device: 'emulator', + app: 'android.release', + }, + }, +}; +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 3`] = ` +"{ + \\"expo\\": { + \\"name\\": \\"rn-setup-ci-create-expo-stack-bun\\", + \\"slug\\": \\"rn-setup-ci-create-expo-stack-bun\\", + \\"version\\": \\"1.0.0\\", + \\"scheme\\": \\"rn-setup-ci-create-expo-stack-bun\\", + \\"web\\": { + \\"bundler\\": \\"metro\\", + \\"output\\": \\"static\\", + \\"favicon\\": \\"./assets/favicon.png\\" + }, + \\"plugins\\": [\\"expo-router\\", \\"@config-plugins/detox\\"], + \\"experiments\\": { + \\"typedRoutes\\": true, + \\"tsconfigPaths\\": true + }, + \\"orientation\\": \\"portrait\\", + \\"icon\\": \\"./assets/icon.png\\", + \\"userInterfaceStyle\\": \\"light\\", + \\"splash\\": { + \\"image\\": \\"./assets/splash.png\\", + \\"resizeMode\\": \\"contain\\", + \\"backgroundColor\\": \\"#ffffff\\" + }, + \\"assetBundlePatterns\\": [\\"**/*\\"], + \\"ios\\": { + \\"supportsTablet\\": true, + \\"bundleIdentifier\\": \\"com.kmichno.rnsetupcicreateexpostackbun\\" + }, + \\"android\\": { + \\"adaptiveIcon\\": { + \\"foregroundImage\\": \\"./assets/adaptive-icon.png\\", + \\"backgroundColor\\": \\"#ffffff\\" + }, + \\"package\\": \\"com.kmichno.rnsetupcicreateexpostackbun\\" + } + } +} +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 4`] = ` +"/** @type {import('@jest/types').Config.InitialOptions} */ +module.exports = { + preset: 'ts-jest', + rootDir: '..', + testMatch: ['/e2e/**/*.test.ts'], + testTimeout: 300000, + maxWorkers: 1, + globalSetup: 'detox/runners/jest/globalSetup', + globalTeardown: 'detox/runners/jest/globalTeardown', + reporters: ['detox/runners/jest/reporter'], + testEnvironment: 'detox/runners/jest/testEnvironment', + verbose: true, +}; +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 5`] = ` +"import { device, by, element, expect } from 'detox'; + +describe('Example', () => { + beforeAll(async () => { + await device.launchApp(); + }); + + beforeEach(async () => { + await device.reloadReactNative(); + }); + + it('Hello world! to be visible', async () => { + await expect(element(by.text('Hello World!'))).toBeVisible(); + }); +}); +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 6`] = ` +"name: Build Android Release App + +on: + pull_request: + +jobs: + lookup-cached-build: + runs-on: ubuntu-latest + outputs: + build-exists: \${{ steps.android-release-restore.outputs.cache-hit }} + steps: + - name: 🐛 Try to restore build from cache + id: android-release-restore + uses: actions/cache/restore@v4 + with: + lookup-only: true + path: android-release-build/ + key: android-release-build-\${{ github.event.pull_request.head.sha }} + + build-release-android: + needs: lookup-cached-build + if: needs.lookup-cached-build.outputs.build-exists != 'true' + runs-on: ubuntu-latest + steps: + - name: 💾 Maximize build space + uses: AdityaGarg8/remove-unwanted-software@v4.1 + with: + remove-dotnet: 'true' + remove-haskell: 'true' + remove-codeql: 'true' + remove-docker-images: 'true' + + - name: 🏗 Checkout repository + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: ☕ Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'zulu' + + - name: 🐘 Setup Gradle 8.8 + uses: gradle/actions/setup-gradle@v4 + with: + gradle-version: 8.8 + + - name: 🛠️ Build + run: bun run build:release:android + + - name: 📁 Prepare cache folder + run: | + mkdir android-release-build + mv ./android/app/build/outputs/apk/release/app-release.apk android-release-build/android-release.apk + mv ./android/app/build/outputs/apk/androidTest/release/app-release-androidTest.apk android-release-build/android-release-test.apk + + - name: 📡 Store built app in cache + id: android-release-save + uses: actions/cache/save@v4 + with: + path: android-release-build/ + key: android-release-build-\${{ github.event.pull_request.head.sha }} +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 7`] = ` +"name: Build iOS Release App + +on: + pull_request: + +jobs: + lookup-cached-build: + runs-on: ubuntu-latest + outputs: + build-exists: \${{ steps.ios-release-restore.outputs.cache-hit }} + steps: + - name: 🐛 Try to restore build from cache + id: ios-release-restore + uses: actions/cache/restore@v4 + with: + lookup-only: true + path: ios-release-build/ + key: ios-release-build-\${{ github.event.pull_request.head.sha }} + + build-release-ios: + needs: lookup-cached-build + if: needs.lookup-cached-build.outputs.build-exists != 'true' + runs-on: macos-latest + steps: + - name: 🏗 Checkout repository + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 🔨 Use latest stable Xcode + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: 🛠️ Build + run: bun run build:release:ios + + - name: 📁 Prepare cache folder + run: | + mkdir ios-release-build + mv ./ios/build/Build/Products/Release-iphonesimulator/rnsetupcicreateexpostackbun.app ios-release-build/ios-release.app + + - name: 📡 Store built app in cache + id: ios-release-save + uses: actions/cache/save@v4 + with: + path: ios-release-build/ + key: ios-release-build-\${{ github.event.pull_request.head.sha }} +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 8`] = ` +"name: Test Detox Android + +on: + pull_request: + +jobs: + test-detox-android: + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + checks: read + contents: read + env: + API_LEVEL: 34 + steps: + - name: ⌛ Wait for build to finish + uses: poseidon/wait-for-status-checks@v0.5.0 + with: + token: \${{ secrets.GITHUB_TOKEN }} + delay: 20s + match_pattern: build-release-android + + - name: 🏗 Checkout repository + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 📦 Install AVD dependencies + run: | + sudo apt update + sudo apt-get install -y libpulse0 libgl1 + + - name: ☕ Set up JDK 17 + uses: actions/setup-java@v4 + with: + java-version: '17' + distribution: 'zulu' + + - name: 🐘 Setup Gradle 8.8 + uses: gradle/actions/setup-gradle@v4 + with: + gradle-version: 8.8 + + - name: 🐛 Try to restore build from cache + id: android-release-restore + uses: actions/cache/restore@v4 + with: + path: android-release-build/ + key: android-release-build-\${{ github.event.pull_request.head.sha }} + + - name: 🏎️ Enable KVM + run: | + echo 'KERNEL==\\"kvm\\", GROUP=\\"kvm\\", MODE=\\"0666\\", OPTIONS+=\\"static_node=kvm\\"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: 📱 AVD cache + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-\${{ env.API_LEVEL }} + + - name: 📋 Run Detox tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: \${{ env.API_LEVEL }} + target: google_apis + disable-animations: false + emulator-options: -no-snapshot -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -camera-front none + avd-name: e2e_emulator + arch: x86_64 + script: bun run detox:test:android +" +`; + +exports[`detox recipe rn-setup-ci-create-expo-stack-bun detox 9`] = ` +"name: Test Detox iOS + +on: + pull_request: + +jobs: + test-detox-ios: + runs-on: macos-latest + timeout-minutes: 60 + permissions: + checks: read + contents: read + steps: + - name: ⌛ Wait for build to finish + uses: poseidon/wait-for-status-checks@v0.5.0 + with: + token: \${{ secrets.GITHUB_TOKEN }} + delay: 20s + match_pattern: build-release-ios + + - name: 🏗 Checkout repository + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 📦 Install macOS dependencies + run: | + brew tap wix/brew + brew install applesimutils + env: + HOMEBREW_NO_AUTO_UPDATE: 1 + HOMEBREW_NO_INSTALL_CLEANUP: 1 + + - name: 🐛 Try to restore build from cache + id: ios-release-restore + uses: actions/cache/restore@v4 + with: + path: ios-release-build/ + key: ios-release-build-\${{ github.event.pull_request.head.sha }} + + - name: 📋 Run Detox tests + run: bun run detox:test:ios +" +`; + exports[`detox recipe rn-setup-ci-npm-flat detox 1`] = ` Object { "dependencies": Object { diff --git a/__tests__/recipes/__snapshots__/jest.test.ts.snap b/__tests__/recipes/__snapshots__/jest.test.ts.snap index 784f814..9272549 100644 --- a/__tests__/recipes/__snapshots__/jest.test.ts.snap +++ b/__tests__/recipes/__snapshots__/jest.test.ts.snap @@ -70,6 +70,75 @@ jobs: " `; +exports[`jest recipe rn-setup-ci-create-expo-stack-bun jest 1`] = ` +Object { + "dependencies": Object { + "react": "", + "react-native": "", + }, + "devDependencies": Object { + "@babel/core": "", + "@babel/preset-env": "", + "@babel/runtime": "", + "@react-native/babel-preset": "", + "@react-native/metro-config": "", + "@react-native/typescript-config": "", + "@types/react": "", + "@types/react-test-renderer": "", + "jest": "", + "react-test-renderer": "", + }, + "engines": Object { + "node": ">=18", + }, + "name": "RnSetupCiYarnFlat", + "packageManager": "yarn@3.6.4", + "private": true, + "scripts": Object { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "test": "jest --passWithNoTests", + }, + "version": "0.0.1", +} +`; + +exports[`jest recipe rn-setup-ci-create-expo-stack-bun jest 2`] = ` +"{ + \\"preset\\": \\"react-native\\", + \\"modulePathIgnorePatterns\\": [\\"e2e\\"] +} +" +`; + +exports[`jest recipe rn-setup-ci-create-expo-stack-bun jest 3`] = ` +"name: Run Jest tests + +on: + pull_request: + +jobs: + jest: + name: Jest + runs-on: ubuntu-latest + steps: + - name: 🏗 Setup repo + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 🎭 Run Jest + run: bun run test +" +`; + exports[`jest recipe rn-setup-ci-npm-flat jest 1`] = ` Object { "dependencies": Object { diff --git a/__tests__/recipes/__snapshots__/lint.test.ts.snap b/__tests__/recipes/__snapshots__/lint.test.ts.snap index 33e5f10..5e2ff56 100644 --- a/__tests__/recipes/__snapshots__/lint.test.ts.snap +++ b/__tests__/recipes/__snapshots__/lint.test.ts.snap @@ -65,6 +65,70 @@ jobs: " `; +exports[`lint recipe rn-setup-ci-create-expo-stack-bun lint 1`] = ` +Object { + "dependencies": Object { + "react": "", + "react-native": "", + }, + "devDependencies": Object { + "@babel/core": "", + "@babel/preset-env": "", + "@babel/runtime": "", + "@react-native/babel-preset": "", + "@react-native/eslint-config": "", + "@react-native/metro-config": "", + "@react-native/typescript-config": "", + "@types/react": "", + "@types/react-test-renderer": "", + "eslint": "", + "eslint-plugin-ft-flow": "", + "react-test-renderer": "", + "typescript": "", + }, + "engines": Object { + "node": ">=18", + }, + "name": "RnSetupCiYarnFlat", + "packageManager": "yarn@3.6.4", + "private": true, + "scripts": Object { + "android": "react-native run-android", + "ios": "react-native run-ios", + "lint": "eslint '**/*.{js,jsx,ts,tsx}'", + "start": "react-native start", + }, + "version": "0.0.1", +} +`; + +exports[`lint recipe rn-setup-ci-create-expo-stack-bun lint 2`] = ` +"name: Check ESLint + +on: + pull_request: + +jobs: + eslint: + name: ESLint + runs-on: ubuntu-latest + steps: + - name: 🏗 Setup repo + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 🤓 Run ESLint + run: bun run lint +" +`; + exports[`lint recipe rn-setup-ci-npm-flat lint 1`] = ` Object { "dependencies": Object { diff --git a/__tests__/recipes/__snapshots__/prettier.test.ts.snap b/__tests__/recipes/__snapshots__/prettier.test.ts.snap index a8d0360..96f6cdd 100644 --- a/__tests__/recipes/__snapshots__/prettier.test.ts.snap +++ b/__tests__/recipes/__snapshots__/prettier.test.ts.snap @@ -63,6 +63,68 @@ jobs: " `; +exports[`prettier check recipe rn-setup-ci-create-expo-stack-bun prettier check 1`] = ` +Object { + "dependencies": Object { + "react": "", + "react-native": "", + }, + "devDependencies": Object { + "@babel/core": "", + "@babel/preset-env": "", + "@babel/runtime": "", + "@react-native/babel-preset": "", + "@react-native/metro-config": "", + "@react-native/typescript-config": "", + "@types/react": "", + "@types/react-test-renderer": "", + "prettier": "", + "react-test-renderer": "", + }, + "engines": Object { + "node": ">=18", + }, + "name": "RnSetupCiYarnFlat", + "packageManager": "yarn@3.6.4", + "private": true, + "scripts": Object { + "android": "react-native run-android", + "ios": "react-native run-ios", + "prettier:check": "prettier --check \\"**/*.{ts,tsx,js,jsx,json,css,scss,md}\\"", + "prettier:write": "prettier --write \\"**/*.{ts,tsx,js,jsx,json,css,scss,md}\\"", + "start": "react-native start", + }, + "version": "0.0.1", +} +`; + +exports[`prettier check recipe rn-setup-ci-create-expo-stack-bun prettier check 2`] = ` +"name: Prettier check + +on: + pull_request: + +jobs: + prettier-check: + name: Prettier check + runs-on: ubuntu-latest + steps: + - name: 🏗 Setup repo + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: ✨ Run Prettier check + run: bun run prettier:check +" +`; + exports[`prettier check recipe rn-setup-ci-npm-flat prettier check 1`] = ` Object { "dependencies": Object { diff --git a/__tests__/recipes/__snapshots__/typescript.test.ts.snap b/__tests__/recipes/__snapshots__/typescript.test.ts.snap index 3db2215..d42d5a3 100644 --- a/__tests__/recipes/__snapshots__/typescript.test.ts.snap +++ b/__tests__/recipes/__snapshots__/typescript.test.ts.snap @@ -78,6 +78,83 @@ jobs: " `; +exports[`typescript check recipe rn-setup-ci-create-expo-stack-bun typescript check 1`] = ` +Object { + "dependencies": Object { + "react": "", + "react-native": "", + }, + "devDependencies": Object { + "@babel/core": "", + "@babel/preset-env": "", + "@babel/runtime": "", + "@react-native/babel-preset": "", + "@react-native/metro-config": "", + "@react-native/typescript-config": "", + "@types/react": "", + "@types/react-test-renderer": "", + "react-test-renderer": "", + "typescript": "", + }, + "engines": Object { + "node": ">=18", + }, + "name": "RnSetupCiYarnFlat", + "packageManager": "yarn@3.6.4", + "private": true, + "scripts": Object { + "android": "react-native run-android", + "ios": "react-native run-ios", + "start": "react-native start", + "ts:check": "tsc -p . --noEmit", + }, + "version": "0.0.1", +} +`; + +exports[`typescript check recipe rn-setup-ci-create-expo-stack-bun typescript check 2`] = ` +"{ + \\"extends\\": \\"expo/tsconfig.base\\", + \\"compilerOptions\\": { + \\"strict\\": true, + + \\"baseUrl\\": \\".\\", + \\"paths\\": { + \\"~/*\\": [\\"*\\"] + } + }, + \\"include\\": [\\"**/*.ts\\", \\"**/*.tsx\\", \\".expo/types/**/*.ts\\", \\"expo-env.d.ts\\"] +} +" +`; + +exports[`typescript check recipe rn-setup-ci-create-expo-stack-bun typescript check 3`] = ` +"name: Run Typescript + +on: + pull_request: + +jobs: + typescript-check: + name: Typescript check + runs-on: ubuntu-latest + steps: + - name: 🏗 Setup repo + uses: actions/checkout@v4 + + - name: 🥟 Setup Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version-file: '.bun-version' + + - name: 📦 Install dependencies + run: bun install --frozen-lockfile + + - name: 🔍 Run Typescript check + run: bun run ts:check +" +`; + exports[`typescript check recipe rn-setup-ci-npm-flat typescript check 1`] = ` Object { "dependencies": Object { diff --git a/__tests__/recipes/detox.test.ts b/__tests__/recipes/detox.test.ts index 7d23040..986de37 100644 --- a/__tests__/recipes/detox.test.ts +++ b/__tests__/recipes/detox.test.ts @@ -22,6 +22,7 @@ describe('detox recipe', () => { 'rn-setup-ci-yarn-monorepo', 'rn-setup-ci-npm-monorepo', 'rn-setup-ci-create-expo-stack', + 'rn-setup-ci-create-expo-stack-bun', ] const checkModifiedFiles = ( diff --git a/__tests__/recipes/jest.test.ts b/__tests__/recipes/jest.test.ts index 1280126..787a75a 100644 --- a/__tests__/recipes/jest.test.ts +++ b/__tests__/recipes/jest.test.ts @@ -20,6 +20,7 @@ describe('jest recipe', () => { 'rn-setup-ci-yarn-monorepo', 'rn-setup-ci-npm-monorepo', 'rn-setup-ci-create-expo-stack', + 'rn-setup-ci-create-expo-stack-bun', ] for (const projectName of PROJECTS) { diff --git a/__tests__/recipes/lint.test.ts b/__tests__/recipes/lint.test.ts index fc392ee..5cc4677 100644 --- a/__tests__/recipes/lint.test.ts +++ b/__tests__/recipes/lint.test.ts @@ -21,6 +21,7 @@ describe('lint recipe', () => { 'rn-setup-ci-yarn-monorepo', 'rn-setup-ci-npm-monorepo', 'rn-setup-ci-create-expo-stack', + 'rn-setup-ci-create-expo-stack-bun', ] for (const projectName of PROJECTS) { diff --git a/__tests__/recipes/prettier.test.ts b/__tests__/recipes/prettier.test.ts index 8b6e629..5f37831 100644 --- a/__tests__/recipes/prettier.test.ts +++ b/__tests__/recipes/prettier.test.ts @@ -20,6 +20,7 @@ describe('prettier check recipe', () => { 'rn-setup-ci-yarn-monorepo', 'rn-setup-ci-npm-monorepo', 'rn-setup-ci-create-expo-stack', + 'rn-setup-ci-create-expo-stack-bun', ] for (const projectName of PROJECTS) { diff --git a/__tests__/recipes/typescript.test.ts b/__tests__/recipes/typescript.test.ts index 7036eed..e582dd2 100644 --- a/__tests__/recipes/typescript.test.ts +++ b/__tests__/recipes/typescript.test.ts @@ -20,6 +20,7 @@ describe('typescript check recipe', () => { 'rn-setup-ci-yarn-monorepo', 'rn-setup-ci-npm-monorepo', 'rn-setup-ci-create-expo-stack', + 'rn-setup-ci-create-expo-stack-bun', ] for (const projectName of PROJECTS) { diff --git a/__tests__/runtime-version-file.test.ts b/__tests__/runtime-version-file.test.ts new file mode 100644 index 0000000..0ff9bcb --- /dev/null +++ b/__tests__/runtime-version-file.test.ts @@ -0,0 +1,67 @@ +import { join } from 'path' +import { readFileSync } from 'fs' +import { + cli, + removeTestProject, + setupTestProject, + TEST_PROJECTS, +} from './utils' + +const EXPECTED_NODE_VERSION = 'v20.17.0' +const EXPECTED_BUN_VERSION = '1.1.30' + +describe('should create runtime version files if necessary', () => { + afterEach(removeTestProject) + + test('creates .nvmrc if necessary', async () => { + const { appRoot } = TEST_PROJECTS['rn-setup-ci-create-expo-stack'] + setupTestProject('rn-setup-ci-create-expo-stack') + + const output = await cli(['--skip-git-check', '--preset', '--lint'], { + cwd: appRoot, + }) + + const nvmrc = readFileSync(join(appRoot, '.nvmrc')).toString() + expect(nvmrc).toBe(`${EXPECTED_NODE_VERSION}\n`) + + expect(output).toContain( + [ + 'No node version file found.', + `Created .nvmrc with default node version (${EXPECTED_NODE_VERSION}).`, + ].join(' ') + ) + expect(output).toContain( + [ + "Couldn't retrieve your project's node version.", + `Generated .nvmrc file with default node version (${EXPECTED_NODE_VERSION}).`, + 'Please check if it matches your project and update if necessary.', + ].join(' ') + ) + }) + + test('creates .bun-version if necessary', async () => { + const { appRoot } = TEST_PROJECTS['rn-setup-ci-create-expo-stack-bun'] + setupTestProject('rn-setup-ci-create-expo-stack-bun') + + const output = await cli(['--skip-git-check', '--preset', '--lint'], { + cwd: appRoot, + }) + + const bunVersion = readFileSync(join(appRoot, '.bun-version')).toString() + expect(bunVersion).toBe(`${EXPECTED_BUN_VERSION}\n`) + + expect(output).toContain( + [ + 'No bun version file found.', + `Created .bun-version with default bun version (${EXPECTED_BUN_VERSION}).`, + ].join(' ') + ) + expect(output).toContain( + [ + "Couldn't retrieve your project's bun version.", + `Generated .bun-version file with default bun version (${EXPECTED_BUN_VERSION}).`, + 'Please check if it matches your project and update if necessary.', + ].join(' ') + ) + }) +}) diff --git a/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/.gitignore b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/.gitignore new file mode 100644 index 0000000..6a904e6 --- /dev/null +++ b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/.gitignore @@ -0,0 +1,24 @@ +node_modules/ +.expo/ +dist/ +npm-debug.* +*.jks +*.p8 +*.p12 +*.key +*.mobileprovision +*.orig.* +web-build/ +# expo router +expo-env.d.ts + + + +ios +android + +# macOS +.DS_Store + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* diff --git a/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/README.md b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/README.md new file mode 100644 index 0000000..9a8f61b --- /dev/null +++ b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/README.md @@ -0,0 +1 @@ +generated using `npx create-expo-stack@latest rn-setup-ci-create-expo-stack-bun --expo-router --stylesheet --bun` diff --git a/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app.json b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app.json new file mode 100644 index 0000000..d0bb5d3 --- /dev/null +++ b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app.json @@ -0,0 +1,41 @@ +{ + "expo": { + "name": "rn-setup-ci-create-expo-stack-bun", + "slug": "rn-setup-ci-create-expo-stack-bun", + "version": "1.0.0", + + "scheme": "rn-setup-ci-create-expo-stack-bun", + "web": { + "bundler": "metro", + "output": "static", + "favicon": "./assets/favicon.png" + }, + "plugins": ["expo-router"], + "experiments": { + "typedRoutes": true, + + "tsconfigPaths": true + }, + + "orientation": "portrait", + "icon": "./assets/icon.png", + + "userInterfaceStyle": "light", + + "splash": { + "image": "./assets/splash.png", + "resizeMode": "contain", + "backgroundColor": "#ffffff" + }, + "assetBundlePatterns": ["**/*"], + "ios": { + "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#ffffff" + } + } + } +} diff --git a/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/+html.tsx b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/+html.tsx new file mode 100644 index 0000000..25524d7 --- /dev/null +++ b/__tests__/test-projects/rn-setup-ci-create-expo-stack-bun/app/+html.tsx @@ -0,0 +1,46 @@ +import { ScrollViewStyleReset } from 'expo-router/html'; + +// This file is web-only and used to configure the root HTML for every +// web page during static rendering. +// The contents of this function only run in Node.js environments and +// do not have access to the DOM or browser APIs. +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + + + + + {/* + This viewport disables scaling which makes the mobile website act more like a native app. + However this does reduce built-in accessibility. If you want to enable scaling, use this instead: + + */} + + {/* + Disable body scrolling on web. This makes ScrollView components work closer to how they do on native. + However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line. + */} + + + {/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */} +