From f7819e503ae2bedd0eec9ea85ef3220de7f72a1b Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 14:45:29 -0600 Subject: [PATCH 01/32] fix ci ios env --- scripts/ios/env.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index c5ee09930..54a486501 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -22,7 +22,11 @@ devbox_omit_nix_env() { dump_env "before" - eval "$(devbox shellenv --init-hook --install --no-refresh-alias --omit-nix-env=true)" + devbox_cmd=(devbox shellenv --init-hook --install --no-refresh-alias --omit-nix-env=true) + if [ -n "${DEVBOX_CONFIG_DIR:-}" ]; then + devbox_cmd=(devbox --config "${DEVBOX_CONFIG_DIR%/}/devbox.json" "${devbox_cmd[@]:1}") + fi + eval "$("${devbox_cmd[@]}")" if [ "$(uname -s)" = "Darwin" ]; then PATH="$(printf '%s' "$PATH" | tr ':' '\n' | awk '!/^\/nix\/store\//{print}' | paste -sd ':' -)" From c93ffaaa7dfbd011683e3556912f36744bbfcfcf Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 15:02:00 -0600 Subject: [PATCH 02/32] stuff --- devbox.json | 3 ++- scripts/android/env.sh | 24 +++++++++++-------- scripts/ios/env.sh | 42 +++++++++++++++++++++------------ scripts/ios/test.sh | 27 ++++++++++++++++----- scripts/shared/sdk-summary.sh | 44 +++++++++++++++++++++++++++++++++++ shells/devbox-android.json | 5 ++-- shells/devbox-ios.json | 3 ++- 7 files changed, 113 insertions(+), 35 deletions(-) create mode 100644 scripts/shared/sdk-summary.sh diff --git a/devbox.json b/devbox.json index 6dd289314..abfaf8fb3 100644 --- a/devbox.json +++ b/devbox.json @@ -21,7 +21,8 @@ ". $DEVBOX_PROJECT_ROOT/scripts/shared/common.sh", "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $DEVBOX_PROJECT_ROOT/scripts/ios/env.sh; fi", ". $DEVBOX_PROJECT_ROOT/scripts/android/env.sh", - "echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'" + ". $DEVBOX_PROJECT_ROOT/scripts/shared/sdk-summary.sh", + "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi" ], "scripts": { "clean": [ diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 0ffe24379..b4f3f569d 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -68,15 +68,19 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then new_path="$new_path:$ANDROID_SDK_ROOT/tools/bin:$PATH" PATH="$new_path" export PATH - echo "Using Android SDK: $ANDROID_SDK_ROOT" - case "$ANDROID_SDK_ROOT" in - /nix/store/*) - echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." - ;; - *) - echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." - ;; - esac + if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "Using Android SDK: $ANDROID_SDK_ROOT" + case "$ANDROID_SDK_ROOT" in + /nix/store/*) + echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." + ;; + *) + echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." + ;; + esac + fi else - echo "Android SDK not set; using system PATH" + if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "Android SDK not set; using system PATH" + fi fi diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 54a486501..014eefe41 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -9,32 +9,43 @@ devbox_omit_nix_env() { export DEVBOX_OMIT_NIX_ENV_APPLIED=1 dump_env() { - echo "devbox omit-nix-env $1" - echo " PATH=$PATH" - echo " CC=${CC:-}" - echo " CXX=${CXX:-}" - echo " LD=${LD:-}" - echo " CPP=${CPP:-}" - echo " AR=${AR:-}" - echo " SDKROOT=${SDKROOT:-}" - echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" + if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "devbox omit-nix-env $1" + echo " PATH=$PATH" + echo " CC=${CC:-}" + echo " CXX=${CXX:-}" + echo " LD=${LD:-}" + echo " CPP=${CPP:-}" + echo " AR=${AR:-}" + echo " SDKROOT=${SDKROOT:-}" + echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" + fi } dump_env "before" - devbox_cmd=(devbox shellenv --init-hook --install --no-refresh-alias --omit-nix-env=true) - if [ -n "${DEVBOX_CONFIG_DIR:-}" ]; then - devbox_cmd=(devbox --config "${DEVBOX_CONFIG_DIR%/}/devbox.json" "${devbox_cmd[@]:1}") + devbox_config_path="" + if [ -n "${DEVBOX_CONFIG:-}" ] && [ -f "$DEVBOX_CONFIG" ]; then + devbox_config_path="$DEVBOX_CONFIG" + elif [ -n "${DEVBOX_CONFIG_PATH:-}" ] && [ -f "$DEVBOX_CONFIG_PATH" ]; then + devbox_config_path="$DEVBOX_CONFIG_PATH" + elif [ -n "${DEVBOX_CONFIG_DIR:-}" ] && [ -f "${DEVBOX_CONFIG_DIR%/}/devbox.json" ]; then + devbox_config_path="${DEVBOX_CONFIG_DIR%/}/devbox.json" + fi + + if [ -n "$devbox_config_path" ]; then + eval "$(devbox --config "$devbox_config_path" shellenv --install --no-refresh-alias --omit-nix-env=true)" + else + eval "$(devbox shellenv --install --no-refresh-alias --omit-nix-env=true)" fi - eval "$("${devbox_cmd[@]}")" if [ "$(uname -s)" = "Darwin" ]; then PATH="$(printf '%s' "$PATH" | tr ':' '\n' | awk '!/^\/nix\/store\//{print}' | paste -sd ':' -)" for var in CC CXX LD CPP AR AS NM RANLIB STRIP OBJC OBJCXX SDKROOT DEVELOPER_DIR; do - value="${!var:-}" + value="$(eval "printf '%s' \"\${$var-}\"")" if [ -n "$value" ] && [ "${value#/nix/store/}" != "$value" ]; then - unset "$var" + eval "unset $var" fi done @@ -54,6 +65,7 @@ devbox_omit_nix_env() { fi dump_env "after" + } devbox_omit_nix_env diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh index 7bf5a4189..179de1c16 100755 --- a/scripts/ios/test.sh +++ b/scripts/ios/test.sh @@ -9,12 +9,27 @@ if [ "$(uname -s)" = "Darwin" ]; then . "$SCRIPTS_DIR/ios/env.sh" fi -echo "iOS test env" -echo " PATH=$PATH" -echo " CC=${CC:-}" -echo " CXX=${CXX:-}" -echo " SDKROOT=${SDKROOT:-}" -echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" +if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "iOS test env" + echo " PATH=$PATH" + echo " CC=${CC:-}" + echo " CXX=${CXX:-}" + echo " SDKROOT=${SDKROOT:-}" + echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" +else + android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" + android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-unknown}}" + xcode_dir="${DEVELOPER_DIR:-$(xcode-select -p 2>/dev/null || true)}" + xcode_version="" + if command -v xcodebuild >/dev/null 2>&1; then + xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" + fi + + echo "Resolved SDKs" + echo " Android SDK: ${android_sdk_root:-unknown} (tools: $android_sdk_version)" + echo " Xcode: ${xcode_version:-unknown}" + echo " Xcode Dir: ${xcode_dir:-unknown}" +fi bash "$SCRIPTS_DIR/ios/setup.sh" yarn install diff --git a/scripts/shared/sdk-summary.sh b/scripts/shared/sdk-summary.sh new file mode 100644 index 000000000..8b4c4a56c --- /dev/null +++ b/scripts/shared/sdk-summary.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env sh +set -euo pipefail + +if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + exit 0 +fi + +if [ -n "${DEVBOX_SDK_SUMMARY_PRINTED:-}" ]; then + exit 0 +fi + +DEVBOX_SDK_SUMMARY_PRINTED=1 +export DEVBOX_SDK_SUMMARY_PRINTED + +android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" +android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-unknown}}" +android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-unknown}}" +android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-unknown}}" +android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-unknown}}" + +ios_min_runtime="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-unknown}}" +ios_max_runtime="${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-latest}}" + +xcode_dir="${DEVELOPER_DIR:-}" +if [ -z "$xcode_dir" ] && command -v xcode-select >/dev/null 2>&1; then + xcode_dir="$(xcode-select -p 2>/dev/null || true)" +fi + +xcode_version="unknown" +if command -v xcodebuild >/dev/null 2>&1; then + xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" +fi + +echo "Resolved SDKs" +echo " Android SDK: ${android_sdk_root:-unknown}" +echo " Tools: ${android_sdk_version:-unknown}" +echo " Min API: ${android_min_api:-unknown}" +echo " Max API: ${android_max_api:-unknown}" +echo " System Image: ${android_system_image_tag:-unknown}" +echo " iOS Runtime:" +echo " Min: ${ios_min_runtime:-unknown}" +echo " Max: ${ios_max_runtime:-unknown}" +echo " Xcode: ${xcode_version:-unknown}" +echo " Xcode Dir: ${xcode_dir:-unknown}" diff --git a/shells/devbox-android.json b/shells/devbox-android.json index a1be49c55..6afb07ffb 100644 --- a/shells/devbox-android.json +++ b/shells/devbox-android.json @@ -10,8 +10,9 @@ "shell": { "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../scripts/shared/common.sh", - "echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'", - ". $SCRIPTS_DIR/android/env.sh" + "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", + ". $SCRIPTS_DIR/android/env.sh", + ". $SCRIPTS_DIR/shared/sdk-summary.sh" ], "scripts": { "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], diff --git a/shells/devbox-ios.json b/shells/devbox-ios.json index ba43b7d33..9acfffe0e 100644 --- a/shells/devbox-ios.json +++ b/shells/devbox-ios.json @@ -11,7 +11,8 @@ "shell": { "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../scripts/shared/common.sh", - "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi" + "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi", + ". $SCRIPTS_DIR/shared/sdk-summary.sh" ], "scripts": { "setup-ios": ["bash $SCRIPTS_DIR/ios/setup.sh"], From 9ed33d021c3a3c2368b72f43970d450b909de236 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 15:15:41 -0600 Subject: [PATCH 03/32] refactor shells to android-min and android-max to avoid downloading two toolchains --- .github/workflows/ci-e2e-full.yml | 8 +- .github/workflows/ci-e2e-latest.yml | 8 +- .github/workflows/ci-fast.yml | 4 +- .github/workflows/publish.yml | 16 +- devbox.json | 7 +- nix/flake.nix | 36 +- .../devbox.json} | 4 +- shells/android-max/devbox.lock | 250 ++++++++++++++ shells/android-min/devbox.json | 22 ++ shells/android-min/devbox.lock | 250 ++++++++++++++ shells/{devbox-ios.json => ios/devbox.json} | 2 +- shells/{ => ios}/devbox.lock | 0 .../{devbox-fast.json => minimal/devbox.json} | 2 +- shells/minimal/devbox.lock | 317 ++++++++++++++++++ wiki/devbox.md | 16 +- wiki/scripts.md | 9 +- 16 files changed, 902 insertions(+), 49 deletions(-) rename shells/{devbox-android.json => android-max/devbox.json} (86%) create mode 100644 shells/android-max/devbox.lock create mode 100644 shells/android-min/devbox.json create mode 100644 shells/android-min/devbox.lock rename shells/{devbox-ios.json => ios/devbox.json} (90%) rename shells/{ => ios}/devbox.lock (100%) rename shells/{devbox-fast.json => minimal/devbox.json} (88%) create mode 100644 shells/minimal/devbox.lock diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 31d37f8b4..c99d41ede 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -42,7 +42,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-ios.json + project-path: shells/ios/devbox.json enable-cache: 'false' - name: Resolve iOS targets run: | @@ -55,7 +55,7 @@ jobs: echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" fi - name: iOS E2E Tests - run: devbox run --config=shells/devbox-ios.json test-ios + run: devbox run --config=shells/ios/devbox.json test-ios run-e2e-android: runs-on: ubuntu-24.04-arm @@ -89,7 +89,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-android.json + project-path: shells/android-${{ matrix.target }}/devbox.json enable-cache: 'false' - name: Resolve Android targets run: | @@ -104,4 +104,4 @@ jobs: avd_name="${device}_API${api}_arm64_v8a" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests - run: devbox run --config=shells/devbox-android.json test-android + run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 98fd45c6d..65a68b306 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -35,7 +35,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-ios.json + project-path: shells/ios/devbox.json enable-cache: 'false' - name: Resolve iOS targets run: | @@ -43,7 +43,7 @@ jobs: echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" - name: iOS E2E Tests (latest) - run: devbox run --config=shells/devbox-ios.json test-ios + run: devbox run --config=shells/ios/devbox.json test-ios run-e2e-android: runs-on: ubuntu-24.04-arm @@ -70,7 +70,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-android.json + project-path: shells/android-max/devbox.json enable-cache: 'false' - name: Resolve Android targets run: | @@ -80,4 +80,4 @@ jobs: avd_name="${device}_API${api}_arm64_v8a" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests (latest) - run: devbox run --config=shells/devbox-android.json test-android + run: devbox run --config=shells/android-max/devbox.json test-android diff --git a/.github/workflows/ci-fast.yml b/.github/workflows/ci-fast.yml index 6d110a051..5534f4006 100644 --- a/.github/workflows/ci-fast.yml +++ b/.github/workflows/ci-fast.yml @@ -18,7 +18,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-fast.json + project-path: shells/minimal/devbox.json enable-cache: 'false' - name: build - run: devbox run --config=shells/devbox-fast.json build + run: devbox run --config=shells/minimal/devbox.json build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 18f54d087..d2767fdd8 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -17,10 +17,10 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-fast.json + project-path: shells/minimal/devbox.json enable-cache: 'false' - name: build - run: devbox run --config=shells/devbox-fast.json build + run: devbox run --config=shells/minimal/devbox.json build e2e-ios: name: E2E iOS (min/max) @@ -55,7 +55,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-ios.json + project-path: shells/ios/devbox.json enable-cache: 'false' - name: Resolve iOS targets run: | @@ -68,7 +68,7 @@ jobs: echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" fi - name: iOS E2E Tests - run: devbox run --config=shells/devbox-ios.json test-ios + run: devbox run --config=shells/ios/devbox.json test-ios e2e-android: name: E2E Android (min/max) @@ -103,7 +103,7 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-android.json + project-path: shells/android-${{ matrix.target }}/devbox.json enable-cache: 'false' - name: Resolve Android targets run: | @@ -118,7 +118,7 @@ jobs: avd_name="${device}_API${api}_arm64_v8a" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests - run: devbox run --config=shells/devbox-android.json test-android + run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android publish: name: Publish to npm @@ -138,11 +138,11 @@ jobs: - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: - project-path: shells/devbox-fast.json + project-path: shells/minimal/devbox.json enable-cache: 'false' - name: Config, Build, Release - run: devbox run --config=shells/devbox-fast.json release + run: devbox run --config=shells/minimal/devbox.json release env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }} diff --git a/devbox.json b/devbox.json index abfaf8fb3..bddaa0551 100644 --- a/devbox.json +++ b/devbox.json @@ -56,9 +56,10 @@ ], "update-shells": [ "devbox update", - "devbox update --config=shells/devbox-fast.json", - "devbox update --config=shells/devbox-android.json", - "devbox update --config=shells/devbox-ios.json" + "devbox update --config=shells/minimal/devbox.json", + "devbox update --config=shells/android-min/devbox.json", + "devbox update --config=shells/android-max/devbox.json", + "devbox update --config=shells/ios/devbox.json" ], "reset-android": [ "rm -rf ~/.android/avd", diff --git a/nix/flake.nix b/nix/flake.nix index 06ff87380..7a515a454 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -27,6 +27,12 @@ cmdLineToolsVersion = getVar "PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION" "19.0"; systemImageTypes = [ (getVar "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" "google_apis") ]; }; + androidSdkConfigMin = androidSdkConfig // { + platformVersions = [ (getVar "PLATFORM_ANDROID_MIN_API" "21") ]; + }; + androidSdkConfigMax = androidSdkConfig // { + platformVersions = [ (getVar "PLATFORM_ANDROID_MAX_API" "33") ]; + }; forAllSystems = f: @@ -51,21 +57,25 @@ abiVersions = if builtins.match "aarch64-.*" system != null then [ "arm64-v8a" ] else [ "x86_64" ]; - androidPkgs = pkgs.androidenv.composeAndroidPackages { - # Keep API 21 images for the AVD and add API 33 for React Native builds. - platformVersions = androidSdkConfig.platformVersions; - buildToolsVersions = [ androidSdkConfig.buildToolsVersion ]; - cmdLineToolsVersion = androidSdkConfig.cmdLineToolsVersion; - includeEmulator = true; - includeSystemImages = true; - includeNDK = false; - abiVersions = abiVersions; - systemImageTypes = androidSdkConfig.systemImageTypes; - }; + androidPkgs = + config: + pkgs.androidenv.composeAndroidPackages { + # Keep API 21 images for the AVD and add API 33 for React Native builds. + platformVersions = config.platformVersions; + buildToolsVersions = [ config.buildToolsVersion ]; + cmdLineToolsVersion = config.cmdLineToolsVersion; + includeEmulator = true; + includeSystemImages = true; + includeNDK = false; + abiVersions = abiVersions; + systemImageTypes = config.systemImageTypes; + }; in { - android-sdk = androidPkgs.androidsdk; - default = androidPkgs.androidsdk; + android-sdk = (androidPkgs androidSdkConfig).androidsdk; + android-sdk-min = (androidPkgs androidSdkConfigMin).androidsdk; + android-sdk-max = (androidPkgs androidSdkConfigMax).androidsdk; + default = (androidPkgs androidSdkConfig).androidsdk; } ); diff --git a/shells/devbox-android.json b/shells/android-max/devbox.json similarity index 86% rename from shells/devbox-android.json rename to shells/android-max/devbox.json index 6afb07ffb..fd35c3f7a 100644 --- a/shells/devbox-android.json +++ b/shells/android-max/devbox.json @@ -5,11 +5,11 @@ "jdk17": "latest", "gradle": "latest", "jq": "latest", - "path:../nix#android-sdk": "" + "path:../../nix#android-sdk-max": "" }, "shell": { "init_hook": [ - ". $DEVBOX_PROJECT_ROOT/../scripts/shared/common.sh", + ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", ". $SCRIPTS_DIR/android/env.sh", ". $SCRIPTS_DIR/shared/sdk-summary.sh" diff --git a/shells/android-max/devbox.lock b/shells/android-max/devbox.lock new file mode 100644 index 000000000..92847cffd --- /dev/null +++ b/shells/android-max/devbox.lock @@ -0,0 +1,250 @@ +{ + "lockfile_version": "1", + "packages": { + "github:NixOS/nixpkgs/nixpkgs-unstable": { + "last_modified": "2026-01-27T15:18:14Z", + "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" + }, + "gradle@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "plugin_version": "0.0.1", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#gradle", + "source": "devbox-search", + "version": "8.14.3", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3" + } + } + }, + "jdk17@latest": { + "last_modified": "2025-10-22T20:59:19Z", + "resolved": "github:NixOS/nixpkgs/01b6809f7f9d1183a2b3e081f0a1e6f8f415cb09#jdk17", + "source": "devbox-search", + "version": "17.0.12", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12", + "default": true + } + ], + "store_path": "/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i4zgq9685y6284hbf5a7ac9ysb88dvlz-zulu-ca-jdk-17.0.12", + "default": true + } + ], + "store_path": "/nix/store/i4zgq9685y6284hbf5a7ac9ysb88dvlz-zulu-ca-jdk-17.0.12" + } + } + }, + "jq@latest": { + "last_modified": "2026-01-20T02:11:35Z", + "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "source": "devbox-search", + "version": "1.8.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + } + ], + "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + } + ], + "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + } + ], + "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + } + ], + "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + } + } + }, + "yarn-berry@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "source": "devbox-search", + "version": "4.12.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + } + } + } + } +} diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json new file mode 100644 index 000000000..3bdc87f19 --- /dev/null +++ b/shells/android-min/devbox.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json", + "packages": { + "yarn-berry": "latest", + "jdk17": "latest", + "gradle": "latest", + "jq": "latest", + "path:../../nix#android-sdk-min": "" + }, + "shell": { + "init_hook": [ + ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", + "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", + ". $SCRIPTS_DIR/android/env.sh", + ". $SCRIPTS_DIR/shared/sdk-summary.sh" + ], + "scripts": { + "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], + "test-android": ["bash $SCRIPTS_DIR/android/test.sh"] + } + } +} diff --git a/shells/android-min/devbox.lock b/shells/android-min/devbox.lock new file mode 100644 index 000000000..92847cffd --- /dev/null +++ b/shells/android-min/devbox.lock @@ -0,0 +1,250 @@ +{ + "lockfile_version": "1", + "packages": { + "github:NixOS/nixpkgs/nixpkgs-unstable": { + "last_modified": "2026-01-27T15:18:14Z", + "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" + }, + "gradle@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "plugin_version": "0.0.1", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#gradle", + "source": "devbox-search", + "version": "8.14.3", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3", + "default": true + } + ], + "store_path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3" + } + } + }, + "jdk17@latest": { + "last_modified": "2025-10-22T20:59:19Z", + "resolved": "github:NixOS/nixpkgs/01b6809f7f9d1183a2b3e081f0a1e6f8f415cb09#jdk17", + "source": "devbox-search", + "version": "17.0.12", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12", + "default": true + } + ], + "store_path": "/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i4zgq9685y6284hbf5a7ac9ysb88dvlz-zulu-ca-jdk-17.0.12", + "default": true + } + ], + "store_path": "/nix/store/i4zgq9685y6284hbf5a7ac9ysb88dvlz-zulu-ca-jdk-17.0.12" + } + } + }, + "jq@latest": { + "last_modified": "2026-01-20T02:11:35Z", + "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "source": "devbox-search", + "version": "1.8.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + } + ], + "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + } + ], + "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + } + ], + "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + } + ], + "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + } + } + }, + "yarn-berry@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "source": "devbox-search", + "version": "4.12.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + } + } + } + } +} diff --git a/shells/devbox-ios.json b/shells/ios/devbox.json similarity index 90% rename from shells/devbox-ios.json rename to shells/ios/devbox.json index 9acfffe0e..f92bea932 100644 --- a/shells/devbox-ios.json +++ b/shells/ios/devbox.json @@ -10,7 +10,7 @@ }, "shell": { "init_hook": [ - ". $DEVBOX_PROJECT_ROOT/../scripts/shared/common.sh", + ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi", ". $SCRIPTS_DIR/shared/sdk-summary.sh" ], diff --git a/shells/devbox.lock b/shells/ios/devbox.lock similarity index 100% rename from shells/devbox.lock rename to shells/ios/devbox.lock diff --git a/shells/devbox-fast.json b/shells/minimal/devbox.json similarity index 88% rename from shells/devbox-fast.json rename to shells/minimal/devbox.json index 2413eb4e5..3fa4f62f3 100644 --- a/shells/devbox-fast.json +++ b/shells/minimal/devbox.json @@ -8,7 +8,7 @@ "shfmt": "latest" }, "shell": { - "init_hook": [". $DEVBOX_PROJECT_ROOT/../scripts/shared/common.sh"], + "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh"], "scripts": { "build": ["bash $SCRIPTS_DIR/build.sh"], "release": [ diff --git a/shells/minimal/devbox.lock b/shells/minimal/devbox.lock new file mode 100644 index 000000000..9a97af8ed --- /dev/null +++ b/shells/minimal/devbox.lock @@ -0,0 +1,317 @@ +{ + "lockfile_version": "1", + "packages": { + "github:NixOS/nixpkgs/nixpkgs-unstable": { + "last_modified": "2026-01-27T15:18:14Z", + "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" + }, + "jq@latest": { + "last_modified": "2026-01-20T02:11:35Z", + "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "source": "devbox-search", + "version": "1.8.1", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + } + ], + "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + } + ], + "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + } + ], + "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "bin", + "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "default": true + }, + { + "name": "man", + "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + }, + { + "name": "doc", + "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + }, + { + "name": "out", + "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + } + ], + "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + } + } + }, + "nixfmt@latest": { + "last_modified": "2026-01-09T13:41:53Z", + "resolved": "github:NixOS/nixpkgs/5f02c91314c8ba4afe83b256b023756412218535#nixfmt", + "source": "devbox-search", + "version": "1.2.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0", + "default": true + } + ], + "store_path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0", + "default": true + } + ], + "store_path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0", + "default": true + } + ], + "store_path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0", + "default": true + } + ], + "store_path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0" + } + } + }, + "shfmt@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#shfmt", + "source": "devbox-search", + "version": "3.12.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0", + "default": true + } + ], + "store_path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0", + "default": true + } + ], + "store_path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0", + "default": true + } + ], + "store_path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0", + "default": true + } + ], + "store_path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0" + } + } + }, + "treefmt@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#treefmt", + "source": "devbox-search", + "version": "2.4.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0", + "default": true + } + ], + "store_path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0", + "default": true + } + ], + "store_path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0", + "default": true + } + ], + "store_path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0", + "default": true + } + ], + "store_path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0" + } + } + }, + "yarn-berry@latest": { + "last_modified": "2025-12-31T03:27:36Z", + "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "source": "devbox-search", + "version": "4.12.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "default": true + } + ], + "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + } + } + } + } +} diff --git a/wiki/devbox.md b/wiki/devbox.md index 76e710ed0..f6645e73b 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -73,16 +73,18 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev The root `devbox.json` is a full local dev environment. CI uses slim Devbox configs under `shells/` to avoid pulling unnecessary SDKs: -- `shells/devbox-fast.json`: build + lint only. -- `shells/devbox-android.json`: Android SDK + JDK/Gradle for Android E2E. -- `shells/devbox-ios.json`: CocoaPods + Yarn for iOS E2E (Xcode still required on macOS). +- `shells/minimal/devbox.json`: build + lint only. +- `shells/android-min/devbox.json`: Android SDK (min API) + JDK/Gradle for Android E2E. +- `shells/android-max/devbox.json`: Android SDK (max API) + JDK/Gradle for Android E2E. +- `shells/ios/devbox.json`: CocoaPods + Yarn for iOS E2E (Xcode still required on macOS). Run them locally with: ```sh -devbox run --config=shells/devbox-fast.json build -devbox run --config=shells/devbox-android.json test-android -devbox run --config=shells/devbox-ios.json test-ios +devbox run --config=shells/minimal/devbox.json build +devbox run --config=shells/android-min/devbox.json test-android +devbox run --config=shells/android-max/devbox.json test-android +devbox run --config=shells/ios/devbox.json test-ios ``` -Note: when you use `devbox run --config=shells/...`, Devbox treats `shells/` as the config root. The init hooks set `SCRIPTS_DIR` to point back at the repo-level `scripts/` folder. +Note: when you use `devbox run --config=shells//devbox.json`, Devbox treats `shells//` as the config root. The init hooks set `SCRIPTS_DIR` to point back at the repo-level `scripts/` folder. diff --git a/wiki/scripts.md b/wiki/scripts.md index 483d447c4..65ed39591 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -25,7 +25,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK. - Loads platform defaults via `scripts/platform-versions.sh`. - - Used by devbox init hooks in `devbox.json` and `shells/devbox-android.json`. + - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. - `scripts/android/setup.sh` @@ -83,8 +83,9 @@ Root devbox (`devbox.json`) exposes: Slim CI shells: -- `shells/devbox-fast.json` -> `scripts/build.sh` -- `shells/devbox-android.json` -> `scripts/android/test.sh` -- `shells/devbox-ios.json` -> `scripts/ios/test.sh` +- `shells/minimal/devbox.json` -> `scripts/build.sh` +- `shells/android-min/devbox.json` -> `scripts/android/test.sh` +- `shells/android-max/devbox.json` -> `scripts/android/test.sh` +- `shells/ios/devbox.json` -> `scripts/ios/test.sh` See `wiki/devbox.md` for usage and `wiki/nix.md` for platform version sources. From 1a70f5ba0d1e8605eba09ff2416ce042dbb33e84 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 15:25:23 -0600 Subject: [PATCH 04/32] dry-run release --- .github/workflows/ci-e2e-latest.yml | 1 + .github/workflows/release-dry-run.yml | 22 ++++++++++++++ devbox.json | 1 - scripts/android/env.sh | 17 +++++++++++ scripts/ios/env.sh | 40 ++++++++++++++++++++++++ scripts/ios/test.sh | 13 -------- scripts/shared/sdk-summary.sh | 44 --------------------------- shells/android-max/devbox.json | 3 +- shells/android-min/devbox.json | 3 +- shells/ios/devbox.json | 3 +- shells/minimal/devbox.json | 5 +++ 11 files changed, 88 insertions(+), 64 deletions(-) create mode 100644 .github/workflows/release-dry-run.yml delete mode 100644 scripts/shared/sdk-summary.sh diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 65a68b306..98c8f8d16 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -2,6 +2,7 @@ name: E2E (Latest) on: workflow_dispatch: + pull_request: concurrency: group: e2e-latest-${{ github.ref }} diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml new file mode 100644 index 000000000..b6fdff49a --- /dev/null +++ b/.github/workflows/release-dry-run.yml @@ -0,0 +1,22 @@ +name: Release Dry Run + +on: + workflow_dispatch: + +jobs: + release-dry-run: + name: Release Dry Run + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - name: devbox installer + uses: jetify-com/devbox-install-action@v0.14.0 + with: + project-path: shells/minimal/devbox.json + enable-cache: 'false' + - name: Release Dry Run + run: devbox run --config=shells/minimal/devbox.json release-dry-run + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/devbox.json b/devbox.json index bddaa0551..fd626cacb 100644 --- a/devbox.json +++ b/devbox.json @@ -21,7 +21,6 @@ ". $DEVBOX_PROJECT_ROOT/scripts/shared/common.sh", "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $DEVBOX_PROJECT_ROOT/scripts/ios/env.sh; fi", ". $DEVBOX_PROJECT_ROOT/scripts/android/env.sh", - ". $DEVBOX_PROJECT_ROOT/scripts/shared/sdk-summary.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi" ], "scripts": { diff --git a/scripts/android/env.sh b/scripts/android/env.sh index b4f3f569d..22072b496 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -79,6 +79,23 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then ;; esac fi + if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_ANDROID_SDK_SUMMARY_PRINTED:-}" ]; then + DEVBOX_ANDROID_SDK_SUMMARY_PRINTED=1 + export DEVBOX_ANDROID_SDK_SUMMARY_PRINTED + + android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" + android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-${PLATFORM_ANDROID_BUILD_TOOLS_VERSION:-${PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION:-}}}}" + android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-}}" + android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-}}" + android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-}}" + + echo "Resolved Android SDK" + echo " SDK: ${android_sdk_root:-not set}" + echo " Tools: ${android_sdk_version:-not set}" + echo " Min API: ${android_min_api:-not set}" + echo " Max API: ${android_max_api:-not set}" + echo " System Image: ${android_system_image_tag:-not set}" + fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then echo "Android SDK not set; using system PATH" diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 014eefe41..60f60d160 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -69,3 +69,43 @@ devbox_omit_nix_env() { } devbox_omit_nix_env + +if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SUMMARY_PRINTED:-}" ]; then + DEVBOX_IOS_SDK_SUMMARY_PRINTED=1 + export DEVBOX_IOS_SDK_SUMMARY_PRINTED + + script_dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" + repo_root="$(cd "$script_dir/../.." && pwd)" + + if [ -z "${PLATFORM_IOS_MIN_RUNTIME:-}" ] || [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then + if ! command -v jq >/dev/null 2>&1; then + if [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then + PATH="$DEVBOX_PACKAGES_DIR/bin:$PATH" + fi + fi + # shellcheck disable=SC1090 + . "$repo_root/scripts/platform-versions.sh" + fi + + ios_min_runtime="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-}}" + ios_max_runtime="${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-}}" + if [ -z "$ios_max_runtime" ] && command -v xcrun >/dev/null 2>&1; then + ios_max_runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + fi + + xcode_dir="${DEVELOPER_DIR:-}" + if [ -z "$xcode_dir" ] && command -v xcode-select >/dev/null 2>&1; then + xcode_dir="$(xcode-select -p 2>/dev/null || true)" + fi + + xcode_version="unknown" + if command -v xcodebuild >/dev/null 2>&1; then + xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" + fi + + echo "Resolved iOS SDK" + echo " Runtime Min: ${ios_min_runtime:-not set}" + echo " Runtime Max: ${ios_max_runtime:-not set}" + echo " Xcode: ${xcode_version:-unknown}" + echo " Xcode Dir: ${xcode_dir:-not set}" +fi diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh index 179de1c16..835a5957f 100755 --- a/scripts/ios/test.sh +++ b/scripts/ios/test.sh @@ -16,19 +16,6 @@ if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then echo " CXX=${CXX:-}" echo " SDKROOT=${SDKROOT:-}" echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" -else - android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" - android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-unknown}}" - xcode_dir="${DEVELOPER_DIR:-$(xcode-select -p 2>/dev/null || true)}" - xcode_version="" - if command -v xcodebuild >/dev/null 2>&1; then - xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" - fi - - echo "Resolved SDKs" - echo " Android SDK: ${android_sdk_root:-unknown} (tools: $android_sdk_version)" - echo " Xcode: ${xcode_version:-unknown}" - echo " Xcode Dir: ${xcode_dir:-unknown}" fi bash "$SCRIPTS_DIR/ios/setup.sh" diff --git a/scripts/shared/sdk-summary.sh b/scripts/shared/sdk-summary.sh deleted file mode 100644 index 8b4c4a56c..000000000 --- a/scripts/shared/sdk-summary.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env sh -set -euo pipefail - -if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then - exit 0 -fi - -if [ -n "${DEVBOX_SDK_SUMMARY_PRINTED:-}" ]; then - exit 0 -fi - -DEVBOX_SDK_SUMMARY_PRINTED=1 -export DEVBOX_SDK_SUMMARY_PRINTED - -android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" -android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-unknown}}" -android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-unknown}}" -android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-unknown}}" -android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-unknown}}" - -ios_min_runtime="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-unknown}}" -ios_max_runtime="${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-latest}}" - -xcode_dir="${DEVELOPER_DIR:-}" -if [ -z "$xcode_dir" ] && command -v xcode-select >/dev/null 2>&1; then - xcode_dir="$(xcode-select -p 2>/dev/null || true)" -fi - -xcode_version="unknown" -if command -v xcodebuild >/dev/null 2>&1; then - xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" -fi - -echo "Resolved SDKs" -echo " Android SDK: ${android_sdk_root:-unknown}" -echo " Tools: ${android_sdk_version:-unknown}" -echo " Min API: ${android_min_api:-unknown}" -echo " Max API: ${android_max_api:-unknown}" -echo " System Image: ${android_system_image_tag:-unknown}" -echo " iOS Runtime:" -echo " Min: ${ios_min_runtime:-unknown}" -echo " Max: ${ios_max_runtime:-unknown}" -echo " Xcode: ${xcode_version:-unknown}" -echo " Xcode Dir: ${xcode_dir:-unknown}" diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index fd35c3f7a..e97dd935f 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -11,8 +11,7 @@ "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", - ". $SCRIPTS_DIR/android/env.sh", - ". $SCRIPTS_DIR/shared/sdk-summary.sh" + ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 3bdc87f19..ecb94fdbf 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -11,8 +11,7 @@ "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", - ". $SCRIPTS_DIR/android/env.sh", - ". $SCRIPTS_DIR/shared/sdk-summary.sh" + ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index f92bea932..5862daa39 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -11,8 +11,7 @@ "shell": { "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", - "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi", - ". $SCRIPTS_DIR/shared/sdk-summary.sh" + "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi" ], "scripts": { "setup-ios": ["bash $SCRIPTS_DIR/ios/setup.sh"], diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index 3fa4f62f3..606e39dfe 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -17,6 +17,11 @@ "yarn build", "yarn release" ], + "release-dry-run": [ + "yarn install --immutable", + "yarn build", + "yarn multi-semantic-release --dry-run" + ], "format": ["treefmt"], "lint": ["treefmt --fail-on-change"] } From 20ad272a26c412b89dae6ee7ec26259aff3e77be Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 15:45:00 -0600 Subject: [PATCH 05/32] subshell fixes --- scripts/android/env.sh | 37 +++++++++++++++++++------ scripts/android/setup.sh | 41 +++++++++++++++++++++++++--- scripts/platform-versions.sh | 11 ++++++-- shells/android-max/devbox.json | 1 + shells/android-max/gradle.properties | 1 + shells/android-min/devbox.json | 1 + shells/android-min/gradle.properties | 1 + 7 files changed, 78 insertions(+), 15 deletions(-) create mode 100644 shells/android-max/gradle.properties create mode 100644 shells/android-min/gradle.properties diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 22072b496..5d0621728 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -8,6 +8,20 @@ script_dir="$(cd "$(dirname "$script_path")" && pwd)" . "$script_dir/../shared/common.sh" load_platform_versions "$script_dir" +if [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then + if ! command -v jq >/dev/null 2>&1; then + if [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then + PATH="$DEVBOX_PACKAGES_DIR/bin:$PATH" + fi + fi + project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" + if [ -z "$project_root" ]; then + project_root="$(cd "$script_dir/../.." && pwd)" + fi + # shellcheck disable=SC1090 + . "$project_root/scripts/platform-versions.sh" +fi + if [ -z "${ANDROID_MIN_API:-}" ] && [ -n "${PLATFORM_ANDROID_MIN_API:-}" ]; then ANDROID_MIN_API="$PLATFORM_ANDROID_MIN_API" fi @@ -26,9 +40,14 @@ fi # Only act if neither var is already provided. if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then + project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" + if [ -z "$project_root" ]; then + project_root="$(cd "$script_dir/../.." && pwd)" + fi + flake_output="${ANDROID_SDK_FLAKE_OUTPUT:-android-sdk}" DEVBOX_SDK_OUT=$( nix --extra-experimental-features 'nix-command flakes' \ - eval --raw "path:${DEVBOX_PROJECT_ROOT}/nix#android-sdk.outPath" 2>/dev/null || true + eval --raw "path:${project_root}/nix#${flake_output}.outPath" 2>/dev/null || true ) if [ -n "${DEVBOX_SDK_OUT:-}" ] && [ -d "$DEVBOX_SDK_OUT/libexec/android-sdk" ]; then ANDROID_SDK_ROOT="$DEVBOX_SDK_OUT/libexec/android-sdk" @@ -84,17 +103,17 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then export DEVBOX_ANDROID_SDK_SUMMARY_PRINTED android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" - android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-${PLATFORM_ANDROID_BUILD_TOOLS_VERSION:-${PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION:-}}}}" - android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-}}" - android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-}}" - android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-}}" + android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${PLATFORM_ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-${PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION:-30.0.3}}}}" + android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}" + android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}" + android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}" echo "Resolved Android SDK" echo " SDK: ${android_sdk_root:-not set}" - echo " Tools: ${android_sdk_version:-not set}" - echo " Min API: ${android_min_api:-not set}" - echo " Max API: ${android_max_api:-not set}" - echo " System Image: ${android_system_image_tag:-not set}" + echo " Tools: ${android_sdk_version:-30.0.3}" + echo " Min API: ${android_min_api:-21}" + echo " Max API: ${android_max_api:-33}" + echo " System Image: ${android_system_image_tag:-google_apis}" fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/android/setup.sh b/scripts/android/setup.sh index ffc0b7cef..a5f85edea 100755 --- a/scripts/android/setup.sh +++ b/scripts/android/setup.sh @@ -120,10 +120,43 @@ main() { local secondary_device="${AVD_SECONDARY_DEVICE:-medium_phone}" local secondary_preferred_abi="${AVD_SECONDARY_ABI:-}" - local targets=( - "$primary_api|$primary_tag|$primary_device|$primary_preferred_abi|${AVD_NAME:-}" - "$secondary_api|$secondary_tag|$secondary_device|$secondary_preferred_abi|${AVD_SECONDARY_NAME:-}" - ) + local primary_required=0 + if [ -n "${AVD_API:-}" ] || [ -n "${AVD_TAG:-}" ] || [ -n "${AVD_DEVICE:-}" ] || [ -n "${AVD_ABI:-}" ] || [ -n "${AVD_NAME:-}" ]; then + primary_required=1 + fi + + local secondary_required=0 + if [ -n "${AVD_SECONDARY_API:-}" ] || [ -n "${AVD_SECONDARY_TAG:-}" ] || [ -n "${AVD_SECONDARY_DEVICE:-}" ] || [ -n "${AVD_SECONDARY_ABI:-}" ] || [ -n "${AVD_SECONDARY_NAME:-}" ]; then + secondary_required=1 + fi + + local targets=() + local primary_dir="$ANDROID_SDK_ROOT/system-images/android-${primary_api}/${primary_tag}" + if [ -d "$primary_dir" ]; then + targets+=("$primary_api|$primary_tag|$primary_device|$primary_preferred_abi|${AVD_NAME:-}") + elif [ "$primary_required" = "1" ]; then + echo "Expected API ${primary_api} system image (${primary_tag}) not found under ${primary_dir}." >&2 + echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 + exit 1 + fi + + local secondary_dir="$ANDROID_SDK_ROOT/system-images/android-${secondary_api}/${secondary_tag}" + if [ -n "$secondary_api" ] && [ "$secondary_api" != "$primary_api" ]; then + if [ -d "$secondary_dir" ]; then + targets+=("$secondary_api|$secondary_tag|$secondary_device|$secondary_preferred_abi|${AVD_SECONDARY_NAME:-}") + elif [ "$secondary_required" = "1" ]; then + echo "Expected API ${secondary_api} system image (${secondary_tag}) not found under ${secondary_dir}." >&2 + echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 + exit 1 + elif [ -d "$primary_dir" ]; then + echo "Warning: API ${secondary_api} system image (${secondary_tag}) not found; continuing with API ${primary_api} only." >&2 + fi + fi + + if [ "${#targets[@]}" -eq 0 ]; then + echo "No compatible Android system images found under ${ANDROID_SDK_ROOT}/system-images for configured APIs." >&2 + exit 1 + fi for target in "${targets[@]}"; do IFS="|" read -r api tag device preferred_abi name_override <<<"$target" diff --git a/scripts/platform-versions.sh b/scripts/platform-versions.sh index 0713ce9cb..024dba43e 100644 --- a/scripts/platform-versions.sh +++ b/scripts/platform-versions.sh @@ -5,8 +5,15 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="$(cd "$script_dir/.." && pwd)" versions_json="${PLATFORM_VERSIONS_JSON:-$repo_root/nix/platform-versions.json}" -if [ -f "$versions_json" ] && command -v jq >/dev/null 2>&1; then +jq_cmd="" +if command -v jq >/dev/null 2>&1; then + jq_cmd="jq" +elif [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then + jq_cmd="$DEVBOX_PACKAGES_DIR/bin/jq" +fi + +if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then eval "$( - jq -r 'to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" + "$jq_cmd" -r 'to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" )" fi diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index e97dd935f..b0057ba49 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -11,6 +11,7 @@ "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", + "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { diff --git a/shells/android-max/gradle.properties b/shells/android-max/gradle.properties new file mode 100644 index 000000000..a468eda9e --- /dev/null +++ b/shells/android-max/gradle.properties @@ -0,0 +1 @@ +org.gradle.java.home=/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12 diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index ecb94fdbf..27115996b 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -11,6 +11,7 @@ "init_hook": [ ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", + "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { diff --git a/shells/android-min/gradle.properties b/shells/android-min/gradle.properties new file mode 100644 index 000000000..a468eda9e --- /dev/null +++ b/shells/android-min/gradle.properties @@ -0,0 +1 @@ +org.gradle.java.home=/nix/store/hlm8a8cnp4hm8xkg0a2yy4kv7cq44jii-zulu-ca-jdk-17.0.12 From 158ebae0dc3de793303ba908e2a5d8e57091731e Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 15:53:05 -0600 Subject: [PATCH 06/32] switch ci workflow to amd64 --- .github/workflows/ci-e2e-full.yml | 5 +++-- .github/workflows/ci-e2e-latest.yml | 5 +++-- .github/workflows/publish.yml | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index c99d41ede..6ab7177ed 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -58,9 +58,10 @@ jobs: run: devbox run --config=shells/ios/devbox.json test-ios run-e2e-android: - runs-on: ubuntu-24.04-arm + runs-on: ubuntu-latest env: EMU_HEADLESS: 1 + AVD_ABI: x86_64 strategy: matrix: include: @@ -101,7 +102,7 @@ jobs: api="$PLATFORM_ANDROID_MAX_API" device="$PLATFORM_ANDROID_MAX_DEVICE" fi - avd_name="${device}_API${api}_arm64_v8a" + avd_name="${device}_API${api}_${AVD_ABI}" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 98c8f8d16..ef7dcb7cf 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -47,9 +47,10 @@ jobs: run: devbox run --config=shells/ios/devbox.json test-ios run-e2e-android: - runs-on: ubuntu-24.04-arm + runs-on: ubuntu-latest env: EMU_HEADLESS: 1 + AVD_ABI: x86_64 steps: - uses: actions/checkout@v4 - name: Aggressive disk cleanup (Ubuntu) @@ -78,7 +79,7 @@ jobs: . scripts/platform-versions.sh api="$PLATFORM_ANDROID_MAX_API" device="$PLATFORM_ANDROID_MAX_DEVICE" - avd_name="${device}_API${api}_arm64_v8a" + avd_name="${device}_API${api}_${AVD_ABI}" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests (latest) run: devbox run --config=shells/android-max/devbox.json test-android diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d2767fdd8..3c1b30f95 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -72,9 +72,10 @@ jobs: e2e-android: name: E2E Android (min/max) - runs-on: ubuntu-24.04-arm + runs-on: ubuntu-latest env: EMU_HEADLESS: 1 + AVD_ABI: x86_64 strategy: matrix: include: @@ -115,7 +116,7 @@ jobs: api="$PLATFORM_ANDROID_MAX_API" device="$PLATFORM_ANDROID_MAX_DEVICE" fi - avd_name="${device}_API${api}_arm64_v8a" + avd_name="${device}_API${api}_${AVD_ABI}" echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android From 2cf7f3d9a1f30d3a37883fcc398dd81c2a9d956f Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 16:04:11 -0600 Subject: [PATCH 07/32] ios fix --- examples/E2E/ios/Podfile | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/examples/E2E/ios/Podfile b/examples/E2E/ios/Podfile index e8c21a1c7..f1cee2744 100644 --- a/examples/E2E/ios/Podfile +++ b/examples/E2E/ios/Podfile @@ -35,6 +35,23 @@ target 'AnalyticsReactNativeE2E' do end post_install do |installer| + is_apple_silicon = `uname -m`.strip == 'arm64' + if is_apple_silicon + excluded_archs = 'i386 x86_64' + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = excluded_archs + end + end + installer.aggregate_targets.each do |aggregate_target| + aggregate_target.user_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = excluded_archs + end + end + end + end + installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.4' From 9747237cd1579865aad59c57ea0de515e56ebcda Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 16:08:19 -0600 Subject: [PATCH 08/32] fix script --- scripts/android/env.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 5d0621728..59ba2fd82 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -1,11 +1,14 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh # Sets ANDROID_SDK_ROOT/ANDROID_HOME and PATH to the flake-pinned SDK if not already set. # Load shared platform versions if present. -script_path="${BASH_SOURCE[0]:-$0}" -script_dir="$(cd "$(dirname "$script_path")" && pwd)" +project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" +if [ -z "$project_root" ]; then + project_root="$(cd "$(dirname "$0")/../.." && pwd)" +fi +script_dir="$project_root/scripts/android" # shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" +. "$project_root/scripts/shared/common.sh" load_platform_versions "$script_dir" if [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then From 2cb80230463d634a3a0a942b12d98fc54f32a469 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 16:47:41 -0600 Subject: [PATCH 09/32] fix abi detection --- devbox.json | 3 +- scripts/act-ci.sh | 59 ++++++------ scripts/android/env.sh | 82 +++++++++++++--- scripts/android/manager.sh | 70 +++++++++----- scripts/android/setup.sh | 191 ++++++++++++++++++++++++------------- scripts/android/test.sh | 6 +- scripts/build.sh | 4 +- scripts/ios/env.sh | 21 ++-- scripts/ios/manager.sh | 40 ++++---- scripts/ios/setup.sh | 38 +++++--- scripts/ios/simctl.sh | 74 +++++++------- scripts/ios/test.sh | 6 +- 12 files changed, 375 insertions(+), 219 deletions(-) diff --git a/devbox.json b/devbox.json index fd626cacb..2ccaf0fa7 100644 --- a/devbox.json +++ b/devbox.json @@ -13,7 +13,8 @@ "gradle": "latest", "jq": "latest", "netcat": "latest", - "path:./nix#android-sdk": "" + "path:./nix#android-sdk": "", + "path:./nix#android-sdk-max": "" }, "shell": { "init_hook": [ diff --git a/scripts/act-ci.sh b/scripts/act-ci.sh index 60c7f85a9..58a996cf8 100755 --- a/scripts/act-ci.sh +++ b/scripts/act-ci.sh @@ -1,46 +1,45 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu # Run GitHub Actions workflows locally via act. # Usage: scripts/act-ci.sh [--job JOB] [--platform ubuntu-latest=IMAGE] JOB="" -PLATFORMS=() +PLATFORMS="" host_arch="$(uname -m)" -if [[ $host_arch == "arm64" || $host_arch == "aarch64" ]]; then - PLATFORMS+=("ubuntu-24.04-arm=ghcr.io/catthehacker/ubuntu:act-24.04") +if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then + PLATFORMS="ubuntu-24.04-arm=ghcr.io/catthehacker/ubuntu:act-24.04" else - PLATFORMS+=("ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04") + PLATFORMS="ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04" fi -PLATFORMS+=("ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04") +PLATFORMS="$PLATFORMS ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" -while [[ $# -gt 0 ]]; do +while [ $# -gt 0 ]; do case "$1" in - -j | --job) - JOB="$2" - shift 2 - ;; - -p | --platform) - PLATFORMS+=("$2") - shift 2 - ;; - *) - echo "Unknown option: $1" >&2 - exit 1 - ;; + -j | --job) + JOB="$2" + shift 2 + ;; + -p | --platform) + PLATFORMS="$PLATFORMS $2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; esac -done + done -CMD=(act) -CMD+=(--pull=false) -for platform in "${PLATFORMS[@]}"; do - CMD+=(--platform "$platform") +set -- act --pull=false +for platform in $PLATFORMS; do + set -- "$@" --platform "$platform" done -CMD+=(--input ACT=true) -if [[ -n $JOB ]]; then - CMD+=(--job "$JOB") +set -- "$@" --input ACT=true +if [ -n "$JOB" ]; then + set -- "$@" --job "$JOB" fi -printf 'Running: %s\n' "${CMD[*]}" -exec "${CMD[@]}" +printf 'Running: %s\n' "$*" +exec "$@" diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 59ba2fd82..3fab642ac 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -41,20 +41,58 @@ if [ -z "${ANDROID_SYSTEM_IMAGE_TAG:-}" ] && [ -n "${PLATFORM_ANDROID_SYSTEM_IMA ANDROID_SYSTEM_IMAGE_TAG="$PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" fi -# Only act if neither var is already provided. -if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then - project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" - if [ -z "$project_root" ]; then - project_root="$(cd "$script_dir/../.." && pwd)" +resolve_flake_sdk_root() { + root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" + if [ -z "$root" ]; then + root="$(cd "$script_dir/../.." && pwd)" fi - flake_output="${ANDROID_SDK_FLAKE_OUTPUT:-android-sdk}" - DEVBOX_SDK_OUT=$( + output="$1" + sdk_out=$( nix --extra-experimental-features 'nix-command flakes' \ - eval --raw "path:${project_root}/nix#${flake_output}.outPath" 2>/dev/null || true + eval --raw "path:${root}/nix#${output}.outPath" 2>/dev/null || true ) - if [ -n "${DEVBOX_SDK_OUT:-}" ] && [ -d "$DEVBOX_SDK_OUT/libexec/android-sdk" ]; then - ANDROID_SDK_ROOT="$DEVBOX_SDK_OUT/libexec/android-sdk" - ANDROID_HOME="$ANDROID_SDK_ROOT" + if [ -n "${sdk_out:-}" ] && [ -d "$sdk_out/libexec/android-sdk" ]; then + printf '%s\n' "$sdk_out/libexec/android-sdk" + return 0 + fi + return 1 +} + +# Only act if neither var is already provided. +if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then + preferred_output="${ANDROID_SDK_FLAKE_OUTPUT:-}" + sdk_root_max="" + sdk_root_min="" + + if [ -n "$preferred_output" ]; then + preferred_root="$(resolve_flake_sdk_root "$preferred_output" 2>/dev/null || true)" + if [ -n "$preferred_root" ]; then + ANDROID_SDK_ROOT="$preferred_root" + ANDROID_HOME="$ANDROID_SDK_ROOT" + fi + fi + + sdk_root_max="$(resolve_flake_sdk_root "android-sdk-max" 2>/dev/null || true)" + sdk_root_min="$(resolve_flake_sdk_root "android-sdk" 2>/dev/null || true)" + + if [ -n "$sdk_root_max" ]; then + ANDROID_SDK_ROOT_MAX="$sdk_root_max" + ANDROID_HOME_MAX="$sdk_root_max" + fi + if [ -n "$sdk_root_min" ]; then + ANDROID_SDK_ROOT_MIN="$sdk_root_min" + ANDROID_HOME_MIN="$sdk_root_min" + fi + export ANDROID_SDK_ROOT_MAX ANDROID_HOME_MAX ANDROID_SDK_ROOT_MIN ANDROID_HOME_MIN + + if [ -z "${ANDROID_SDK_ROOT:-}" ]; then + if [ -n "$sdk_root_max" ]; then + ANDROID_SDK_ROOT="$sdk_root_max" + ANDROID_HOME="$ANDROID_SDK_ROOT" + elif [ -n "$sdk_root_min" ]; then + ANDROID_SDK_ROOT="$sdk_root_min" + ANDROID_HOME="$ANDROID_SDK_ROOT" + fi fi fi @@ -110,13 +148,33 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}" android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}" android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}" + android_system_image_abi="" + if [ -n "$android_sdk_root" ] && [ -n "$android_max_api" ] && [ -n "$android_system_image_tag" ]; then + host_arch="$(uname -m)" + if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then + candidates="arm64-v8a x86_64 x86" + else + candidates="x86_64 x86 arm64-v8a" + fi + for abi in $candidates; do + if [ -d "$android_sdk_root/system-images/android-${android_max_api}/${android_system_image_tag}/${abi}" ]; then + android_system_image_abi="$abi" + break + fi + done + fi + if [ -n "$android_system_image_abi" ]; then + android_system_image_summary="${android_system_image_tag};${android_system_image_abi}" + else + android_system_image_summary="$android_system_image_tag" + fi echo "Resolved Android SDK" echo " SDK: ${android_sdk_root:-not set}" echo " Tools: ${android_sdk_version:-30.0.3}" echo " Min API: ${android_min_api:-21}" echo " Max API: ${android_max_api:-33}" - echo " System Image: ${android_system_image_tag:-google_apis}" + echo " System Image: ${android_system_image_summary:-google_apis}" fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/android/manager.sh b/scripts/android/manager.sh index a1275adb6..b1a05cb52 100755 --- a/scripts/android/manager.sh +++ b/scripts/android/manager.sh @@ -1,41 +1,59 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu action="${1:-}" shift || true -source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/env.sh" +script_dir="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1090 +. "$script_dir/env.sh" start_android() { - local flavor="${AVD_FLAVOR:-latest}" headless="${EMU_HEADLESS:-}" port="${EMU_PORT:-5554}" - local avd="${DETOX_AVD:-}" + flavor="${AVD_FLAVOR:-latest}" + headless="${EMU_HEADLESS:-}" + port="${EMU_PORT:-5554}" + avd="${DETOX_AVD:-}" - if [[ -z $avd ]]; then - if [[ $flavor == "latest" ]]; then - local host_arch + if [ -z "$avd" ]; then + if [ "$flavor" = "latest" ]; then host_arch="$(uname -m)" - avd="medium_phone_API33_$([[ $host_arch == "arm64" || $host_arch == "aarch64" ]] && echo arm64_v8a || echo x86_64)" + if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then + abi="arm64_v8a" + else + abi="x86_64" + fi + avd="medium_phone_API33_${abi}" else - avd="pixel_API21_$(uname -m | grep -qi arm && echo arm64_v8a || echo x86_64)" + if uname -m | grep -qi arm; then + abi="arm64_v8a" + else + abi="x86_64" + fi + avd="pixel_API21_${abi}" fi fi devbox run setup-android - local target_serial="emulator-${port}" + target_serial="emulator-${port}" if command -v adb >/dev/null 2>&1; then adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done fi echo "Starting Android emulator: ${avd} (flavor ${flavor}, port ${port}, headless=${headless:-0})" - emulator -avd "${avd}" ${headless:+-no-window} -port "${port}" -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -accel on -writable-system -no-snapshot-save & - adb -s "${target_serial}" wait-for-device - local boot_completed="" + if [ -n "$headless" ]; then + headless_flag="-no-window" + else + headless_flag="" + fi + emulator -avd "$avd" ${headless_flag:+$headless_flag} -port "$port" -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -accel on -writable-system -no-snapshot-save & + adb -s "$target_serial" wait-for-device + boot_completed="" until [ "$boot_completed" = "1" ]; do - boot_completed=$(adb -s "${target_serial}" shell getprop sys.boot_completed 2>/dev/null | tr -d "\r") + boot_completed=$(adb -s "$target_serial" shell getprop sys.boot_completed 2>/dev/null | tr -d "\r") sleep 5 done - adb -s "${target_serial}" shell settings put global window_animation_scale 0 - adb -s "${target_serial}" shell settings put global transition_animation_scale 0 - adb -s "${target_serial}" shell settings put global animator_duration_scale 0 + adb -s "$target_serial" shell settings put global window_animation_scale 0 + adb -s "$target_serial" shell settings put global transition_animation_scale 0 + adb -s "$target_serial" shell settings put global animator_duration_scale 0 } stop_android() { @@ -47,11 +65,11 @@ reset_android() { } case "$action" in -start) start_android ;; -stop) stop_android ;; -reset) reset_android ;; -*) - echo "Usage: manager.sh {start|stop|reset}" >&2 - exit 1 - ;; -esac + start) start_android ;; + stop) stop_android ;; + reset) reset_android ;; + *) + echo "Usage: manager.sh {start|stop|reset}" >&2 + exit 1 + ;; + esac diff --git a/scripts/android/setup.sh b/scripts/android/setup.sh index a5f85edea..7857b9c98 100755 --- a/scripts/android/setup.sh +++ b/scripts/android/setup.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu # Creates AVDs using the Android SDK provided by devbox/flake (system images, emulator, NDK already installed). # Run inside a devbox shell so SDK tools are available. @@ -22,66 +22,74 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" load_platform_versions "$script_dir" detect_sdk_root() { - if [[ -n ${ANDROID_SDK_ROOT:-} ]]; then - echo "$ANDROID_SDK_ROOT" - return + if [ -n "${ANDROID_SDK_ROOT:-}" ]; then + printf '%s\n' "$ANDROID_SDK_ROOT" + return 0 fi - local sm - sm="$(command -v sdkmanager 2>/dev/null || true)" - if [[ -z $sm ]]; then - return + sm=$(command -v sdkmanager 2>/dev/null || true) + if [ -z "$sm" ]; then + return 1 fi - sm="$(readlink -f "$sm")" - local candidates=( - "$(dirname "$sm")/.." - "$(dirname "$sm")/../share/android-sdk" - "$(dirname "$sm")/../libexec/android-sdk" - "$(dirname "$sm")/../.." - ) - for c in "${candidates[@]}"; do - if [[ -d "$c/platform-tools" || -d "$c/platforms" || -d "$c/system-images" ]]; then - echo "$c" - return + sm=$(readlink -f "$sm") + candidates="$(dirname "$sm")/.. $(dirname "$sm")/../share/android-sdk $(dirname "$sm")/../libexec/android-sdk $(dirname "$sm")/../.." + for c in $candidates; do + if [ -d "$c/platform-tools" ] || [ -d "$c/platforms" ] || [ -d "$c/system-images" ]; then + printf '%s\n' "$c" + return 0 fi done + return 1 } avd_exists() { - local name="$1" + name="$1" avdmanager list avd | grep -q "Name: ${name}" } pick_image() { - local api="$1" tag="$2" preferred_abi="$3" - local host_arch + api="$1" + tag="$2" + preferred_abi="$3" host_arch="$(uname -m)" - local candidates=() - if [[ -n ${preferred_abi:-} ]]; then - candidates=("$preferred_abi") + if [ -n "$preferred_abi" ]; then + candidates="$preferred_abi" else case "$host_arch" in - arm64 | aarch64) candidates=("arm64-v8a" "x86_64" "x86") ;; - *) candidates=("x86_64" "x86" "arm64-v8a") ;; + arm64 | aarch64) candidates="arm64-v8a x86_64 x86" ;; + *) candidates="x86_64 x86 arm64-v8a" ;; esac fi - for abi in "${candidates[@]}"; do - local image="system-images;android-${api};${tag};${abi}" - local path="${ANDROID_SDK_ROOT}/system-images/android-${api}/${tag}/${abi}" - if [[ -d $path ]]; then - echo "$image" + ifs_backup="$IFS" + IFS=' ' + for abi in $candidates; do + image="system-images;android-${api};${tag};${abi}" + path="${ANDROID_SDK_ROOT}/system-images/android-${api}/${tag}/${abi}" + if [ -n "${ANDROID_SETUP_DEBUG:-}" ]; then + if [ -d "$path" ]; then + echo "Debug: found ABI path $path" >&2 + else + echo "Debug: missing ABI path $path" >&2 + fi + fi + if [ -d "$path" ]; then + printf '%s\n' "$image" + IFS="$ifs_backup" return 0 fi done + IFS="$ifs_backup" return 1 } create_avd() { - local name="$1" device="$2" image="$3" - local abi="${image##*;}" + name="$1" + device="$2" + image="$3" + abi="${image##*;}" if avd_exists "$name"; then echo "AVD ${name} already exists." @@ -92,58 +100,69 @@ create_avd() { avdmanager create avd --force --name "$name" --package "$image" --device "$device" --abi "$abi" --sdcard 512M } +add_target() { + target_line="$1" + if [ -z "${TARGETS:-}" ]; then + TARGETS="$target_line" + else + TARGETS="${TARGETS} +${target_line}" + fi +} + main() { - local detected_sdk_root - detected_sdk_root="$(detect_sdk_root)" + TARGETS="" + detected_sdk_root="$(detect_sdk_root 2>/dev/null || true)" - if [[ -z ${ANDROID_SDK_ROOT:-} && -n $detected_sdk_root ]]; then - export ANDROID_SDK_ROOT="$detected_sdk_root" + if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "$detected_sdk_root" ]; then + ANDROID_SDK_ROOT="$detected_sdk_root" + export ANDROID_SDK_ROOT fi - if [[ -z ${ANDROID_SDK_ROOT:-} && -z ${ANDROID_HOME:-} ]]; then + if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then echo "ANDROID_SDK_ROOT/ANDROID_HOME must be set. In a devbox shell, the flake-provided SDK should supply sdkmanager in PATH; if not, set ANDROID_SDK_ROOT to the flake's android-sdk path." >&2 exit 1 fi - export ANDROID_HOME="${ANDROID_HOME:-$ANDROID_SDK_ROOT}" + ANDROID_HOME="${ANDROID_HOME:-$ANDROID_SDK_ROOT}" + export ANDROID_HOME require_tool avdmanager require_tool emulator - local primary_api="${AVD_API:-${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}}" - local primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" - local primary_device="${AVD_DEVICE:-pixel}" - local primary_preferred_abi="${AVD_ABI:-}" + primary_api="${AVD_API:-${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}}" + primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" + primary_device="${AVD_DEVICE:-pixel}" + primary_preferred_abi="${AVD_ABI:-}" - local secondary_api="${AVD_SECONDARY_API:-${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}}" - local secondary_tag="${AVD_SECONDARY_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" - local secondary_device="${AVD_SECONDARY_DEVICE:-medium_phone}" - local secondary_preferred_abi="${AVD_SECONDARY_ABI:-}" + secondary_api="${AVD_SECONDARY_API:-${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}}" + secondary_tag="${AVD_SECONDARY_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" + secondary_device="${AVD_SECONDARY_DEVICE:-medium_phone}" + secondary_preferred_abi="${AVD_SECONDARY_ABI:-}" - local primary_required=0 + primary_required=0 if [ -n "${AVD_API:-}" ] || [ -n "${AVD_TAG:-}" ] || [ -n "${AVD_DEVICE:-}" ] || [ -n "${AVD_ABI:-}" ] || [ -n "${AVD_NAME:-}" ]; then primary_required=1 fi - local secondary_required=0 + secondary_required=0 if [ -n "${AVD_SECONDARY_API:-}" ] || [ -n "${AVD_SECONDARY_TAG:-}" ] || [ -n "${AVD_SECONDARY_DEVICE:-}" ] || [ -n "${AVD_SECONDARY_ABI:-}" ] || [ -n "${AVD_SECONDARY_NAME:-}" ]; then secondary_required=1 fi - local targets=() - local primary_dir="$ANDROID_SDK_ROOT/system-images/android-${primary_api}/${primary_tag}" + primary_dir="$ANDROID_SDK_ROOT/system-images/android-${primary_api}/${primary_tag}" if [ -d "$primary_dir" ]; then - targets+=("$primary_api|$primary_tag|$primary_device|$primary_preferred_abi|${AVD_NAME:-}") + add_target "${primary_api}|${primary_tag}|${primary_device}|${primary_preferred_abi}|${AVD_NAME:-}" elif [ "$primary_required" = "1" ]; then echo "Expected API ${primary_api} system image (${primary_tag}) not found under ${primary_dir}." >&2 echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 exit 1 fi - local secondary_dir="$ANDROID_SDK_ROOT/system-images/android-${secondary_api}/${secondary_tag}" + secondary_dir="$ANDROID_SDK_ROOT/system-images/android-${secondary_api}/${secondary_tag}" if [ -n "$secondary_api" ] && [ "$secondary_api" != "$primary_api" ]; then if [ -d "$secondary_dir" ]; then - targets+=("$secondary_api|$secondary_tag|$secondary_device|$secondary_preferred_abi|${AVD_SECONDARY_NAME:-}") + add_target "${secondary_api}|${secondary_tag}|${secondary_device}|${secondary_preferred_abi}|${AVD_SECONDARY_NAME:-}" elif [ "$secondary_required" = "1" ]; then echo "Expected API ${secondary_api} system image (${secondary_tag}) not found under ${secondary_dir}." >&2 echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 @@ -153,29 +172,71 @@ main() { fi fi - if [ "${#targets[@]}" -eq 0 ]; then + if [ -z "$TARGETS" ]; then echo "No compatible Android system images found under ${ANDROID_SDK_ROOT}/system-images for configured APIs." >&2 exit 1 fi - for target in "${targets[@]}"; do - IFS="|" read -r api tag device preferred_abi name_override <<<"$target" - - local api_image - if ! api_image="$(pick_image "$api" "$tag" "$preferred_abi")"; then - echo "Expected API ${api} system image (${tag}; preferred ABI ${preferred_abi:-auto}) not found under ${ANDROID_SDK_ROOT}/system-images/android-${api}." >&2 + ifs_backup="$IFS" + IFS=' +' + for target in $TARGETS; do + IFS='|' read -r api tag device preferred_abi name_override </dev/null || true)" + fi + if [ -z "$api_image" ]; then + base_dir="${ANDROID_SDK_ROOT}/system-images/android-${api}/${tag}" + if [ -d "$base_dir" ]; then + available_abis="$(ls -1 "$base_dir" 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')" + if [ -n "$available_abis" ]; then + host_arch="$(uname -m)" + if [ -n "$preferred_abi" ]; then + candidates="$preferred_abi" + else + case "$host_arch" in + arm64 | aarch64) candidates="arm64-v8a x86_64 x86" ;; + *) candidates="x86_64 x86 arm64-v8a" ;; + esac + fi + echo "Debug: host_arch=${host_arch} candidates=${candidates} base_dir=${base_dir}" >&2 + echo "API ${api} system image tag '${tag}' found, but no compatible ABI (preferred ${preferred_abi:-auto}). Available: ${available_abis}." >&2 + else + echo "API ${api} system image tag '${tag}' exists but has no ABI directories under ${base_dir}." >&2 + fi + else + echo "Expected API ${api} system image (${tag}; preferred ABI ${preferred_abi:-auto}) not found under ${ANDROID_SDK_ROOT}/system-images/android-${api}." >&2 + fi echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 continue fi - local abi="${api_image##*;}" - local avd_name="${name_override:-$(printf '%s_API%s_%s' "$device" "$api" "${abi//-/_}")}" + abi="${api_image##*;}" + abi_safe="$(printf '%s' "$abi" | tr '-' '_')" + if [ -n "$name_override" ]; then + avd_name="$name_override" + else + avd_name="$(printf '%s_API%s_%s' "$device" "$api" "$abi_safe")" + fi create_avd "$avd_name" "$device" "$api_image" if avd_exists "$avd_name"; then echo "AVD ready: ${avd_name} (${api_image})" fi done + IFS="$ifs_backup" echo "AVDs ready. Boot with: emulator -avd --netdelay none --netspeed full" } diff --git a/scripts/android/test.sh b/scripts/android/test.sh index 342a187a0..a27edf02d 100755 --- a/scripts/android/test.sh +++ b/scripts/android/test.sh @@ -1,11 +1,11 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" -bash "$SCRIPTS_DIR/android/setup.sh" +sh "$SCRIPTS_DIR/android/setup.sh" yarn install yarn e2e install yarn build diff --git a/scripts/build.sh b/scripts/build.sh index d22efb734..9c4e841f6 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 60f60d160..9812906ae 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu devbox_omit_nix_env() { if [ "${DEVBOX_OMIT_NIX_ENV_APPLIED:-}" = "1" ]; then @@ -50,14 +50,16 @@ devbox_omit_nix_env() { done if [ -x /usr/bin/clang ]; then - export CC=/usr/bin/clang - export CXX=/usr/bin/clang++ + CC=/usr/bin/clang + CXX=/usr/bin/clang++ + export CC CXX fi if command -v xcode-select >/dev/null 2>&1; then dev_dir="$(xcode-select -p 2>/dev/null || true)" if [ -n "$dev_dir" ]; then - export DEVELOPER_DIR="$dev_dir" + DEVELOPER_DIR="$dev_dir" + export DEVELOPER_DIR fi fi @@ -74,8 +76,13 @@ if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SU DEVBOX_IOS_SDK_SUMMARY_PRINTED=1 export DEVBOX_IOS_SDK_SUMMARY_PRINTED - script_dir="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)" - repo_root="$(cd "$script_dir/../.." && pwd)" + repo_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" + if [ -z "$repo_root" ] && [ -n "${SCRIPTS_DIR:-}" ]; then + repo_root="$(cd "$SCRIPTS_DIR/.." && pwd)" + fi + if [ -z "$repo_root" ]; then + repo_root="$(cd "$(dirname "$0")/../.." && pwd)" + fi if [ -z "${PLATFORM_IOS_MIN_RUNTIME:-}" ] || [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then if ! command -v jq >/dev/null 2>&1; then diff --git a/scripts/ios/manager.sh b/scripts/ios/manager.sh index 52359735f..d804339f1 100755 --- a/scripts/ios/manager.sh +++ b/scripts/ios/manager.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 @@ -10,19 +10,21 @@ action="${1:-}" shift || true start_ios() { - local flavor="${IOS_FLAVOR:-latest}" - if [[ $flavor == "minsdk" ]]; then - export IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" - export IOS_RUNTIME="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}" - export DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" + flavor="${IOS_FLAVOR:-latest}" + if [ "$flavor" = "minsdk" ]; then + IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" + IOS_RUNTIME="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" + export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE else - export IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - export IOS_RUNTIME="${IOS_RUNTIME:-${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-}}}" - export DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" + IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + IOS_RUNTIME="${IOS_RUNTIME:-${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-}}}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" + export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE fi devbox run setup-ios - local sim_device="${DETOX_IOS_DEVICE}" + sim_device="${DETOX_IOS_DEVICE}" if ! xcrun simctl list devices | grep -q "${sim_device}"; then echo "Simulator ${sim_device} not found; ensure setup-ios created it." >&2 exit 1 @@ -41,11 +43,11 @@ reset_ios() { } case "$action" in -start) start_ios ;; -stop) stop_ios ;; -reset) reset_ios ;; -*) - echo "Usage: manager.sh {start|stop|reset}" >&2 - exit 1 - ;; -esac + start) start_ios ;; + stop) stop_ios ;; + reset) reset_ios ;; + *) + echo "Usage: manager.sh {start|stop|reset}" >&2 + exit 1 + ;; + esac diff --git a/scripts/ios/setup.sh b/scripts/ios/setup.sh index de7827cad..3a17b941f 100755 --- a/scripts/ios/setup.sh +++ b/scripts/ios/setup.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 @@ -16,18 +16,19 @@ load_platform_versions "$script_dir" # IOS_DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" to override the Xcode path; defaults to xcode-select -p or the standard Xcode.app if found ensure_developer_dir() { - local desired="${IOS_DEVELOPER_DIR:-}" - if [[ -z $desired ]]; then + desired="${IOS_DEVELOPER_DIR:-}" + if [ -z "$desired" ]; then if xcode-select -p >/dev/null 2>&1; then desired="$(xcode-select -p)" - elif [[ -d /Applications/Xcode.app/Contents/Developer ]]; then + elif [ -d /Applications/Xcode.app/Contents/Developer ]; then desired="/Applications/Xcode.app/Contents/Developer" fi fi - if [[ -n $desired && -d $desired ]]; then - export DEVELOPER_DIR="$desired" - export PATH="$DEVELOPER_DIR/usr/bin:$PATH" + if [ -n "$desired" ] && [ -d "$desired" ]; then + DEVELOPER_DIR="$desired" + PATH="$DEVELOPER_DIR/usr/bin:$PATH" + export DEVELOPER_DIR PATH return 0 fi @@ -44,25 +45,32 @@ ensure_simctl() { if xcrun -f simctl >/dev/null 2>&1; then return 0 fi - cat >&2 <<'EOF' + cat >&2 <<'EOM' Missing simctl. - The standalone Command Line Tools do NOT include simctl; you need full Xcode. - Install/locate Xcode.app, then select it: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer - You can also set IOS_DEVELOPER_DIR to your Xcode path for this script. -EOF +EOM exit 1 } ensure_simctl main() { - ensure_core_sim_service || return 1 - IFS=',' read -r -a devices <<<"${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - local runtime="${IOS_RUNTIME:-${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}}" - for device in "${devices[@]}"; do - ensure_device "$(echo "$device" | xargs)" "$runtime" + if ! ensure_core_sim_service; then + return 1 + fi + devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + runtime="${IOS_RUNTIME:-${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}}" + + ifs_backup="$IFS" + IFS=',' + for device in $devices_list; do + device_trimmed="$(printf '%s' "$device" | xargs)" + ensure_device "$device_trimmed" "$runtime" done + IFS="$ifs_backup" echo "Done. Launch via Xcode > Devices or 'xcrun simctl boot \"\"' then 'open -a Simulator'." } diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index ddfe7bf27..5c5b50b15 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -1,10 +1,10 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu ensure_core_sim_service() { - local output status + status=0 output="$(xcrun simctl list devices -j 2>&1)" || status=$? - if [[ -n ${status:-} ]]; then + if [ "$status" -ne 0 ]; then echo "simctl failed while listing devices (status ${status}). CoreSimulatorService may be unhealthy." >&2 echo "Try restarting it:" >&2 echo " killall -9 com.apple.CoreSimulatorService 2>/dev/null || true" >&2 @@ -27,29 +27,31 @@ ensure_core_sim_service() { } pick_runtime() { - local preferred="$1" - local json choice + preferred="$1" json="$(xcrun simctl list runtimes -j)" choice="$(echo "$json" | jq -r --arg v "$preferred" '.runtimes[] | select(.isAvailable and (.name|startswith("iOS \($v)"))) | "\(.identifier)|\(.name)"' | head -n1)" - if [[ -z $choice || $choice == "null" ]]; then + if [ -z "$choice" ] || [ "$choice" = "null" ]; then choice="$(echo "$json" | jq -r '.runtimes[] | select(.isAvailable and (.name|startswith("iOS "))) | "\(.version)|\(.identifier)|\(.name)"' | sort -Vr | head -n1 | cut -d"|" -f2-)" fi - [[ -n $choice && $choice != "null" ]] || return 1 - echo "$choice" + if [ -n "$choice" ] && [ "$choice" != "null" ]; then + printf '%s\n' "$choice" + return 0 + fi + return 1 } resolve_runtime() { - local preferred="$1" - if choice=$(pick_runtime "$preferred"); then - echo "$choice" + preferred="$1" + if choice="$(pick_runtime "$preferred")"; then + printf '%s\n' "$choice" return 0 fi - if [[ ${IOS_DOWNLOAD_RUNTIME:-1} != "0" ]] && command -v xcodebuild >/dev/null 2>&1; then + if [ "${IOS_DOWNLOAD_RUNTIME:-1}" != "0" ] && command -v xcodebuild >/dev/null 2>&1; then echo "Preferred runtime iOS ${preferred} not found. Attempting to download via xcodebuild -downloadPlatform iOS..." >&2 if xcodebuild -downloadPlatform iOS; then - if choice=$(pick_runtime "$preferred"); then - echo "$choice" + if choice="$(pick_runtime "$preferred")"; then + printf '%s\n' "$choice" return 0 fi else @@ -61,30 +63,31 @@ resolve_runtime() { } existing_device_udid_any_runtime() { - local name="$1" + name="$1" xcrun simctl list devices -j | jq -r --arg name "$name" '.devices[]?[]? | select(.name == $name) | .udid' | head -n1 } device_data_dir_exists() { - local udid="${1:-}" - [[ -n $udid ]] || return 1 - local dir="$HOME/Library/Developer/CoreSimulator/Devices/$udid" - [[ -d $dir ]] + udid="${1:-}" + if [ -z "$udid" ]; then + return 1 + fi + dir="$HOME/Library/Developer/CoreSimulator/Devices/$udid" + [ -d "$dir" ] } devicetype_id_for_name() { - local name="$1" + name="$1" xcrun simctl list devicetypes -j | jq -r --arg name "$name" '.devicetypes[] | select((.name|ascii_downcase) == ($name|ascii_downcase)) | .identifier' | head -n1 } ensure_device() { - local base_name="$1" preferred_runtime="$2" + base_name="$1" + preferred_runtime="$2" # If a device with this name already exists anywhere, reuse it. - if - existing_udid=$(existing_device_udid_any_runtime "$base_name") - [[ -n ${existing_udid} ]] - then + existing_udid="$(existing_device_udid_any_runtime "$base_name")" + if [ -n "$existing_udid" ]; then if device_data_dir_exists "$existing_udid"; then echo "Found existing ${base_name}: ${existing_udid}" return 0 @@ -93,26 +96,25 @@ ensure_device() { xcrun simctl delete "$existing_udid" || true fi - local choice runtime_id runtime_name - if ! choice=$(resolve_runtime "$preferred_runtime"); then + choice="$(resolve_runtime "$preferred_runtime" || true)" + if [ -z "$choice" ]; then echo "No available iOS simulator runtime found. Install one in Xcode (Settings > Platforms) and retry." >&2 return 1 fi - runtime_id="$(echo "$choice" | cut -d'|' -f1)" - runtime_name="$(echo "$choice" | cut -d'|' -f2)" + runtime_id="$(printf '%s' "$choice" | cut -d'|' -f1)" + runtime_name="$(printf '%s' "$choice" | cut -d'|' -f2)" - local display_name="${base_name} (${runtime_name})" + display_name="${base_name} (${runtime_name})" - if ! device_type=$(devicetype_id_for_name "$base_name"); then + device_type="$(devicetype_id_for_name "$base_name" || true)" + if [ -z "$device_type" ]; then echo "Device type '${base_name}' is unavailable in this Xcode install. Skipping ${display_name}." >&2 return 0 fi # Also check for an existing device with the runtime-qualified display name. - if - existing_udid=$(existing_device_udid_any_runtime "$display_name") - [[ -n ${existing_udid} ]] - then + existing_udid="$(existing_device_udid_any_runtime "$display_name")" + if [ -n "$existing_udid" ]; then if device_data_dir_exists "$existing_udid"; then echo "Found existing ${display_name}: ${existing_udid}" return 0 diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh index 835a5957f..aa88b44c8 100755 --- a/scripts/ios/test.sh +++ b/scripts/ios/test.sh @@ -1,5 +1,5 @@ -#!/usr/bin/env bash -set -euo pipefail +#!/usr/bin/env sh +set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 @@ -18,7 +18,7 @@ if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" fi -bash "$SCRIPTS_DIR/ios/setup.sh" +sh "$SCRIPTS_DIR/ios/setup.sh" yarn install yarn e2e install yarn e2e pods From 4b9b4b2a2debe2ae737f75de38115638869e109a Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 16:59:29 -0600 Subject: [PATCH 10/32] cleanups --- devbox.json | 67 ++++++++-------------------------- scripts/android/env.sh | 38 ++++++++++++++++--- scripts/android/manager.sh | 23 ++++++++++-- scripts/android/setup.sh | 2 +- scripts/ios/env.sh | 10 +++-- scripts/ios/manager.sh | 21 +++++++++-- shells/android-max/devbox.json | 4 +- shells/android-min/devbox.json | 4 +- shells/ios/devbox.json | 4 +- shells/minimal/devbox.json | 2 +- 10 files changed, 100 insertions(+), 75 deletions(-) diff --git a/devbox.json b/devbox.json index 2ccaf0fa7..906f61227 100644 --- a/devbox.json +++ b/devbox.json @@ -32,23 +32,23 @@ "yarn cache clean", "find $DEVBOX_PROJECT_DIR -type d -name node_modules -exec rmdir {} \\;" ], - "build": ["bash $SCRIPTS_DIR/build.sh"], + "build": ["sh $SCRIPTS_DIR/build.sh"], "format": ["treefmt"], "lint": ["treefmt --fail-on-change"], - "test-android": ["bash $SCRIPTS_DIR/android/test.sh"], - "test-ios": ["bash $SCRIPTS_DIR/ios/test.sh"], + "test-android": ["sh $SCRIPTS_DIR/android/test.sh"], + "test-ios": ["sh $SCRIPTS_DIR/ios/test.sh"], "act-ci": [ - "bash $SCRIPTS_DIR/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" + "sh $SCRIPTS_DIR/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" ], - "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], - "setup-ios": ["bash $SCRIPTS_DIR/ios/setup.sh"], - "start-emulator": ["bash $SCRIPTS_DIR/android/manager.sh start"], - "start-ios": ["bash $SCRIPTS_DIR/ios/manager.sh start"], - "start-android-minsdk": ["bash $SCRIPTS_DIR/android/manager.sh start"], + "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], + "setup-ios": ["sh $SCRIPTS_DIR/ios/setup.sh"], + "start-emulator": ["sh $SCRIPTS_DIR/android/manager.sh start"], + "start-ios": ["sh $SCRIPTS_DIR/ios/manager.sh start"], + "start-android-minsdk": ["sh $SCRIPTS_DIR/android/manager.sh start"], "start-android-latest": [ - "AVD_FLAVOR=latest bash $SCRIPTS_DIR/android/manager.sh start" + "AVD_FLAVOR=latest sh $SCRIPTS_DIR/android/manager.sh start" ], - "start-android": ["bash $SCRIPTS_DIR/android/manager.sh start"], + "start-android": ["sh $SCRIPTS_DIR/android/manager.sh start"], "update-apps": [ "yarn install --no-immutable", "yarn e2e install --no-immutable", @@ -61,47 +61,10 @@ "devbox update --config=shells/android-max/devbox.json", "devbox update --config=shells/ios/devbox.json" ], - "reset-android": [ - "rm -rf ~/.android/avd", - "rm -f ~/.android/adbkey*", - "echo \"AVDs and adb keys removed. Recreate via devbox run start-android* as needed.\"" - ], - "reset-ios": [ - "xcrun simctl shutdown all || true", - "xcrun simctl erase all || true", - "xcrun simctl delete all || true", - "xcrun simctl delete unavailable || true", - "killall -9 com.apple.CoreSimulatorService 2>/dev/null || true", - "echo \"Simulators reset via simctl. Recreate via devbox run start-ios.\"" - ], - "stop-android": [ - "if command -v adb >/dev/null 2>&1; then", - " devices=$(adb devices -l 2>/dev/null | tail -n +2 | awk '{print $1}' | tr '\\n' ' ');", - " if [[ -n \"$devices\" ]]; then", - " echo \"Stopping Android emulators: $devices\";", - " for d in $devices; do adb -s \"$d\" emu kill >/dev/null 2>&1 || true; done;", - " else", - " echo \"No Android emulators detected via adb.\";", - " fi;", - "else", - " echo \"adb not found; skipping Android emulator shutdown.\";", - "fi", - "pkill -f \"emulator@\" >/dev/null 2>&1 || true", - "echo \"Android emulators stopped (if any were running).\"" - ], - "stop-ios": [ - "if command -v xcrun >/dev/null 2>&1 && xcrun -f simctl >/dev/null 2>&1; then", - " if xcrun simctl list devices booted | grep -q \"Booted\"; then", - " echo \"Shutting down booted iOS simulators...\";", - " xcrun simctl shutdown all >/dev/null 2>&1 || true;", - " else", - " echo \"No booted iOS simulators detected.\";", - " fi;", - "else", - " echo \"simctl not available; skipping iOS shutdown.\";", - "fi", - "echo \"iOS simulators shutdown (if any were running).\"" - ], + "reset-android": ["sh $SCRIPTS_DIR/android/manager.sh reset"], + "reset-ios": ["sh $SCRIPTS_DIR/ios/manager.sh reset"], + "stop-android": ["sh $SCRIPTS_DIR/android/manager.sh stop"], + "stop-ios": ["sh $SCRIPTS_DIR/ios/manager.sh stop"], "stop": ["devbox run stop-android", "devbox run stop-ios"], "test": ["devbox run test-android", "devbox run test-ios"] } diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 3fab642ac..7ddf623d3 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -149,6 +149,21 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}" android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}" android_system_image_abi="" + android_target_api="${AVD_API:-${ANDROID_TARGET_API:-}}" + android_target_source="" + if [ -z "$android_target_api" ]; then + if [ -n "$android_max_api" ]; then + android_target_api="$android_max_api" + android_target_source="max" + elif [ -n "$android_min_api" ]; then + android_target_api="$android_min_api" + android_target_source="min" + fi + elif [ -n "${AVD_API:-}" ]; then + android_target_source="avd" + elif [ -n "${ANDROID_TARGET_API:-}" ]; then + android_target_source="target" + fi if [ -n "$android_sdk_root" ] && [ -n "$android_max_api" ] && [ -n "$android_system_image_tag" ]; then host_arch="$(uname -m)" if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then @@ -163,6 +178,18 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then fi done fi + if [ -z "$android_target_api" ] && [ -n "$android_sdk_root" ] && [ -n "$android_min_api" ] && [ -n "$android_system_image_tag" ]; then + for abi in $candidates; do + if [ -d "$android_sdk_root/system-images/android-${android_min_api}/${android_system_image_tag}/${abi}" ]; then + android_system_image_abi="${android_system_image_abi:-$abi}" + if [ -z "$android_target_api" ]; then + android_target_api="$android_min_api" + android_target_source="min" + fi + break + fi + done + fi if [ -n "$android_system_image_abi" ]; then android_system_image_summary="${android_system_image_tag};${android_system_image_abi}" else @@ -170,11 +197,12 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then fi echo "Resolved Android SDK" - echo " SDK: ${android_sdk_root:-not set}" - echo " Tools: ${android_sdk_version:-30.0.3}" - echo " Min API: ${android_min_api:-21}" - echo " Max API: ${android_max_api:-33}" - echo " System Image: ${android_system_image_summary:-google_apis}" + echo " ANDROID_SDK_ROOT: ${android_sdk_root:-not set}" + echo " ANDROID_BUILD_TOOLS_VERSION: ${android_sdk_version:-30.0.3}" + echo " ANDROID_MIN_API: ${android_min_api:-21}" + echo " ANDROID_MAX_API: ${android_max_api:-33}" + echo " ANDROID_TARGET_API: ${android_target_api:-not set}${android_target_source:+ (${android_target_source})}" + echo " ANDROID_SYSTEM_IMAGE_TAG: ${android_system_image_summary:-google_apis}" fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/android/manager.sh b/scripts/android/manager.sh index b1a05cb52..b06e25c9a 100755 --- a/scripts/android/manager.sh +++ b/scripts/android/manager.sh @@ -33,7 +33,7 @@ start_android() { fi fi - devbox run setup-android + sh "$SCRIPTS_DIR/android/setup.sh" target_serial="emulator-${port}" if command -v adb >/dev/null 2>&1; then adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done @@ -57,11 +57,28 @@ start_android() { } stop_android() { - devbox run stop-android + if command -v adb >/dev/null 2>&1; then + adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done + devices="$(adb devices -l 2>/dev/null | awk 'NR>1{print $1}' | tr '\n' ' ')" + if [ -n "$devices" ]; then + echo "Stopping Android emulators: $devices" + for d in $devices; do + adb -s "$d" emu kill >/dev/null 2>&1 || true + done + else + echo "No Android emulators detected via adb." + fi + else + echo "adb not found; skipping Android emulator shutdown." + fi + pkill -f "emulator@" >/dev/null 2>&1 || true + echo "Android emulators stopped (if any were running)." } reset_android() { - devbox run reset-android + rm -rf "$HOME/.android/avd" + rm -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub" + echo "AVDs and adb keys removed. Recreate via start-android* as needed." } case "$action" in diff --git a/scripts/android/setup.sh b/scripts/android/setup.sh index 7857b9c98..377f54a13 100755 --- a/scripts/android/setup.sh +++ b/scripts/android/setup.sh @@ -130,7 +130,7 @@ main() { require_tool avdmanager require_tool emulator - primary_api="${AVD_API:-${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}}" + primary_api="${AVD_API:-${ANDROID_TARGET_API:-${ANDROID_MAX_API:-${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}}}}" primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" primary_device="${AVD_DEVICE:-pixel}" primary_preferred_abi="${AVD_ABI:-}" diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 9812906ae..4c120de87 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -110,9 +110,11 @@ if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SU xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" fi + ios_target_runtime="${IOS_RUNTIME:-${ios_max_runtime:-${ios_min_runtime:-}}}" echo "Resolved iOS SDK" - echo " Runtime Min: ${ios_min_runtime:-not set}" - echo " Runtime Max: ${ios_max_runtime:-not set}" - echo " Xcode: ${xcode_version:-unknown}" - echo " Xcode Dir: ${xcode_dir:-not set}" + echo " IOS_MIN_RUNTIME: ${ios_min_runtime:-not set}" + echo " IOS_MAX_RUNTIME: ${ios_max_runtime:-not set}" + echo " IOS_RUNTIME: ${ios_target_runtime:-not set}" + echo " xcodebuild: ${xcode_version:-unknown}" + echo " DEVELOPER_DIR: ${xcode_dir:-not set}" fi diff --git a/scripts/ios/manager.sh b/scripts/ios/manager.sh index d804339f1..f0ca5ba40 100755 --- a/scripts/ios/manager.sh +++ b/scripts/ios/manager.sh @@ -23,7 +23,7 @@ start_ios() { export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE fi - devbox run setup-ios + sh "$SCRIPTS_DIR/ios/setup.sh" sim_device="${DETOX_IOS_DEVICE}" if ! xcrun simctl list devices | grep -q "${sim_device}"; then echo "Simulator ${sim_device} not found; ensure setup-ios created it." >&2 @@ -35,11 +35,26 @@ start_ios() { } stop_ios() { - devbox run stop-ios + if command -v xcrun >/dev/null 2>&1 && xcrun -f simctl >/dev/null 2>&1; then + if xcrun simctl list devices booted | grep -q "Booted"; then + echo "Shutting down booted iOS simulators..." + xcrun simctl shutdown all >/dev/null 2>&1 || true + else + echo "No booted iOS simulators detected." + fi + else + echo "simctl not available; skipping iOS shutdown." + fi + echo "iOS simulators shutdown (if any were running)." } reset_ios() { - devbox run reset-ios + xcrun simctl shutdown all || true + xcrun simctl erase all || true + xcrun simctl delete all || true + xcrun simctl delete unavailable || true + killall -9 com.apple.CoreSimulatorService 2>/dev/null || true + echo "Simulators reset via simctl. Recreate via start-ios." } case "$action" in diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index b0057ba49..c87b0ec12 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -15,8 +15,8 @@ ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { - "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], - "test-android": ["bash $SCRIPTS_DIR/android/test.sh"] + "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], + "test-android": ["sh $SCRIPTS_DIR/android/test.sh"] } } } diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 27115996b..e7125620b 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -15,8 +15,8 @@ ". $SCRIPTS_DIR/android/env.sh" ], "scripts": { - "setup-android": ["bash $SCRIPTS_DIR/android/setup.sh"], - "test-android": ["bash $SCRIPTS_DIR/android/test.sh"] + "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], + "test-android": ["sh $SCRIPTS_DIR/android/test.sh"] } } } diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index 5862daa39..f15d16f1f 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -14,8 +14,8 @@ "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi" ], "scripts": { - "setup-ios": ["bash $SCRIPTS_DIR/ios/setup.sh"], - "test-ios": ["bash $SCRIPTS_DIR/ios/test.sh"] + "setup-ios": ["sh $SCRIPTS_DIR/ios/setup.sh"], + "test-ios": ["sh $SCRIPTS_DIR/ios/test.sh"] } } } diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index 606e39dfe..57e2b9107 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -10,7 +10,7 @@ "shell": { "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh"], "scripts": { - "build": ["bash $SCRIPTS_DIR/build.sh"], + "build": ["sh $SCRIPTS_DIR/build.sh"], "release": [ "npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}", "yarn install --immutable", From de7be372f6175ba7a473f97c46e372b2cd86c519 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 17:35:29 -0600 Subject: [PATCH 11/32] debug logs --- .github/workflows/ci-e2e-full.yml | 2 + .github/workflows/ci-e2e-latest.yml | 2 + .github/workflows/publish.yml | 2 + .../project.pbxproj | 4 -- .../project.pbxproj | 8 ++-- examples/E2E/ios/Podfile.lock | 2 +- scripts/android/env.sh | 29 ++++++++------ scripts/android/test.sh | 38 +++++++++++++++++++ scripts/ios/test.sh | 24 +++++++++++- wiki/devbox.md | 4 +- wiki/scripts.md | 5 ++- 11 files changed, 94 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 6ab7177ed..9443a1868 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -13,6 +13,7 @@ jobs: run-e2e-ios: runs-on: macos-26 env: + ANALYTICS_CI_DEBUG: "1" YARN_ENABLE_HARDENED_MODE: 0 XCODE_VERSION: '26.2' strategy: @@ -60,6 +61,7 @@ jobs: run-e2e-android: runs-on: ubuntu-latest env: + ANALYTICS_CI_DEBUG: "1" EMU_HEADLESS: 1 AVD_ABI: x86_64 strategy: diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index ef7dcb7cf..424133e6a 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -12,6 +12,7 @@ jobs: run-e2e-ios: runs-on: macos-26 env: + ANALYTICS_CI_DEBUG: "1" YARN_ENABLE_HARDENED_MODE: 0 XCODE_VERSION: '26.2' steps: @@ -49,6 +50,7 @@ jobs: run-e2e-android: runs-on: ubuntu-latest env: + ANALYTICS_CI_DEBUG: "1" EMU_HEADLESS: 1 AVD_ABI: x86_64 steps: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3c1b30f95..2f165e25d 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -26,6 +26,7 @@ jobs: name: E2E iOS (min/max) runs-on: macos-26 env: + ANALYTICS_CI_DEBUG: "1" YARN_ENABLE_HARDENED_MODE: 0 XCODE_VERSION: '26.2' strategy: @@ -74,6 +75,7 @@ jobs: name: E2E Android (min/max) runs-on: ubuntu-latest env: + ANALYTICS_CI_DEBUG: "1" EMU_HEADLESS: 1 AVD_ABI: x86_64 strategy: diff --git a/examples/E2E-73/ios/AnalyticsReactNativeE2E73.xcodeproj/project.pbxproj b/examples/E2E-73/ios/AnalyticsReactNativeE2E73.xcodeproj/project.pbxproj index 974b8d041..ccf2855be 100644 --- a/examples/E2E-73/ios/AnalyticsReactNativeE2E73.xcodeproj/project.pbxproj +++ b/examples/E2E-73/ios/AnalyticsReactNativeE2E73.xcodeproj/project.pbxproj @@ -582,8 +582,6 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -654,8 +652,6 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj b/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj index 9c478de2d..073a7fdb4 100644 --- a/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj +++ b/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj @@ -433,6 +433,7 @@ baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-AnalyticsReactNativeE2E-AnalyticsReactNativeE2ETests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -461,6 +462,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64"; INFOPLIST_FILE = AnalyticsReactNativeE2ETests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -487,6 +489,7 @@ CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64"; INFOPLIST_FILE = AnalyticsReactNativeE2E/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -513,6 +516,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = 1; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 x86_64"; INFOPLIST_FILE = AnalyticsReactNativeE2E/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -602,8 +606,6 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -676,8 +678,6 @@ ); OTHER_LDFLAGS = ( "$(inherited)", - "-Wl", - "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/examples/E2E/ios/Podfile.lock b/examples/E2E/ios/Podfile.lock index 0039daf46..a81ffcdf8 100644 --- a/examples/E2E/ios/Podfile.lock +++ b/examples/E2E/ios/Podfile.lock @@ -652,6 +652,6 @@ SPEC CHECKSUMS: sovran-react-native: eec37f82e4429f0e3661f46aaf4fcd85d1b54f60 Yoga: eddf2bbe4a896454c248a8f23b4355891eb720a6 -PODFILE CHECKSUM: a4c187e503408b85ffe8c89a4cb726ec541057ce +PODFILE CHECKSUM: a235bed286d6dd128990b8d39ccd155b6acdc28b COCOAPODS: 1.16.2 diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 7ddf623d3..14b8b2fc1 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -58,8 +58,15 @@ resolve_flake_sdk_root() { return 1 } -# Only act if neither var is already provided. -if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then +prefer_local="${ANDROID_SDK_USE_LOCAL:-}" +if [ -n "$prefer_local" ]; then + if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "${ANDROID_HOME:-}" ]; then + ANDROID_SDK_ROOT="$ANDROID_HOME" + fi + if [ -n "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then + ANDROID_HOME="$ANDROID_SDK_ROOT" + fi +else preferred_output="${ANDROID_SDK_FLAKE_OUTPUT:-}" sdk_root_max="" sdk_root_min="" @@ -85,14 +92,12 @@ if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -z "${ANDROID_HOME:-}" ]; then fi export ANDROID_SDK_ROOT_MAX ANDROID_HOME_MAX ANDROID_SDK_ROOT_MIN ANDROID_HOME_MIN - if [ -z "${ANDROID_SDK_ROOT:-}" ]; then - if [ -n "$sdk_root_max" ]; then - ANDROID_SDK_ROOT="$sdk_root_max" - ANDROID_HOME="$ANDROID_SDK_ROOT" - elif [ -n "$sdk_root_min" ]; then - ANDROID_SDK_ROOT="$sdk_root_min" - ANDROID_HOME="$ANDROID_SDK_ROOT" - fi + if [ -n "$sdk_root_max" ]; then + ANDROID_SDK_ROOT="$sdk_root_max" + ANDROID_HOME="$ANDROID_SDK_ROOT" + elif [ -n "$sdk_root_min" ]; then + ANDROID_SDK_ROOT="$sdk_root_min" + ANDROID_HOME="$ANDROID_SDK_ROOT" fi fi @@ -132,10 +137,10 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then echo "Using Android SDK: $ANDROID_SDK_ROOT" case "$ANDROID_SDK_ROOT" in /nix/store/*) - echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." + echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_SDK_USE_LOCAL=1 before starting devbox shell." ;; *) - echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT before starting devbox shell." + echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT and ensure ANDROID_SDK_USE_LOCAL is not set before starting devbox shell." ;; esac fi diff --git a/scripts/android/test.sh b/scripts/android/test.sh index a27edf02d..e889da2c7 100755 --- a/scripts/android/test.sh +++ b/scripts/android/test.sh @@ -5,6 +5,44 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" +if [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ]; then + echo "Android test env" + echo " ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT:-}" + echo " ANDROID_HOME=${ANDROID_HOME:-}" + echo " ANDROID_SDK_USE_LOCAL=${ANDROID_SDK_USE_LOCAL:-}" + echo " ANDROID_TARGET_API=${ANDROID_TARGET_API:-}" + echo " ANDROID_MIN_API=${ANDROID_MIN_API:-}" + echo " ANDROID_MAX_API=${ANDROID_MAX_API:-}" + echo " ANDROID_SYSTEM_IMAGE_TAG=${ANDROID_SYSTEM_IMAGE_TAG:-}" + echo " ANDROID_BUILD_TOOLS_VERSION=${ANDROID_BUILD_TOOLS_VERSION:-}" + echo " ANDROID_CMDLINE_TOOLS_VERSION=${ANDROID_CMDLINE_TOOLS_VERSION:-}" + echo " AVD_API=${AVD_API:-}" + echo " AVD_ABI=${AVD_ABI:-}" + echo " AVD_DEVICE=${AVD_DEVICE:-}" + echo " AVD_TAG=${AVD_TAG:-}" + echo " AVD_NAME=${AVD_NAME:-}" + echo " AVD_SECONDARY_API=${AVD_SECONDARY_API:-}" + echo " AVD_SECONDARY_ABI=${AVD_SECONDARY_ABI:-}" + echo " AVD_SECONDARY_DEVICE=${AVD_SECONDARY_DEVICE:-}" + echo " AVD_SECONDARY_TAG=${AVD_SECONDARY_TAG:-}" + echo " AVD_SECONDARY_NAME=${AVD_SECONDARY_NAME:-}" + echo " EMU_HEADLESS=${EMU_HEADLESS:-}" + echo " EMU_PORT=${EMU_PORT:-}" + echo " DETOX_AVD=${DETOX_AVD:-}" + if command -v uname >/dev/null 2>&1; then + echo " HOST_ARCH=$(uname -m)" + fi + if command -v sdkmanager >/dev/null 2>&1; then + echo " sdkmanager=$(command -v sdkmanager)" + fi + if command -v avdmanager >/dev/null 2>&1; then + echo " avdmanager=$(command -v avdmanager)" + fi + if command -v emulator >/dev/null 2>&1; then + echo " emulator=$(command -v emulator)" + fi +fi + sh "$SCRIPTS_DIR/android/setup.sh" yarn install yarn e2e install diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh index aa88b44c8..89f4810c9 100755 --- a/scripts/ios/test.sh +++ b/scripts/ios/test.sh @@ -9,13 +9,35 @@ if [ "$(uname -s)" = "Darwin" ]; then . "$SCRIPTS_DIR/ios/env.sh" fi -if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then +if [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ]; then echo "iOS test env" echo " PATH=$PATH" echo " CC=${CC:-}" echo " CXX=${CXX:-}" echo " SDKROOT=${SDKROOT:-}" echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" + echo " IOS_RUNTIME=${IOS_RUNTIME:-}" + echo " IOS_MIN_RUNTIME=${IOS_MIN_RUNTIME:-}" + echo " IOS_MAX_RUNTIME=${IOS_MAX_RUNTIME:-}" + echo " DETOX_IOS_DEVICE=${DETOX_IOS_DEVICE:-}" + echo " IOS_DEVICE_NAMES=${IOS_DEVICE_NAMES:-}" + echo " IOS_DEVELOPER_DIR=${IOS_DEVELOPER_DIR:-}" + echo " IOS_DOWNLOAD_RUNTIME=${IOS_DOWNLOAD_RUNTIME:-}" + if command -v sw_vers >/dev/null 2>&1; then + sw_vers + fi + if command -v xcode-select >/dev/null 2>&1; then + echo "xcode-select: $(xcode-select -p 2>/dev/null || true)" + fi + if command -v xcodebuild >/dev/null 2>&1; then + xcodebuild -version 2>/dev/null || true + fi + if command -v swiftc >/dev/null 2>&1; then + swiftc --version 2>/dev/null || true + fi + if command -v clang >/dev/null 2>&1; then + clang --version 2>/dev/null | head -n 1 || true + fi fi sh "$SCRIPTS_DIR/ios/setup.sh" diff --git a/wiki/devbox.md b/wiki/devbox.md index f6645e73b..195819538 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -13,13 +13,13 @@ Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT ## Android -By default, Devbox uses the flake-pinned SDK (`path:./nix#android-sdk`). It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Clear both env vars to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/setup.sh` + `scripts/android/manager.sh`). Version sources are documented in `wiki/nix.md`. +By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_SDK_USE_LOCAL=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_SDK_USE_LOCAL` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/setup.sh` + `scripts/android/manager.sh`). Version sources are documented in `wiki/nix.md`. ### Emulator/AVD scripts - `devbox run start-android` launches the default “latest” AVD (API 33, Medium Phone). On arm64 hosts it uses the arm64-v8a image; on Intel it uses x86_64. Override with `AVD_FLAVOR=minsdk` to launch the API 21 Pixel AVD instead. You can also set `DETOX_AVD` to pick an exact AVD name. - `devbox run start-android-latest` / `start-android-minsdk` explicitly launch the latest (API 33) or minsdk (API 21) AVDs. Both will create the AVD first via `scripts/android/setup.sh` if it does not exist. -- `scripts/android/setup.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`. Defaults target API 21 for minsdk; CI passes API 33 for latest. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. +- `scripts/android/setup.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. - `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. - `EMU_HEADLESS=1 devbox run start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. - `EMU_PORT=5554 devbox run start-android*` to set the emulator port/serial (defaults to 5554) and avoid adb conflicts. diff --git a/wiki/scripts.md b/wiki/scripts.md index 65ed39591..5c9faaa5f 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -23,7 +23,8 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `scripts/android/env.sh` - - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK. + - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). + - Set `ANDROID_SDK_USE_LOCAL=1` to keep a pre-set local SDK instead. - Loads platform defaults via `scripts/platform-versions.sh`. - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. @@ -36,7 +37,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `scripts/android/manager.sh` - Starts/stops/resets AVDs and applies emulator defaults. - - Uses `devbox run setup-android` to ensure AVDs exist. + - Invokes `scripts/android/setup.sh` directly to ensure AVDs exist. - `scripts/android/test.sh` - Runs setup + yarn build + Android E2E (Detox). From d701c87736dbf7330e3391733f5f83a4cc6d1ebf Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 18:15:53 -0600 Subject: [PATCH 12/32] debug logs --- .github/workflows/ci-e2e-full.yml | 2 - .github/workflows/ci-e2e-latest.yml | 1 - .github/workflows/publish.yml | 2 - devbox.json | 35 ++++----- nix/platform-versions.json | 4 +- scripts/act-ci.sh | 5 ++ scripts/android/env.sh | 112 +++++++++++++++++++++------- scripts/android/manager.sh | 1 + scripts/android/setup.sh | 36 +++++++-- scripts/android/test.sh | 50 ++++--------- scripts/build.sh | 1 + scripts/devbox/init.sh | 25 +++++++ scripts/ios/env.sh | 66 +++++++++++++--- scripts/ios/manager.sh | 3 +- scripts/ios/setup.sh | 6 +- scripts/ios/simctl.sh | 4 + scripts/ios/test.sh | 32 +------- scripts/platform-versions.sh | 30 ++++++++ scripts/shared/common.sh | 6 ++ scripts/shared/debug.sh | 32 ++++++++ shells/android-max/devbox.json | 8 +- shells/android-min/devbox.json | 8 +- shells/ios/devbox.json | 7 +- shells/minimal/devbox.json | 4 +- wiki/devbox.md | 6 +- wiki/nix.md | 2 +- 26 files changed, 330 insertions(+), 158 deletions(-) create mode 100644 scripts/devbox/init.sh create mode 100644 scripts/shared/debug.sh diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 9443a1868..18419baf1 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -50,10 +50,8 @@ jobs: . scripts/platform-versions.sh if [ "${{ matrix.name }}" = "ios-min" ]; then echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MIN_DEVICE}" >> "$GITHUB_ENV" - echo "IOS_RUNTIME=${PLATFORM_IOS_MIN_RUNTIME}" >> "$GITHUB_ENV" else echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" - echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" fi - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 424133e6a..84f03849c 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -43,7 +43,6 @@ jobs: run: | . scripts/platform-versions.sh echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" - echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" - name: iOS E2E Tests (latest) run: devbox run --config=shells/ios/devbox.json test-ios diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2f165e25d..235fe0f73 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -63,10 +63,8 @@ jobs: . scripts/platform-versions.sh if [ "${{ matrix.name }}" = "ios-min" ]; then echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MIN_DEVICE}" >> "$GITHUB_ENV" - echo "IOS_RUNTIME=${PLATFORM_IOS_MIN_RUNTIME}" >> "$GITHUB_ENV" else echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" - echo "IOS_RUNTIME=${PLATFORM_IOS_MAX_RUNTIME}" >> "$GITHUB_ENV" fi - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios diff --git a/devbox.json b/devbox.json index 906f61227..16b3b4dac 100644 --- a/devbox.json +++ b/devbox.json @@ -19,10 +19,7 @@ "shell": { "init_hook": [ "echo 'Welcome to analytics-react-native devbox!' > /dev/null", - ". $DEVBOX_PROJECT_ROOT/scripts/shared/common.sh", - "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $DEVBOX_PROJECT_ROOT/scripts/ios/env.sh; fi", - ". $DEVBOX_PROJECT_ROOT/scripts/android/env.sh", - "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi" + "DEVBOX_INIT_ANDROID=1 DEVBOX_INIT_IOS=1 sh $DEVBOX_PROJECT_ROOT/scripts/devbox/init.sh" ], "scripts": { "clean": [ @@ -32,23 +29,23 @@ "yarn cache clean", "find $DEVBOX_PROJECT_DIR -type d -name node_modules -exec rmdir {} \\;" ], - "build": ["sh $SCRIPTS_DIR/build.sh"], + "build": ["sh $DEVBOX_PROJECT_ROOT/scripts/build.sh"], "format": ["treefmt"], "lint": ["treefmt --fail-on-change"], - "test-android": ["sh $SCRIPTS_DIR/android/test.sh"], - "test-ios": ["sh $SCRIPTS_DIR/ios/test.sh"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/test.sh"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/test.sh"], "act-ci": [ - "sh $SCRIPTS_DIR/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" + "sh $DEVBOX_PROJECT_ROOT/scripts/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" ], - "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], - "setup-ios": ["sh $SCRIPTS_DIR/ios/setup.sh"], - "start-emulator": ["sh $SCRIPTS_DIR/android/manager.sh start"], - "start-ios": ["sh $SCRIPTS_DIR/ios/manager.sh start"], - "start-android-minsdk": ["sh $SCRIPTS_DIR/android/manager.sh start"], + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/setup.sh"], + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/setup.sh"], + "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], + "start-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh start"], + "start-android-minsdk": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], "start-android-latest": [ - "AVD_FLAVOR=latest sh $SCRIPTS_DIR/android/manager.sh start" + "AVD_FLAVOR=latest sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start" ], - "start-android": ["sh $SCRIPTS_DIR/android/manager.sh start"], + "start-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], "update-apps": [ "yarn install --no-immutable", "yarn e2e install --no-immutable", @@ -61,10 +58,10 @@ "devbox update --config=shells/android-max/devbox.json", "devbox update --config=shells/ios/devbox.json" ], - "reset-android": ["sh $SCRIPTS_DIR/android/manager.sh reset"], - "reset-ios": ["sh $SCRIPTS_DIR/ios/manager.sh reset"], - "stop-android": ["sh $SCRIPTS_DIR/android/manager.sh stop"], - "stop-ios": ["sh $SCRIPTS_DIR/ios/manager.sh stop"], + "reset-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh reset"], + "reset-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh reset"], + "stop-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh stop"], + "stop-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh stop"], "stop": ["devbox run stop-android", "devbox run stop-ios"], "test": ["devbox run test-android", "devbox run test-ios"] } diff --git a/nix/platform-versions.json b/nix/platform-versions.json index 506669900..87c7ac9b8 100644 --- a/nix/platform-versions.json +++ b/nix/platform-versions.json @@ -6,8 +6,8 @@ "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG": "google_apis", "PLATFORM_ANDROID_MIN_DEVICE": "pixel", "PLATFORM_ANDROID_MAX_DEVICE": "medium_phone", - "PLATFORM_IOS_MIN_RUNTIME": "15.0", - "PLATFORM_IOS_MAX_RUNTIME": "", + "PLATFORM_IOS_MIN_VERSION": "15.0", + "PLATFORM_IOS_MAX_VERSION": "26.2", "PLATFORM_IOS_MIN_DEVICE": "iPhone 13", "PLATFORM_IOS_MAX_DEVICE": "iPhone 17" } diff --git a/scripts/act-ci.sh b/scripts/act-ci.sh index 58a996cf8..55a20d38f 100755 --- a/scripts/act-ci.sh +++ b/scripts/act-ci.sh @@ -4,6 +4,11 @@ set -eu # Run GitHub Actions workflows locally via act. # Usage: scripts/act-ci.sh [--job JOB] [--platform ubuntu-latest=IMAGE] +script_dir="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1090 +. "$script_dir/shared/common.sh" +debug_log_script "scripts/act-ci.sh" + JOB="" PLATFORMS="" diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 14b8b2fc1..f93fd37c9 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -10,6 +10,7 @@ script_dir="$project_root/scripts/android" # shellcheck disable=SC1090 . "$project_root/scripts/shared/common.sh" load_platform_versions "$script_dir" +debug_log_script "scripts/android/env.sh" if [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then if ! command -v jq >/dev/null 2>&1; then @@ -58,6 +59,25 @@ resolve_flake_sdk_root() { return 1 } +detect_sdk_root_from_sdkmanager() { + sm=$(command -v sdkmanager 2>/dev/null || true) + if [ -z "$sm" ]; then + return 1 + fi + if command -v readlink >/dev/null 2>&1; then + sm="$(readlink "$sm" 2>/dev/null || printf '%s' "$sm")" + fi + sm_dir="$(cd "$(dirname "$sm")" && pwd)" + candidates="${sm_dir}/.. ${sm_dir}/../share/android-sdk ${sm_dir}/../libexec/android-sdk ${sm_dir}/../.." + for c in $candidates; do + if [ -d "$c/platform-tools" ] || [ -d "$c/platforms" ] || [ -d "$c/system-images" ]; then + printf '%s\n' "$c" + return 0 + fi + done + return 1 +} + prefer_local="${ANDROID_SDK_USE_LOCAL:-}" if [ -n "$prefer_local" ]; then if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "${ANDROID_HOME:-}" ]; then @@ -99,6 +119,14 @@ else ANDROID_SDK_ROOT="$sdk_root_min" ANDROID_HOME="$ANDROID_SDK_ROOT" fi + + if [ -z "${ANDROID_SDK_ROOT:-}" ]; then + detected_root="$(detect_sdk_root_from_sdkmanager 2>/dev/null || true)" + if [ -n "$detected_root" ]; then + ANDROID_SDK_ROOT="$detected_root" + ANDROID_HOME="$ANDROID_SDK_ROOT" + fi + fi fi if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "${ANDROID_HOME:-}" ]; then @@ -112,7 +140,7 @@ fi export ANDROID_SDK_ROOT ANDROID_HOME export ANDROID_BUILD_TOOLS_VERSION -if [ -n "${ANDROID_SDK_ROOT:-}" ]; then + if [ -n "${ANDROID_SDK_ROOT:-}" ]; then # Prefer cmdline-tools;latest, or fall back to the highest numbered cmdline-tools folder. cmdline_tools_bin="" if [ -d "$ANDROID_SDK_ROOT/cmdline-tools/latest/bin" ]; then @@ -134,17 +162,19 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then PATH="$new_path" export PATH if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then - echo "Using Android SDK: $ANDROID_SDK_ROOT" - case "$ANDROID_SDK_ROOT" in - /nix/store/*) - echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_SDK_USE_LOCAL=1 before starting devbox shell." - ;; - *) - echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT and ensure ANDROID_SDK_USE_LOCAL is not set before starting devbox shell." - ;; - esac - fi - if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_ANDROID_SDK_SUMMARY_PRINTED:-}" ]; then + if [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ]; then + echo "Using Android SDK: $ANDROID_SDK_ROOT" + case "$ANDROID_SDK_ROOT" in + /nix/store/*) + echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_SDK_USE_LOCAL=1 before starting devbox shell." + ;; + *) + echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT and ensure ANDROID_SDK_USE_LOCAL is not set before starting devbox shell." + ;; + esac + fi + fi +if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_ANDROID_SDK_SUMMARY_PRINTED:-}" ]; then DEVBOX_ANDROID_SDK_SUMMARY_PRINTED=1 export DEVBOX_ANDROID_SDK_SUMMARY_PRINTED @@ -169,37 +199,65 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then elif [ -n "${ANDROID_TARGET_API:-}" ]; then android_target_source="target" fi - if [ -n "$android_sdk_root" ] && [ -n "$android_max_api" ] && [ -n "$android_system_image_tag" ]; then + + android_target_device="${AVD_DEVICE:-}" + if [ -z "$android_target_device" ]; then + if [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_min_api" ]; then + android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" + elif [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_max_api" ]; then + android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" + fi + fi + + candidates="" + if [ -n "$android_sdk_root" ] && [ -n "$android_system_image_tag" ]; then host_arch="$(uname -m)" if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then candidates="arm64-v8a x86_64 x86" else candidates="x86_64 x86 arm64-v8a" fi - for abi in $candidates; do - if [ -d "$android_sdk_root/system-images/android-${android_max_api}/${android_system_image_tag}/${abi}" ]; then - android_system_image_abi="$abi" - break - fi - done fi - if [ -z "$android_target_api" ] && [ -n "$android_sdk_root" ] && [ -n "$android_min_api" ] && [ -n "$android_system_image_tag" ]; then + + if [ -n "$android_sdk_root" ] && [ -n "$android_target_api" ] && [ -n "$android_system_image_tag" ]; then for abi in $candidates; do - if [ -d "$android_sdk_root/system-images/android-${android_min_api}/${android_system_image_tag}/${abi}" ]; then - android_system_image_abi="${android_system_image_abi:-$abi}" - if [ -z "$android_target_api" ]; then - android_target_api="$android_min_api" - android_target_source="min" - fi + if [ -d "$android_sdk_root/system-images/android-${android_target_api}/${android_system_image_tag}/${abi}" ]; then + android_system_image_abi="$abi" break fi done fi + if [ -n "$android_system_image_abi" ]; then android_system_image_summary="${android_system_image_tag};${android_system_image_abi}" else android_system_image_summary="$android_system_image_tag" fi + if [ -n "$android_target_device" ]; then + android_system_image_summary="${android_system_image_summary} (${android_target_device})" + fi + + if debug_enabled; then + if [ "${ANDROID_ENV_DEBUG_PRINTED:-}" != "1" ]; then + ANDROID_ENV_DEBUG_PRINTED=1 + export ANDROID_ENV_DEBUG_PRINTED + debug_dump_vars \ + ANDROID_SDK_ROOT \ + ANDROID_HOME \ + ANDROID_SDK_USE_LOCAL \ + ANDROID_SDK_FLAKE_OUTPUT \ + ANDROID_SDK_ROOT_MIN \ + ANDROID_HOME_MIN \ + ANDROID_SDK_ROOT_MAX \ + ANDROID_HOME_MAX \ + ANDROID_MIN_API \ + ANDROID_MAX_API \ + ANDROID_TARGET_API \ + ANDROID_SYSTEM_IMAGE_TAG \ + ANDROID_BUILD_TOOLS_VERSION \ + ANDROID_CMDLINE_TOOLS_VERSION + fi + fi echo "Resolved Android SDK" echo " ANDROID_SDK_ROOT: ${android_sdk_root:-not set}" @@ -207,7 +265,7 @@ if [ -n "${ANDROID_SDK_ROOT:-}" ]; then echo " ANDROID_MIN_API: ${android_min_api:-21}" echo " ANDROID_MAX_API: ${android_max_api:-33}" echo " ANDROID_TARGET_API: ${android_target_api:-not set}${android_target_source:+ (${android_target_source})}" - echo " ANDROID_SYSTEM_IMAGE_TAG: ${android_system_image_summary:-google_apis}" + echo " ANDROID_AVD_TARGET: api=${android_target_api:-not set} device=${android_target_device:-unknown} image=${android_system_image_summary:-google_apis}" fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/android/manager.sh b/scripts/android/manager.sh index b06e25c9a..f9d537d7f 100755 --- a/scripts/android/manager.sh +++ b/scripts/android/manager.sh @@ -7,6 +7,7 @@ shift || true script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/env.sh" +debug_log_script "scripts/android/manager.sh" start_android() { flavor="${AVD_FLAVOR:-latest}" diff --git a/scripts/android/setup.sh b/scripts/android/setup.sh index 377f54a13..cdbad4f03 100755 --- a/scripts/android/setup.sh +++ b/scripts/android/setup.sh @@ -20,6 +20,7 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" load_platform_versions "$script_dir" +debug_log_script "scripts/android/setup.sh" detect_sdk_root() { if [ -n "${ANDROID_SDK_ROOT:-}" ]; then @@ -31,8 +32,11 @@ detect_sdk_root() { if [ -z "$sm" ]; then return 1 fi - sm=$(readlink -f "$sm") - candidates="$(dirname "$sm")/.. $(dirname "$sm")/../share/android-sdk $(dirname "$sm")/../libexec/android-sdk $(dirname "$sm")/../.." + if command -v readlink >/dev/null 2>&1; then + sm="$(readlink "$sm" 2>/dev/null || printf '%s' "$sm")" + fi + sm_dir="$(cd "$(dirname "$sm")" && pwd)" + candidates="${sm_dir}/.. ${sm_dir}/../share/android-sdk ${sm_dir}/../libexec/android-sdk ${sm_dir}/../.." for c in $candidates; do if [ -d "$c/platform-tools" ] || [ -d "$c/platforms" ] || [ -d "$c/system-images" ]; then printf '%s\n' "$c" @@ -130,16 +134,38 @@ main() { require_tool avdmanager require_tool emulator - primary_api="${AVD_API:-${ANDROID_TARGET_API:-${ANDROID_MAX_API:-${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}}}}" - primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" - primary_device="${AVD_DEVICE:-pixel}" + platform_min_api="${PLATFORM_ANDROID_MIN_API:-21}" + platform_max_api="${PLATFORM_ANDROID_MAX_API:-33}" + platform_min_device="${PLATFORM_ANDROID_MIN_DEVICE:-pixel}" + platform_max_device="${PLATFORM_ANDROID_MAX_DEVICE:-medium_phone}" + platform_image_tag="${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" + + primary_api="${AVD_API:-${ANDROID_TARGET_API:-${ANDROID_MAX_API:-${platform_max_api:-${ANDROID_MIN_API:-$platform_min_api}}}}}" + primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" + if [ -n "${AVD_DEVICE:-}" ]; then + primary_device="$AVD_DEVICE" + elif [ -n "$primary_api" ] && [ "$primary_api" = "$platform_min_api" ]; then + primary_device="$platform_min_device" + elif [ -n "$primary_api" ] && [ "$primary_api" = "$platform_max_api" ]; then + primary_device="$platform_max_device" + else + primary_device="pixel" + fi primary_preferred_abi="${AVD_ABI:-}" + if debug_enabled; then + debug_log "primary_api=${primary_api} primary_device=${primary_device} primary_tag=${primary_tag} primary_preferred_abi=${primary_preferred_abi:-auto}" + fi + secondary_api="${AVD_SECONDARY_API:-${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}}" secondary_tag="${AVD_SECONDARY_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" secondary_device="${AVD_SECONDARY_DEVICE:-medium_phone}" secondary_preferred_abi="${AVD_SECONDARY_ABI:-}" + if debug_enabled; then + debug_log "secondary_api=${secondary_api} secondary_device=${secondary_device} secondary_tag=${secondary_tag} secondary_preferred_abi=${secondary_preferred_abi:-auto}" + fi + primary_required=0 if [ -n "${AVD_API:-}" ] || [ -n "${AVD_TAG:-}" ] || [ -n "${AVD_DEVICE:-}" ] || [ -n "${AVD_ABI:-}" ] || [ -n "${AVD_NAME:-}" ]; then primary_required=1 diff --git a/scripts/android/test.sh b/scripts/android/test.sh index e889da2c7..18098ac22 100755 --- a/scripts/android/test.sh +++ b/scripts/android/test.sh @@ -4,44 +4,22 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" +load_platform_versions "$script_dir" +debug_log_script "scripts/android/test.sh" -if [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ]; then - echo "Android test env" - echo " ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT:-}" - echo " ANDROID_HOME=${ANDROID_HOME:-}" - echo " ANDROID_SDK_USE_LOCAL=${ANDROID_SDK_USE_LOCAL:-}" - echo " ANDROID_TARGET_API=${ANDROID_TARGET_API:-}" - echo " ANDROID_MIN_API=${ANDROID_MIN_API:-}" - echo " ANDROID_MAX_API=${ANDROID_MAX_API:-}" - echo " ANDROID_SYSTEM_IMAGE_TAG=${ANDROID_SYSTEM_IMAGE_TAG:-}" - echo " ANDROID_BUILD_TOOLS_VERSION=${ANDROID_BUILD_TOOLS_VERSION:-}" - echo " ANDROID_CMDLINE_TOOLS_VERSION=${ANDROID_CMDLINE_TOOLS_VERSION:-}" - echo " AVD_API=${AVD_API:-}" - echo " AVD_ABI=${AVD_ABI:-}" - echo " AVD_DEVICE=${AVD_DEVICE:-}" - echo " AVD_TAG=${AVD_TAG:-}" - echo " AVD_NAME=${AVD_NAME:-}" - echo " AVD_SECONDARY_API=${AVD_SECONDARY_API:-}" - echo " AVD_SECONDARY_ABI=${AVD_SECONDARY_ABI:-}" - echo " AVD_SECONDARY_DEVICE=${AVD_SECONDARY_DEVICE:-}" - echo " AVD_SECONDARY_TAG=${AVD_SECONDARY_TAG:-}" - echo " AVD_SECONDARY_NAME=${AVD_SECONDARY_NAME:-}" - echo " EMU_HEADLESS=${EMU_HEADLESS:-}" - echo " EMU_PORT=${EMU_PORT:-}" - echo " DETOX_AVD=${DETOX_AVD:-}" - if command -v uname >/dev/null 2>&1; then - echo " HOST_ARCH=$(uname -m)" - fi - if command -v sdkmanager >/dev/null 2>&1; then - echo " sdkmanager=$(command -v sdkmanager)" - fi - if command -v avdmanager >/dev/null 2>&1; then - echo " avdmanager=$(command -v avdmanager)" - fi - if command -v emulator >/dev/null 2>&1; then - echo " emulator=$(command -v emulator)" - fi +if [ -z "${ANDROID_MIN_API:-}" ] && [ -n "${PLATFORM_ANDROID_MIN_API:-}" ]; then + ANDROID_MIN_API="$PLATFORM_ANDROID_MIN_API" fi +if [ -z "${ANDROID_MAX_API:-}" ] && [ -n "${PLATFORM_ANDROID_MAX_API:-}" ]; then + ANDROID_MAX_API="$PLATFORM_ANDROID_MAX_API" +fi +if [ -z "${ANDROID_SYSTEM_IMAGE_TAG:-}" ] && [ -n "${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-}" ]; then + ANDROID_SYSTEM_IMAGE_TAG="$PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" +fi +if [ -z "${ANDROID_TARGET_API:-}" ] && [ -n "${ANDROID_MAX_API:-}" ]; then + ANDROID_TARGET_API="$ANDROID_MAX_API" +fi +export ANDROID_MIN_API ANDROID_MAX_API ANDROID_SYSTEM_IMAGE_TAG ANDROID_TARGET_API sh "$SCRIPTS_DIR/android/setup.sh" yarn install diff --git a/scripts/build.sh b/scripts/build.sh index 9c4e841f6..42aa2183c 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -4,6 +4,7 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/shared/common.sh" +debug_log_script "scripts/build.sh" yarn install --immutable yarn build diff --git a/scripts/devbox/init.sh b/scripts/devbox/init.sh new file mode 100644 index 000000000..4fd673eae --- /dev/null +++ b/scripts/devbox/init.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env sh +set -eu + +script_dir="$(cd "$(dirname "$0")" && pwd)" +repo_root="$(cd "$script_dir/../.." && pwd)" + +PROJECT_ROOT="$repo_root" +SCRIPTS_DIR="$repo_root/scripts" +export PROJECT_ROOT SCRIPTS_DIR + +# shellcheck disable=SC1090 +. "$repo_root/scripts/shared/common.sh" + +if [ "${DEVBOX_INIT_IOS:-}" = "1" ] && [ "$(uname -s)" = "Darwin" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/ios/env.sh" +fi + +if [ "${DEVBOX_INIT_ANDROID:-}" = "1" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/android/env.sh" + if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + echo "Android SDK env configured (details: wiki/devbox.md#devbox-android)." + fi +fi diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 4c120de87..5dc2bb9e9 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -1,6 +1,12 @@ #!/usr/bin/env sh set -eu +script_dir="$(cd "$(dirname "$0")" && pwd)" +# shellcheck disable=SC1090 +. "$script_dir/../shared/common.sh" +debug_log_script "scripts/ios/env.sh" +load_platform_versions "$script_dir" + devbox_omit_nix_env() { if [ "${DEVBOX_OMIT_NIX_ENV_APPLIED:-}" = "1" ]; then return 0 @@ -10,6 +16,9 @@ devbox_omit_nix_env() { dump_env() { if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then + if ! debug_enabled; then + return 0 + fi echo "devbox omit-nix-env $1" echo " PATH=$PATH" echo " CC=${CC:-}" @@ -72,7 +81,41 @@ devbox_omit_nix_env() { devbox_omit_nix_env -if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SUMMARY_PRINTED:-}" ]; then +if debug_enabled; then + if [ "${IOS_ENV_DEBUG_PRINTED:-}" != "1" ]; then + IOS_ENV_DEBUG_PRINTED=1 + export IOS_ENV_DEBUG_PRINTED + debug_dump_vars \ + IOS_RUNTIME \ + IOS_MIN_VERSION \ + IOS_MAX_VERSION \ + IOS_DEVICE_NAMES \ + DETOX_IOS_DEVICE \ + IOS_DEVELOPER_DIR \ + IOS_DOWNLOAD_RUNTIME \ + DEVELOPER_DIR \ + SDKROOT \ + CC \ + CXX + if command -v sw_vers >/dev/null 2>&1; then + sw_vers + fi + if command -v xcode-select >/dev/null 2>&1; then + echo "xcode-select: $(xcode-select -p 2>/dev/null || true)" + fi + if command -v xcodebuild >/dev/null 2>&1; then + xcodebuild -version 2>/dev/null || true + fi + if command -v swiftc >/dev/null 2>&1; then + swiftc --version 2>/dev/null || true + fi + if command -v clang >/dev/null 2>&1; then + clang --version 2>/dev/null | head -n 1 || true + fi + fi +fi + +if [ -n "${DEVBOX_INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SUMMARY_PRINTED:-}" ]; then DEVBOX_IOS_SDK_SUMMARY_PRINTED=1 export DEVBOX_IOS_SDK_SUMMARY_PRINTED @@ -84,7 +127,7 @@ if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SU repo_root="$(cd "$(dirname "$0")/../.." && pwd)" fi - if [ -z "${PLATFORM_IOS_MIN_RUNTIME:-}" ] || [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then + if [ -z "${PLATFORM_IOS_MIN_VERSION:-}" ] || [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then if ! command -v jq >/dev/null 2>&1; then if [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then PATH="$DEVBOX_PACKAGES_DIR/bin:$PATH" @@ -94,10 +137,14 @@ if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SU . "$repo_root/scripts/platform-versions.sh" fi - ios_min_runtime="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-}}" - ios_max_runtime="${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-}}" - if [ -z "$ios_max_runtime" ] && command -v xcrun >/dev/null 2>&1; then - ios_max_runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + ios_min_version="${IOS_MIN_VERSION:-${PLATFORM_IOS_MIN_VERSION:-}}" + ios_max_version="${IOS_MAX_VERSION:-${PLATFORM_IOS_MAX_VERSION:-}}" + ios_runtime="${IOS_RUNTIME:-}" + if [ -z "$ios_runtime" ] && command -v xcrun >/dev/null 2>&1; then + ios_runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + fi + if [ -z "$ios_max_version" ]; then + ios_max_version="$ios_runtime" fi xcode_dir="${DEVELOPER_DIR:-}" @@ -110,11 +157,10 @@ if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SU xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" fi - ios_target_runtime="${IOS_RUNTIME:-${ios_max_runtime:-${ios_min_runtime:-}}}" echo "Resolved iOS SDK" - echo " IOS_MIN_RUNTIME: ${ios_min_runtime:-not set}" - echo " IOS_MAX_RUNTIME: ${ios_max_runtime:-not set}" - echo " IOS_RUNTIME: ${ios_target_runtime:-not set}" + echo " IOS_MIN_VERSION: ${ios_min_version:-not set}" + echo " IOS_MAX_VERSION: ${ios_max_version:-not set}" + echo " IOS_RUNTIME: ${ios_runtime:-not set}" echo " xcodebuild: ${xcode_version:-unknown}" echo " DEVELOPER_DIR: ${xcode_dir:-not set}" fi diff --git a/scripts/ios/manager.sh b/scripts/ios/manager.sh index f0ca5ba40..b23c590d6 100755 --- a/scripts/ios/manager.sh +++ b/scripts/ios/manager.sh @@ -5,6 +5,7 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" load_platform_versions "$script_dir" +debug_log_script "scripts/ios/manager.sh" action="${1:-}" shift || true @@ -13,12 +14,10 @@ start_ios() { flavor="${IOS_FLAVOR:-latest}" if [ "$flavor" = "minsdk" ]; then IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" - IOS_RUNTIME="${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE else IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - IOS_RUNTIME="${IOS_RUNTIME:-${IOS_MAX_RUNTIME:-${PLATFORM_IOS_MAX_RUNTIME:-}}}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE fi diff --git a/scripts/ios/setup.sh b/scripts/ios/setup.sh index 3a17b941f..4038398a4 100755 --- a/scripts/ios/setup.sh +++ b/scripts/ios/setup.sh @@ -7,6 +7,7 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/simctl.sh" load_platform_versions "$script_dir" +debug_log_script "scripts/ios/setup.sh" # Creates local iOS simulators for common targets. Requires Xcode command-line tools and jq. # Env overrides: @@ -62,7 +63,10 @@ main() { return 1 fi devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - runtime="${IOS_RUNTIME:-${IOS_MIN_RUNTIME:-${PLATFORM_IOS_MIN_RUNTIME:-15.0}}}" + runtime="${IOS_RUNTIME:-}" + if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then + runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + fi ifs_backup="$IFS" IFS=',' diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index 5c5b50b15..88121ac71 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -1,6 +1,10 @@ #!/usr/bin/env sh set -eu +if command -v debug_log_script >/dev/null 2>&1; then + debug_log_script "scripts/ios/simctl.sh" +fi + ensure_core_sim_service() { status=0 output="$(xcrun simctl list devices -j 2>&1)" || status=$? diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh index 89f4810c9..dceb72527 100755 --- a/scripts/ios/test.sh +++ b/scripts/ios/test.sh @@ -4,42 +4,12 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" +debug_log_script "scripts/ios/test.sh" if [ "$(uname -s)" = "Darwin" ]; then . "$SCRIPTS_DIR/ios/env.sh" fi -if [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ]; then - echo "iOS test env" - echo " PATH=$PATH" - echo " CC=${CC:-}" - echo " CXX=${CXX:-}" - echo " SDKROOT=${SDKROOT:-}" - echo " DEVELOPER_DIR=${DEVELOPER_DIR:-}" - echo " IOS_RUNTIME=${IOS_RUNTIME:-}" - echo " IOS_MIN_RUNTIME=${IOS_MIN_RUNTIME:-}" - echo " IOS_MAX_RUNTIME=${IOS_MAX_RUNTIME:-}" - echo " DETOX_IOS_DEVICE=${DETOX_IOS_DEVICE:-}" - echo " IOS_DEVICE_NAMES=${IOS_DEVICE_NAMES:-}" - echo " IOS_DEVELOPER_DIR=${IOS_DEVELOPER_DIR:-}" - echo " IOS_DOWNLOAD_RUNTIME=${IOS_DOWNLOAD_RUNTIME:-}" - if command -v sw_vers >/dev/null 2>&1; then - sw_vers - fi - if command -v xcode-select >/dev/null 2>&1; then - echo "xcode-select: $(xcode-select -p 2>/dev/null || true)" - fi - if command -v xcodebuild >/dev/null 2>&1; then - xcodebuild -version 2>/dev/null || true - fi - if command -v swiftc >/dev/null 2>&1; then - swiftc --version 2>/dev/null || true - fi - if command -v clang >/dev/null 2>&1; then - clang --version 2>/dev/null | head -n 1 || true - fi -fi - sh "$SCRIPTS_DIR/ios/setup.sh" yarn install yarn e2e install diff --git a/scripts/platform-versions.sh b/scripts/platform-versions.sh index 024dba43e..12b445608 100644 --- a/scripts/platform-versions.sh +++ b/scripts/platform-versions.sh @@ -5,6 +5,15 @@ script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="$(cd "$script_dir/.." && pwd)" versions_json="${PLATFORM_VERSIONS_JSON:-$repo_root/nix/platform-versions.json}" +if ! command -v debug_log_script >/dev/null 2>&1; then + if [ -f "$script_dir/shared/debug.sh" ]; then + # shellcheck disable=SC1090 + . "$script_dir/shared/debug.sh" + fi +fi + +debug_log_script "scripts/platform-versions.sh" + jq_cmd="" if command -v jq >/dev/null 2>&1; then jq_cmd="jq" @@ -16,4 +25,25 @@ if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then eval "$( "$jq_cmd" -r 'to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" )" + if debug_enabled; then + if [ "${PLATFORM_VERSIONS_DEBUG_PRINTED:-}" != "1" ]; then + PLATFORM_VERSIONS_DEBUG_PRINTED=1 + export PLATFORM_VERSIONS_DEBUG_PRINTED + for key in \ + PLATFORM_ANDROID_MIN_API \ + PLATFORM_ANDROID_MAX_API \ + PLATFORM_ANDROID_BUILD_TOOLS_VERSION \ + PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION \ + PLATFORM_ANDROID_SYSTEM_IMAGE_TAG \ + PLATFORM_ANDROID_MIN_DEVICE \ + PLATFORM_ANDROID_MAX_DEVICE \ + PLATFORM_IOS_MIN_VERSION \ + PLATFORM_IOS_MAX_VERSION \ + PLATFORM_IOS_MIN_DEVICE \ + PLATFORM_IOS_MAX_DEVICE; do + value="$(eval "printf '%s' \"\${$key-}\"")" + printf 'DEBUG: %s=%s\n' "$key" "$value" + done + fi + fi fi diff --git a/scripts/shared/common.sh b/scripts/shared/common.sh index a62edbf02..98cb52bff 100644 --- a/scripts/shared/common.sh +++ b/scripts/shared/common.sh @@ -52,3 +52,9 @@ if [ -z "${SCRIPTS_DIR:-}" ] && [ -n "${PROJECT_ROOT:-}" ]; then SCRIPTS_DIR="$PROJECT_ROOT/scripts" export SCRIPTS_DIR fi + +if [ -f "${SCRIPTS_DIR:-}/shared/debug.sh" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/shared/debug.sh" + debug_log_script "scripts/shared/common.sh" +fi diff --git a/scripts/shared/debug.sh b/scripts/shared/debug.sh new file mode 100644 index 000000000..51824b9ad --- /dev/null +++ b/scripts/shared/debug.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env sh +set -eu + +debug_enabled() { + [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ] +} + +debug_log() { + if debug_enabled; then + printf '%s\n' "DEBUG: $*" + fi +} + +debug_log_script() { + if debug_enabled; then + if (return 0 2>/dev/null); then + context="sourced" + else + context="run" + fi + debug_log "$1 ($context)" + fi +} + +debug_dump_vars() { + if debug_enabled; then + for var in "$@"; do + value="$(eval "printf '%s' \"\${$var-}\"")" + printf 'DEBUG: %s=%s\n' "$var" "$value" + done + fi +} diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index c87b0ec12..3f653e866 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -9,14 +9,12 @@ }, "shell": { "init_hook": [ - ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", - "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", - ". $SCRIPTS_DIR/android/env.sh" + "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], - "test-android": ["sh $SCRIPTS_DIR/android/test.sh"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/setup.sh"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/test.sh"] } } } diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index e7125620b..c5fd85e7f 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -9,14 +9,12 @@ }, "shell": { "init_hook": [ - ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", - "if [ -n \"${CI:-}\" ] || [ -n \"${GITHUB_ACTIONS:-}\" ]; then echo 'Android SDK env configured (details: wiki/devbox.md#devbox-android).'; fi", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", - ". $SCRIPTS_DIR/android/env.sh" + "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-android": ["sh $SCRIPTS_DIR/android/setup.sh"], - "test-android": ["sh $SCRIPTS_DIR/android/test.sh"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/setup.sh"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/test.sh"] } } } diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index f15d16f1f..f30a96e95 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -10,12 +10,11 @@ }, "shell": { "init_hook": [ - ". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh", - "if [ \"$(uname -s)\" = \"Darwin\" ]; then . $SCRIPTS_DIR/ios/env.sh; fi" + "DEVBOX_INIT_IOS=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-ios": ["sh $SCRIPTS_DIR/ios/setup.sh"], - "test-ios": ["sh $SCRIPTS_DIR/ios/test.sh"] + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/ios/setup.sh"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/ios/test.sh"] } } } diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index 57e2b9107..ac5fad0c3 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -8,9 +8,9 @@ "shfmt": "latest" }, "shell": { - "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/shared/common.sh"], + "init_hook": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh"], "scripts": { - "build": ["sh $SCRIPTS_DIR/build.sh"], + "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/build.sh"], "release": [ "npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}", "yarn install --immutable", diff --git a/wiki/devbox.md b/wiki/devbox.md index 195819538..48422e3ce 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -47,17 +47,17 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/platform-versions.json` (min/max device/runtime). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. +- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/platform-versions.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. - `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `nix/platform-versions.json`) or leave default for latest. Internally uses `scripts/ios/manager.sh`. - `devbox run reset-ios` shuts down/erases and removes all local simulator devices. - `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). -- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/platform-versions.json`) and latest (iPhone 17 @ latest runtime). +- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/platform-versions.json`) and latest (iPhone 17). - `devbox run test-ios` runs `setup-ios` first to ensure simulators exist; Detox handles booting. Use `start-ios` if you want to pre-boot. ### Common env knobs - Android: `AVD_FLAVOR` (minsdk/latest), `DETOX_AVD` (explicit AVD name), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). -- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). +- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `nix/platform-versions.json` as `PLATFORM_IOS_MIN_VERSION`/`PLATFORM_IOS_MAX_VERSION`. ### Releases diff --git a/wiki/nix.md b/wiki/nix.md index 986eff98d..c04343202 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -29,7 +29,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc 1. Edit `nix/platform-versions.json`. 2. In a devbox shell, run `refresh` to rebuild the SDK. -3. If iOS min/max changes, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. +3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. ## CI targets From afa4e5020437618f9dcf721e99165e9cacb06060 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 18:45:59 -0600 Subject: [PATCH 13/32] refactor --- devbox.json | 28 ++--- nix/platform-versions.json | 61 +++++++++-- scripts/android/{setup.sh => avd.sh} | 124 +++++++++++++++++----- scripts/android/env.sh | 8 +- scripts/android/manager.sh | 93 ----------------- scripts/android/test.sh | 29 ------ scripts/build.sh | 18 +++- scripts/entry/run.sh | 147 +++++++++++++++++++++++++++ scripts/ios/env.sh | 9 +- scripts/ios/manager.sh | 67 ------------ scripts/ios/setup.sh | 81 --------------- scripts/ios/simctl.sh | 87 +++++++++++++++- scripts/ios/test.sh | 19 ---- scripts/platform-versions.sh | 2 +- scripts/shared/common.sh | 3 + shells/android-max/devbox.json | 4 +- shells/android-min/devbox.json | 4 +- shells/ios/devbox.json | 4 +- shells/minimal/devbox.json | 2 +- wiki/devbox.md | 14 +-- wiki/nix.md | 1 + wiki/scripts.md | 49 +++------ 22 files changed, 454 insertions(+), 400 deletions(-) rename scripts/android/{setup.sh => avd.sh} (73%) mode change 100755 => 100644 delete mode 100755 scripts/android/manager.sh delete mode 100755 scripts/android/test.sh create mode 100644 scripts/entry/run.sh delete mode 100755 scripts/ios/manager.sh delete mode 100755 scripts/ios/setup.sh delete mode 100755 scripts/ios/test.sh diff --git a/devbox.json b/devbox.json index 16b3b4dac..86d585454 100644 --- a/devbox.json +++ b/devbox.json @@ -29,23 +29,23 @@ "yarn cache clean", "find $DEVBOX_PROJECT_DIR -type d -name node_modules -exec rmdir {} \\;" ], - "build": ["sh $DEVBOX_PROJECT_ROOT/scripts/build.sh"], + "build": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh build"], "format": ["treefmt"], "lint": ["treefmt --fail-on-change"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/test.sh"], - "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/test.sh"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android test"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios test"], "act-ci": [ "sh $DEVBOX_PROJECT_ROOT/scripts/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" ], - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/setup.sh"], - "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/setup.sh"], - "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], - "start-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh start"], - "start-android-minsdk": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android setup"], + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios setup"], + "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], + "start-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios start"], + "start-android-minsdk": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], "start-android-latest": [ - "AVD_FLAVOR=latest sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start" + "AVD_FLAVOR=latest sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start" ], - "start-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh start"], + "start-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], "update-apps": [ "yarn install --no-immutable", "yarn e2e install --no-immutable", @@ -58,10 +58,10 @@ "devbox update --config=shells/android-max/devbox.json", "devbox update --config=shells/ios/devbox.json" ], - "reset-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh reset"], - "reset-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh reset"], - "stop-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/android/manager.sh stop"], - "stop-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/ios/manager.sh stop"], + "reset-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android reset"], + "reset-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios reset"], + "stop-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android stop"], + "stop-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios stop"], "stop": ["devbox run stop-android", "devbox run stop-ios"], "test": ["devbox run test-android", "devbox run test-ios"] } diff --git a/nix/platform-versions.json b/nix/platform-versions.json index 87c7ac9b8..149c88e77 100644 --- a/nix/platform-versions.json +++ b/nix/platform-versions.json @@ -1,13 +1,52 @@ { - "PLATFORM_ANDROID_MIN_API": "21", - "PLATFORM_ANDROID_MAX_API": "33", - "PLATFORM_ANDROID_BUILD_TOOLS_VERSION": "30.0.3", - "PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION": "19.0", - "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG": "google_apis", - "PLATFORM_ANDROID_MIN_DEVICE": "pixel", - "PLATFORM_ANDROID_MAX_DEVICE": "medium_phone", - "PLATFORM_IOS_MIN_VERSION": "15.0", - "PLATFORM_IOS_MAX_VERSION": "26.2", - "PLATFORM_IOS_MIN_DEVICE": "iPhone 13", - "PLATFORM_IOS_MAX_DEVICE": "iPhone 17" + "defaults": { + "PLATFORM_ANDROID_MIN_API": "21", + "PLATFORM_ANDROID_MAX_API": "33", + "PLATFORM_ANDROID_BUILD_TOOLS_VERSION": "30.0.3", + "PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION": "19.0", + "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG": "google_apis", + "PLATFORM_ANDROID_MIN_DEVICE": "pixel", + "PLATFORM_ANDROID_MAX_DEVICE": "medium_phone", + "PLATFORM_IOS_MIN_VERSION": "15.0", + "PLATFORM_IOS_MAX_VERSION": "26.2", + "PLATFORM_IOS_MIN_DEVICE": "iPhone 13", + "PLATFORM_IOS_MAX_DEVICE": "iPhone 17" + }, + "vars": { + "ANDROID": [ + "ANDROID_SDK_USE_LOCAL", + "ANDROID_SDK_FLAKE_OUTPUT", + "ANDROID_TARGET_API", + "ANDROID_MIN_API", + "ANDROID_MAX_API", + "ANDROID_SYSTEM_IMAGE_TAG", + "ANDROID_BUILD_TOOLS_VERSION", + "ANDROID_CMDLINE_TOOLS_VERSION" + ], + "ANDROID_AVD": [ + "AVD_API", + "AVD_DEVICE", + "AVD_TAG", + "AVD_ABI", + "AVD_NAME", + "AVD_SECONDARY_API", + "AVD_SECONDARY_DEVICE", + "AVD_SECONDARY_TAG", + "AVD_SECONDARY_ABI", + "AVD_SECONDARY_NAME", + "EMU_HEADLESS", + "EMU_PORT", + "DETOX_AVD" + ], + "IOS": [ + "IOS_RUNTIME", + "IOS_MIN_VERSION", + "IOS_MAX_VERSION", + "IOS_DEVICE_NAMES", + "IOS_DEVELOPER_DIR", + "IOS_DOWNLOAD_RUNTIME", + "IOS_FLAVOR", + "DETOX_IOS_DEVICE" + ] + } } diff --git a/scripts/android/setup.sh b/scripts/android/avd.sh old mode 100755 new mode 100644 similarity index 73% rename from scripts/android/setup.sh rename to scripts/android/avd.sh index cdbad4f03..3ecc14401 --- a/scripts/android/setup.sh +++ b/scripts/android/avd.sh @@ -1,26 +1,15 @@ #!/usr/bin/env sh set -eu -# Creates AVDs using the Android SDK provided by devbox/flake (system images, emulator, NDK already installed). -# Run inside a devbox shell so SDK tools are available. -# Configurable via env: -# AVD_API (default 21) -# AVD_DEVICE (default "pixel") -# AVD_TAG (default "google_apis") -# AVD_ABI (preferred ABI; optional) -# AVD_NAME (override final AVD name; otherwise computed) -# Secondary AVD (created in addition to the primary): -# AVD_SECONDARY_API (default 33) -# AVD_SECONDARY_DEVICE (default "medium_phone") -# AVD_SECONDARY_TAG (default "google_apis") -# AVD_SECONDARY_ABI (preferred ABI; optional) -# AVD_SECONDARY_NAME (override final name) +# Android AVD setup + lifecycle helpers. script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$script_dir/../shared/common.sh" +fi load_platform_versions "$script_dir" -debug_log_script "scripts/android/setup.sh" +debug_log_script "scripts/android/avd.sh" detect_sdk_root() { if [ -n "${ANDROID_SDK_ROOT:-}" ]; then @@ -114,7 +103,7 @@ ${target_line}" fi } -main() { +android_setup() { TARGETS="" detected_sdk_root="$(detect_sdk_root 2>/dev/null || true)" @@ -204,14 +193,12 @@ main() { fi ifs_backup="$IFS" - IFS=' -' + IFS='\n' for target in $TARGETS; do - IFS='|' read -r api tag device preferred_abi name_override < --netdelay none --netspeed full" } -main "$@" +android_start() { + flavor="${AVD_FLAVOR:-latest}" + headless="${EMU_HEADLESS:-}" + port="${EMU_PORT:-5554}" + avd="${DETOX_AVD:-}" + + if [ -z "$avd" ]; then + if [ "$flavor" = "latest" ]; then + host_arch="$(uname -m)" + if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then + abi="arm64_v8a" + else + abi="x86_64" + fi + avd="medium_phone_API33_${abi}" + else + if uname -m | grep -qi arm; then + abi="arm64_v8a" + else + abi="x86_64" + fi + avd="pixel_API21_${abi}" + fi + fi + + android_setup + + target_serial="emulator-${port}" + if command -v adb >/dev/null 2>&1; then + adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done + fi + echo "Starting Android emulator: ${avd} (flavor ${flavor}, port ${port}, headless=${headless:-0})" + if [ -n "$headless" ]; then + headless_flag="-no-window" + else + headless_flag="" + fi + emulator -avd "$avd" ${headless_flag:+$headless_flag} -port "$port" -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -accel on -writable-system -no-snapshot-save & + adb -s "$target_serial" wait-for-device + boot_completed="" + until [ "$boot_completed" = "1" ]; do + boot_completed=$(adb -s "$target_serial" shell getprop sys.boot_completed 2>/dev/null | tr -d "\r") + sleep 5 + done + adb -s "$target_serial" shell settings put global window_animation_scale 0 + adb -s "$target_serial" shell settings put global transition_animation_scale 0 + adb -s "$target_serial" shell settings put global animator_duration_scale 0 +} + +android_stop() { + if command -v adb >/dev/null 2>&1; then + adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done + devices="$(adb devices -l 2>/dev/null | awk 'NR>1{print $1}' | tr '\n' ' ')" + if [ -n "$devices" ]; then + echo "Stopping Android emulators: $devices" + for d in $devices; do + adb -s "$d" emu kill >/dev/null 2>&1 || true + done + else + echo "No Android emulators detected via adb." + fi + else + echo "adb not found; skipping Android emulator shutdown." + fi + pkill -f "emulator@" >/dev/null 2>&1 || true + echo "Android emulators stopped (if any were running)." +} + +android_reset() { + rm -rf "$HOME/.android/avd" + rm -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub" + echo "AVDs and adb keys removed. Recreate via start-android* as needed." +} + +if [ "${RUN_MAIN:-1}" = "1" ]; then + action="${1:-}" + shift || true + case "$action" in + start) android_start "$@" ;; + stop) android_stop "$@" ;; + reset) android_reset "$@" ;; + setup) android_setup "$@" ;; + *) + echo "Usage: avd.sh {start|stop|reset|setup}" >&2 + exit 1 + ;; + esac +fi diff --git a/scripts/android/env.sh b/scripts/android/env.sh index f93fd37c9..fe93a3ee3 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -7,8 +7,10 @@ if [ -z "$project_root" ]; then project_root="$(cd "$(dirname "$0")/../.." && pwd)" fi script_dir="$project_root/scripts/android" -# shellcheck disable=SC1090 -. "$project_root/scripts/shared/common.sh" +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$project_root/scripts/shared/common.sh" +fi load_platform_versions "$script_dir" debug_log_script "scripts/android/env.sh" @@ -139,6 +141,8 @@ fi export ANDROID_SDK_ROOT ANDROID_HOME export ANDROID_BUILD_TOOLS_VERSION +ANDROID_ENV_LOADED=1 +export ANDROID_ENV_LOADED if [ -n "${ANDROID_SDK_ROOT:-}" ]; then # Prefer cmdline-tools;latest, or fall back to the highest numbered cmdline-tools folder. diff --git a/scripts/android/manager.sh b/scripts/android/manager.sh deleted file mode 100755 index f9d537d7f..000000000 --- a/scripts/android/manager.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env sh -set -eu - -action="${1:-}" -shift || true - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/env.sh" -debug_log_script "scripts/android/manager.sh" - -start_android() { - flavor="${AVD_FLAVOR:-latest}" - headless="${EMU_HEADLESS:-}" - port="${EMU_PORT:-5554}" - avd="${DETOX_AVD:-}" - - if [ -z "$avd" ]; then - if [ "$flavor" = "latest" ]; then - host_arch="$(uname -m)" - if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then - abi="arm64_v8a" - else - abi="x86_64" - fi - avd="medium_phone_API33_${abi}" - else - if uname -m | grep -qi arm; then - abi="arm64_v8a" - else - abi="x86_64" - fi - avd="pixel_API21_${abi}" - fi - fi - - sh "$SCRIPTS_DIR/android/setup.sh" - target_serial="emulator-${port}" - if command -v adb >/dev/null 2>&1; then - adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done - fi - echo "Starting Android emulator: ${avd} (flavor ${flavor}, port ${port}, headless=${headless:-0})" - if [ -n "$headless" ]; then - headless_flag="-no-window" - else - headless_flag="" - fi - emulator -avd "$avd" ${headless_flag:+$headless_flag} -port "$port" -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none -accel on -writable-system -no-snapshot-save & - adb -s "$target_serial" wait-for-device - boot_completed="" - until [ "$boot_completed" = "1" ]; do - boot_completed=$(adb -s "$target_serial" shell getprop sys.boot_completed 2>/dev/null | tr -d "\r") - sleep 5 - done - adb -s "$target_serial" shell settings put global window_animation_scale 0 - adb -s "$target_serial" shell settings put global transition_animation_scale 0 - adb -s "$target_serial" shell settings put global animator_duration_scale 0 -} - -stop_android() { - if command -v adb >/dev/null 2>&1; then - adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done - devices="$(adb devices -l 2>/dev/null | awk 'NR>1{print $1}' | tr '\n' ' ')" - if [ -n "$devices" ]; then - echo "Stopping Android emulators: $devices" - for d in $devices; do - adb -s "$d" emu kill >/dev/null 2>&1 || true - done - else - echo "No Android emulators detected via adb." - fi - else - echo "adb not found; skipping Android emulator shutdown." - fi - pkill -f "emulator@" >/dev/null 2>&1 || true - echo "Android emulators stopped (if any were running)." -} - -reset_android() { - rm -rf "$HOME/.android/avd" - rm -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub" - echo "AVDs and adb keys removed. Recreate via start-android* as needed." -} - -case "$action" in - start) start_android ;; - stop) stop_android ;; - reset) reset_android ;; - *) - echo "Usage: manager.sh {start|stop|reset}" >&2 - exit 1 - ;; - esac diff --git a/scripts/android/test.sh b/scripts/android/test.sh deleted file mode 100755 index 18098ac22..000000000 --- a/scripts/android/test.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" -load_platform_versions "$script_dir" -debug_log_script "scripts/android/test.sh" - -if [ -z "${ANDROID_MIN_API:-}" ] && [ -n "${PLATFORM_ANDROID_MIN_API:-}" ]; then - ANDROID_MIN_API="$PLATFORM_ANDROID_MIN_API" -fi -if [ -z "${ANDROID_MAX_API:-}" ] && [ -n "${PLATFORM_ANDROID_MAX_API:-}" ]; then - ANDROID_MAX_API="$PLATFORM_ANDROID_MAX_API" -fi -if [ -z "${ANDROID_SYSTEM_IMAGE_TAG:-}" ] && [ -n "${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-}" ]; then - ANDROID_SYSTEM_IMAGE_TAG="$PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" -fi -if [ -z "${ANDROID_TARGET_API:-}" ] && [ -n "${ANDROID_MAX_API:-}" ]; then - ANDROID_TARGET_API="$ANDROID_MAX_API" -fi -export ANDROID_MIN_API ANDROID_MAX_API ANDROID_SYSTEM_IMAGE_TAG ANDROID_TARGET_API - -sh "$SCRIPTS_DIR/android/setup.sh" -yarn install -yarn e2e install -yarn build -yarn e2e build:android -yarn e2e test:android diff --git a/scripts/build.sh b/scripts/build.sh index 42aa2183c..4ddd95ac9 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,10 +2,18 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/shared/common.sh" +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$script_dir/shared/common.sh" +fi debug_log_script "scripts/build.sh" -yarn install --immutable -yarn build -yarn lint +build_project() { + yarn install --immutable + yarn build + yarn lint +} + +if [ "${RUN_MAIN:-1}" = "1" ]; then + build_project "$@" +fi diff --git a/scripts/entry/run.sh b/scripts/entry/run.sh new file mode 100644 index 000000000..5a9f92e07 --- /dev/null +++ b/scripts/entry/run.sh @@ -0,0 +1,147 @@ +#!/usr/bin/env sh +set -eu + +script_dir="$(cd "$(dirname "$0")" && pwd)" +repo_root="$(cd "$script_dir/../.." && pwd)" + +# shellcheck disable=SC1090 +. "$repo_root/scripts/shared/common.sh" +debug_log_script "scripts/entry/run.sh" + +platform="${1:-}" +action="${2:-}" +shift 2 || true + +run_android() { + # shellcheck disable=SC1090 + . "$repo_root/scripts/android/env.sh" + + case "$action" in + test) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/android/avd.sh" + android_setup + yarn e2e install + yarn build + yarn e2e build:android + yarn e2e test:android + ;; + setup) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/android/avd.sh" + android_setup "$@" + ;; + start | stop | reset) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/android/avd.sh" + case "$action" in + start) android_start "$@" ;; + stop) android_stop "$@" ;; + reset) android_reset "$@" ;; + esac + ;; + *) + echo "Usage: run.sh android {test|setup|start|stop|reset} [args]" >&2 + exit 1 + ;; + esac +} + +run_ios() { + if [ "$(uname -s)" = "Darwin" ]; then + # shellcheck disable=SC1090 + . "$repo_root/scripts/ios/env.sh" + fi + + case "$action" in + test) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/ios/simctl.sh" + ios_setup + yarn e2e install + yarn e2e pods + yarn build + yarn e2e build:ios + yarn e2e test:ios + ;; + setup) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/ios/simctl.sh" + ios_setup "$@" + ;; + start | stop | reset) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/ios/simctl.sh" + case "$action" in + start) + flavor="${IOS_FLAVOR:-latest}" + if [ "$flavor" = "minsdk" ]; then + IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" + else + IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" + fi + export IOS_DEVICE_NAMES DETOX_IOS_DEVICE + ios_setup + sim_device="${DETOX_IOS_DEVICE}" + if ! xcrun simctl list devices | grep -q "${sim_device}"; then + echo "Simulator ${sim_device} not found; ensure setup-ios created it." >&2 + exit 1 + fi + echo "Starting iOS simulator: ${sim_device} (runtime ${IOS_RUNTIME:-})" + xcrun simctl boot "$sim_device" || true + if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ]; then + open -a Simulator + fi + ;; + stop) + if command -v xcrun >/dev/null 2>&1 && xcrun -f simctl >/dev/null 2>&1; then + if xcrun simctl list devices booted | grep -q "Booted"; then + echo "Shutting down booted iOS simulators..." + xcrun simctl shutdown all >/dev/null 2>&1 || true + else + echo "No booted iOS simulators detected." + fi + else + echo "simctl not available; skipping iOS shutdown." + fi + echo "iOS simulators shutdown (if any were running)." + ;; + reset) + xcrun simctl shutdown all || true + xcrun simctl erase all || true + xcrun simctl delete all || true + xcrun simctl delete unavailable || true + killall -9 com.apple.CoreSimulatorService 2>/dev/null || true + echo "Simulators reset via simctl. Recreate via start-ios." + ;; + esac + ;; + *) + echo "Usage: run.sh ios {test|setup|start|stop|reset} [args]" >&2 + exit 1 + ;; + esac +} + +case "$platform" in + android) run_android "$@" ;; + ios) run_ios "$@" ;; + build) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$repo_root/scripts/build.sh" + build_project "$@" + ;; + *) + echo "Usage: run.sh {android|ios} [args] | run.sh build" >&2 + exit 1 + ;; +esac diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 5dc2bb9e9..2c31d5ca6 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -2,8 +2,10 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$script_dir/../shared/common.sh" +fi debug_log_script "scripts/ios/env.sh" load_platform_versions "$script_dir" @@ -81,6 +83,9 @@ devbox_omit_nix_env() { devbox_omit_nix_env +IOS_ENV_LOADED=1 +export IOS_ENV_LOADED + if debug_enabled; then if [ "${IOS_ENV_DEBUG_PRINTED:-}" != "1" ]; then IOS_ENV_DEBUG_PRINTED=1 diff --git a/scripts/ios/manager.sh b/scripts/ios/manager.sh deleted file mode 100755 index b23c590d6..000000000 --- a/scripts/ios/manager.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" -load_platform_versions "$script_dir" -debug_log_script "scripts/ios/manager.sh" - -action="${1:-}" -shift || true - -start_ios() { - flavor="${IOS_FLAVOR:-latest}" - if [ "$flavor" = "minsdk" ]; then - IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" - export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE - else - IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" - export IOS_DEVICE_NAMES IOS_RUNTIME DETOX_IOS_DEVICE - fi - - sh "$SCRIPTS_DIR/ios/setup.sh" - sim_device="${DETOX_IOS_DEVICE}" - if ! xcrun simctl list devices | grep -q "${sim_device}"; then - echo "Simulator ${sim_device} not found; ensure setup-ios created it." >&2 - exit 1 - fi - echo "Starting iOS simulator: ${sim_device} (runtime ${IOS_RUNTIME})" - xcrun simctl boot "$sim_device" || true - open -a Simulator -} - -stop_ios() { - if command -v xcrun >/dev/null 2>&1 && xcrun -f simctl >/dev/null 2>&1; then - if xcrun simctl list devices booted | grep -q "Booted"; then - echo "Shutting down booted iOS simulators..." - xcrun simctl shutdown all >/dev/null 2>&1 || true - else - echo "No booted iOS simulators detected." - fi - else - echo "simctl not available; skipping iOS shutdown." - fi - echo "iOS simulators shutdown (if any were running)." -} - -reset_ios() { - xcrun simctl shutdown all || true - xcrun simctl erase all || true - xcrun simctl delete all || true - xcrun simctl delete unavailable || true - killall -9 com.apple.CoreSimulatorService 2>/dev/null || true - echo "Simulators reset via simctl. Recreate via start-ios." -} - -case "$action" in - start) start_ios ;; - stop) stop_ios ;; - reset) reset_ios ;; - *) - echo "Usage: manager.sh {start|stop|reset}" >&2 - exit 1 - ;; - esac diff --git a/scripts/ios/setup.sh b/scripts/ios/setup.sh deleted file mode 100755 index 4038398a4..000000000 --- a/scripts/ios/setup.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" -# shellcheck disable=SC1090 -. "$script_dir/simctl.sh" -load_platform_versions "$script_dir" -debug_log_script "scripts/ios/setup.sh" - -# Creates local iOS simulators for common targets. Requires Xcode command-line tools and jq. -# Env overrides: -# IOS_DEVICE_NAMES="iPhone 15,iPhone 17" (comma-separated) -# IOS_RUNTIME="26.1" (preferred runtime prefix; falls back to latest available) -# IOS_DOWNLOAD_RUNTIME=1 to attempt xcodebuild -downloadPlatform iOS when the preferred runtime is missing -# IOS_DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" to override the Xcode path; defaults to xcode-select -p or the standard Xcode.app if found - -ensure_developer_dir() { - desired="${IOS_DEVELOPER_DIR:-}" - if [ -z "$desired" ]; then - if xcode-select -p >/dev/null 2>&1; then - desired="$(xcode-select -p)" - elif [ -d /Applications/Xcode.app/Contents/Developer ]; then - desired="/Applications/Xcode.app/Contents/Developer" - fi - fi - - if [ -n "$desired" ] && [ -d "$desired" ]; then - DEVELOPER_DIR="$desired" - PATH="$DEVELOPER_DIR/usr/bin:$PATH" - export DEVELOPER_DIR PATH - return 0 - fi - - echo "Xcode developer directory not found. Install Xcode/CLI tools or set IOS_DEVELOPER_DIR to an Xcode path (e.g., /Applications/Xcode.app/Contents/Developer)." >&2 - exit 1 -} - -ensure_developer_dir - -require_tool xcrun "Missing required tool: xcrun. Install Xcode CLI tools before running (xcode-select --install or Xcode.app + xcode-select -s)." -require_tool jq - -ensure_simctl() { - if xcrun -f simctl >/dev/null 2>&1; then - return 0 - fi - cat >&2 <<'EOM' -Missing simctl. -- The standalone Command Line Tools do NOT include simctl; you need full Xcode. -- Install/locate Xcode.app, then select it: - sudo xcode-select -s /Applications/Xcode.app/Contents/Developer -- You can also set IOS_DEVELOPER_DIR to your Xcode path for this script. -EOM - exit 1 -} - -ensure_simctl - -main() { - if ! ensure_core_sim_service; then - return 1 - fi - devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" - runtime="${IOS_RUNTIME:-}" - if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then - runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" - fi - - ifs_backup="$IFS" - IFS=',' - for device in $devices_list; do - device_trimmed="$(printf '%s' "$device" | xargs)" - ensure_device "$device_trimmed" "$runtime" - done - IFS="$ifs_backup" - echo "Done. Launch via Xcode > Devices or 'xcrun simctl boot \"\"' then 'open -a Simulator'." -} - -main "$@" diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index 88121ac71..e9982e8b9 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -1,9 +1,13 @@ #!/usr/bin/env sh set -eu -if command -v debug_log_script >/dev/null 2>&1; then - debug_log_script "scripts/ios/simctl.sh" +script_dir="$(cd "$(dirname "$0")" && pwd)" +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$script_dir/../shared/common.sh" fi +load_platform_versions "$script_dir" +debug_log_script "scripts/ios/simctl.sh" ensure_core_sim_service() { status=0 @@ -131,3 +135,82 @@ ensure_device() { xcrun simctl create "$display_name" "$device_type" "$runtime_id" echo "Created ${display_name}" } + +# Creates local iOS simulators for common targets. Requires Xcode command-line tools and jq. +# Env overrides: +# IOS_DEVICE_NAMES="iPhone 15,iPhone 17" (comma-separated) +# IOS_RUNTIME="26.1" (preferred runtime prefix; falls back to latest available) +# IOS_DOWNLOAD_RUNTIME=1 to attempt xcodebuild -downloadPlatform iOS when the preferred runtime is missing +# IOS_DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" to override the Xcode path; defaults to xcode-select -p or the standard Xcode.app if found + +ensure_developer_dir() { + desired="${IOS_DEVELOPER_DIR:-}" + if [ -z "$desired" ]; then + if xcode-select -p >/dev/null 2>&1; then + desired="$(xcode-select -p)" + elif [ -d /Applications/Xcode.app/Contents/Developer ]; then + desired="/Applications/Xcode.app/Contents/Developer" + fi + fi + + if [ -n "$desired" ] && [ -d "$desired" ]; then + DEVELOPER_DIR="$desired" + PATH="$DEVELOPER_DIR/usr/bin:$PATH" + export DEVELOPER_DIR PATH + return 0 + fi + + echo "Xcode developer directory not found. Install Xcode/CLI tools or set IOS_DEVELOPER_DIR to an Xcode path (e.g., /Applications/Xcode.app/Contents/Developer)." >&2 + exit 1 +} + +ensure_simctl() { + if xcrun -f simctl >/dev/null 2>&1; then + return 0 + fi + cat >&2 <<'EOM' +Missing simctl. +- The standalone Command Line Tools do NOT include simctl; you need full Xcode. +- Install/locate Xcode.app, then select it: + sudo xcode-select -s /Applications/Xcode.app/Contents/Developer +- You can also set IOS_DEVELOPER_DIR to your Xcode path for this script. +EOM + exit 1 +} + +ios_setup() { + ensure_developer_dir + require_tool xcrun "Missing required tool: xcrun. Install Xcode CLI tools before running (xcode-select --install or Xcode.app + xcode-select -s)." + require_tool jq + ensure_simctl + + if ! ensure_core_sim_service; then + return 1 + fi + devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + runtime="${IOS_RUNTIME:-}" + if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then + runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + fi + + ifs_backup="$IFS" + IFS=',' + for device in $devices_list; do + device_trimmed="$(printf '%s' "$device" | xargs)" + ensure_device "$device_trimmed" "$runtime" + done + IFS="$ifs_backup" + echo "Done. Launch via Xcode > Devices or 'xcrun simctl boot \"\"' then 'open -a Simulator'." +} + +if [ "${RUN_MAIN:-1}" = "1" ]; then + action="${1:-}" + shift || true + case "$action" in + setup) ios_setup "$@" ;; + *) + echo "Usage: simctl.sh {setup}" >&2 + exit 1 + ;; + esac +fi diff --git a/scripts/ios/test.sh b/scripts/ios/test.sh deleted file mode 100755 index dceb72527..000000000 --- a/scripts/ios/test.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/../shared/common.sh" -debug_log_script "scripts/ios/test.sh" - -if [ "$(uname -s)" = "Darwin" ]; then - . "$SCRIPTS_DIR/ios/env.sh" -fi - -sh "$SCRIPTS_DIR/ios/setup.sh" -yarn install -yarn e2e install -yarn e2e pods -yarn build -yarn e2e build:ios -yarn e2e test:ios diff --git a/scripts/platform-versions.sh b/scripts/platform-versions.sh index 12b445608..b2a51ccae 100644 --- a/scripts/platform-versions.sh +++ b/scripts/platform-versions.sh @@ -23,7 +23,7 @@ fi if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then eval "$( - "$jq_cmd" -r 'to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" + "$jq_cmd" -r 'if has("defaults") then .defaults else . end | to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" )" if debug_enabled; then if [ "${PLATFORM_VERSIONS_DEBUG_PRINTED:-}" != "1" ]; then diff --git a/scripts/shared/common.sh b/scripts/shared/common.sh index 98cb52bff..2a2c188a4 100644 --- a/scripts/shared/common.sh +++ b/scripts/shared/common.sh @@ -58,3 +58,6 @@ if [ -f "${SCRIPTS_DIR:-}/shared/debug.sh" ]; then . "$SCRIPTS_DIR/shared/debug.sh" debug_log_script "scripts/shared/common.sh" fi + +COMMON_SH_LOADED=1 +export COMMON_SH_LOADED diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index 3f653e866..edc75ce85 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -13,8 +13,8 @@ "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/setup.sh"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/test.sh"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android setup"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android test"] } } } diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index c5fd85e7f..e7603ac28 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -13,8 +13,8 @@ "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/setup.sh"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/android/test.sh"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android setup"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android test"] } } } diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index f30a96e95..af78dbea6 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -13,8 +13,8 @@ "DEVBOX_INIT_IOS=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" ], "scripts": { - "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/ios/setup.sh"], - "test-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/ios/test.sh"] + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh ios setup"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh ios test"] } } } diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index ac5fad0c3..b26377ab9 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -10,7 +10,7 @@ "shell": { "init_hook": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh"], "scripts": { - "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/build.sh"], + "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh build"], "release": [ "npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}", "yarn install --immutable", diff --git a/wiki/devbox.md b/wiki/devbox.md index 48422e3ce..aaa7b041e 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -13,13 +13,13 @@ Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT ## Android -By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_SDK_USE_LOCAL=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_SDK_USE_LOCAL` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/setup.sh` + `scripts/android/manager.sh`). Version sources are documented in `wiki/nix.md`. +By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_SDK_USE_LOCAL=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_SDK_USE_LOCAL` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/avd.sh`). Version sources are documented in `wiki/nix.md`. ### Emulator/AVD scripts -- `devbox run start-android` launches the default “latest” AVD (API 33, Medium Phone). On arm64 hosts it uses the arm64-v8a image; on Intel it uses x86_64. Override with `AVD_FLAVOR=minsdk` to launch the API 21 Pixel AVD instead. You can also set `DETOX_AVD` to pick an exact AVD name. -- `devbox run start-android-latest` / `start-android-minsdk` explicitly launch the latest (API 33) or minsdk (API 21) AVDs. Both will create the AVD first via `scripts/android/setup.sh` if it does not exist. -- `scripts/android/setup.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. +- `devbox run start-android` launches the default “latest” AVD (API 33, Medium Phone). On arm64 hosts it uses the arm64-v8a image; on Intel it uses x86_64. Override with `AVD_FLAVOR=minsdk` to launch the API 21 Pixel AVD instead. You can also set `DETOX_AVD` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. +- `devbox run start-android-latest` / `start-android-minsdk` explicitly launch the latest (API 33) or minsdk (API 21) AVDs. Both will create the AVD first via `scripts/android/avd.sh` if it does not exist. +- `scripts/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. - `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. - `EMU_HEADLESS=1 devbox run start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. - `EMU_PORT=5554 devbox run start-android*` to set the emulator port/serial (defaults to 5554) and avoid adb conflicts. @@ -43,12 +43,12 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `devbox run setup-ios` to provision simulators and validate Xcode tooling. Full Xcode is required for `simctl` (Command Line Tools alone are not enough). Make sure Xcode command line tools are selected (`xcode-select --print-path` or `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`) and that you have agreed to the license if prompted. -> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/ios/test.sh` re-applies it before running E2E. +> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/entry/run.sh` re-applies it before running iOS E2E. ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/platform-versions.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. -- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `nix/platform-versions.json`) or leave default for latest. Internally uses `scripts/ios/manager.sh`. +- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/platform-versions.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. +- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `nix/platform-versions.json`) or leave default for latest. Internally uses `scripts/entry/run.sh ios start`. - `devbox run reset-ios` shuts down/erases and removes all local simulator devices. - `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). - Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/platform-versions.json`) and latest (iPhone 17). diff --git a/wiki/nix.md b/wiki/nix.md index c04343202..a589a5752 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -30,6 +30,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc 1. Edit `nix/platform-versions.json`. 2. In a devbox shell, run `refresh` to rebuild the SDK. 3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. +4. `nix/platform-versions.json` now has a `defaults` section (exported by `scripts/platform-versions.sh`) and a `vars` section that lists supported env knobs. ## CI targets diff --git a/wiki/scripts.md b/wiki/scripts.md index 5c9faaa5f..268e7ba9a 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -28,20 +28,12 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Loads platform defaults via `scripts/platform-versions.sh`. - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. -- `scripts/android/setup.sh` +- `scripts/android/avd.sh` - - Creates/ensures AVDs for min and max API levels. + - Creates/ensures AVDs for min and max API levels, then starts/stops/resets emulators. - Depends on `sdkmanager`, `avdmanager`, `emulator` in PATH (Devbox shell). - Uses platform defaults from `scripts/platform-versions.sh`. -- `scripts/android/manager.sh` - - - Starts/stops/resets AVDs and applies emulator defaults. - - Invokes `scripts/android/setup.sh` directly to ensure AVDs exist. - -- `scripts/android/test.sh` - - Runs setup + yarn build + Android E2E (Detox). - - Used by `devbox run test-android` and CI Android workflows. ## iOS scripts @@ -49,44 +41,31 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Workaround for Devbox macOS toolchain injection. - Removes Nix toolchain variables and re-selects system clang/Xcode. - - Sourced by devbox init hooks and re-applied in `scripts/ios/test.sh`. + - Sourced by devbox init hooks and re-applied in `scripts/entry/run.sh` for iOS tasks. - `scripts/ios/simctl.sh` - Helpers for runtime selection and simulator management. - - Used by `scripts/ios/setup.sh`. - -- `scripts/ios/setup.sh` - - Ensures Xcode tools are selected and simulators exist. - - Uses `scripts/ios/simctl.sh` to choose runtimes/devices. - -- `scripts/ios/manager.sh` - - - Boots/shuts down simulators via `simctl`. - - Uses platform defaults from `scripts/platform-versions.sh`. -- `scripts/ios/test.sh` - - Applies `scripts/ios/env.sh`, then runs setup + yarn build + iOS E2E. - - Used by `devbox run test-ios` and CI iOS workflows. ## Devbox wiring Root devbox (`devbox.json`) exposes: -- `build` -> `scripts/build.sh` -- `test-android` -> `scripts/android/test.sh` -- `test-ios` -> `scripts/ios/test.sh` -- `setup-android` -> `scripts/android/setup.sh` -- `setup-ios` -> `scripts/ios/setup.sh` -- `start-android*` -> `scripts/android/manager.sh` -- `start-ios` -> `scripts/ios/manager.sh` +- `build` -> `scripts/entry/run.sh build` +- `test-android` -> `scripts/entry/run.sh android test` +- `test-ios` -> `scripts/entry/run.sh ios test` +- `setup-android` -> `scripts/entry/run.sh android setup` +- `setup-ios` -> `scripts/entry/run.sh ios setup` +- `start-android*` -> `scripts/entry/run.sh android start` (uses `scripts/android/avd.sh`) +- `start-ios` -> `scripts/entry/run.sh ios start` Slim CI shells: -- `shells/minimal/devbox.json` -> `scripts/build.sh` -- `shells/android-min/devbox.json` -> `scripts/android/test.sh` -- `shells/android-max/devbox.json` -> `scripts/android/test.sh` -- `shells/ios/devbox.json` -> `scripts/ios/test.sh` +- `shells/minimal/devbox.json` -> `scripts/entry/run.sh build` +- `shells/android-min/devbox.json` -> `scripts/entry/run.sh android test` +- `shells/android-max/devbox.json` -> `scripts/entry/run.sh android test` +- `shells/ios/devbox.json` -> `scripts/entry/run.sh ios test` See `wiki/devbox.md` for usage and `wiki/nix.md` for platform version sources. From d84cebcb9d64b50ca836e74834ca69ce911dc3c3 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 19:24:41 -0600 Subject: [PATCH 14/32] cleanups --- devbox.json | 36 ++-- nix/flake.nix | 5 +- scripts/act-ci.sh | 50 ------ scripts/android/avd.sh | 168 +++++++++++------- scripts/android/env.sh | 51 +++--- scripts/android/run.sh | 57 ++++++ scripts/build.sh | 19 -- scripts/devbox/init.sh | 25 --- .../env-defaults.json | 6 +- scripts/env-defaults.sh | 91 ++++++++++ scripts/ios/env.sh | 11 -- scripts/{entry => ios}/run.sh | 79 ++------ scripts/ios/simctl.sh | 1 - scripts/platform-versions.sh | 49 ----- scripts/run.sh | 106 +++++++++++ scripts/shared/common.sh | 18 +- shells/android-max/devbox.json | 6 +- shells/android-min/devbox.json | 6 +- shells/ios/devbox.json | 6 +- shells/minimal/devbox.json | 4 +- wiki/devbox.md | 22 +-- wiki/nix.md | 14 +- wiki/scripts.md | 39 ++-- 23 files changed, 476 insertions(+), 393 deletions(-) delete mode 100755 scripts/act-ci.sh create mode 100644 scripts/android/run.sh delete mode 100755 scripts/build.sh delete mode 100644 scripts/devbox/init.sh rename nix/platform-versions.json => scripts/env-defaults.json (89%) create mode 100644 scripts/env-defaults.sh rename scripts/{entry => ios}/run.sh (64%) delete mode 100644 scripts/platform-versions.sh create mode 100644 scripts/run.sh diff --git a/devbox.json b/devbox.json index 86d585454..0e0731efa 100644 --- a/devbox.json +++ b/devbox.json @@ -19,7 +19,7 @@ "shell": { "init_hook": [ "echo 'Welcome to analytics-react-native devbox!' > /dev/null", - "DEVBOX_INIT_ANDROID=1 DEVBOX_INIT_IOS=1 sh $DEVBOX_PROJECT_ROOT/scripts/devbox/init.sh" + "DEVBOX_INIT_ANDROID=1 DEVBOX_INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/env-defaults.sh" ], "scripts": { "clean": [ @@ -29,23 +29,23 @@ "yarn cache clean", "find $DEVBOX_PROJECT_DIR -type d -name node_modules -exec rmdir {} \\;" ], - "build": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh build"], + "build": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh build"], "format": ["treefmt"], "lint": ["treefmt --fail-on-change"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android test"], - "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios test"], - "act-ci": [ - "sh $DEVBOX_PROJECT_ROOT/scripts/act-ci.sh --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" + "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android test"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios test"], + "act": [ + "sh $DEVBOX_PROJECT_ROOT/scripts/run.sh act ci-fast --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" ], - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android setup"], - "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios setup"], - "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], - "start-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios start"], - "start-android-minsdk": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], - "start-android-latest": [ - "AVD_FLAVOR=latest sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start" + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android setup"], + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios setup"], + "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android start"], + "start-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios start"], + "start-android-min": ["TARGET_SDK=min sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android start"], + "start-android-max": [ + "TARGET_SDK=max sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android start" ], - "start-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android start"], + "start-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android start"], "update-apps": [ "yarn install --no-immutable", "yarn e2e install --no-immutable", @@ -58,10 +58,10 @@ "devbox update --config=shells/android-max/devbox.json", "devbox update --config=shells/ios/devbox.json" ], - "reset-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android reset"], - "reset-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios reset"], - "stop-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh android stop"], - "stop-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/entry/run.sh ios stop"], + "reset-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android reset"], + "reset-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios reset"], + "stop-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android stop"], + "stop-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios stop"], "stop": ["devbox run stop-android", "devbox run stop-ios"], "test": ["devbox run test-android", "devbox run test-ios"] } diff --git a/nix/flake.nix b/nix/flake.nix index 7a515a454..0b955cf17 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -13,10 +13,11 @@ "aarch64-darwin" ]; - versionData = builtins.fromJSON (builtins.readFile ./platform-versions.json); + versionData = builtins.fromJSON (builtins.readFile ../scripts/env-defaults.json); + defaultsData = if builtins.hasAttr "defaults" versionData then versionData.defaults else versionData; getVar = name: default: - if builtins.hasAttr name versionData then toString (builtins.getAttr name versionData) else default; + if builtins.hasAttr name defaultsData then toString (builtins.getAttr name defaultsData) else default; androidSdkConfig = { platformVersions = [ diff --git a/scripts/act-ci.sh b/scripts/act-ci.sh deleted file mode 100755 index 55a20d38f..000000000 --- a/scripts/act-ci.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env sh -set -eu - -# Run GitHub Actions workflows locally via act. -# Usage: scripts/act-ci.sh [--job JOB] [--platform ubuntu-latest=IMAGE] - -script_dir="$(cd "$(dirname "$0")" && pwd)" -# shellcheck disable=SC1090 -. "$script_dir/shared/common.sh" -debug_log_script "scripts/act-ci.sh" - -JOB="" -PLATFORMS="" - -host_arch="$(uname -m)" -if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then - PLATFORMS="ubuntu-24.04-arm=ghcr.io/catthehacker/ubuntu:act-24.04" -else - PLATFORMS="ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04" -fi -PLATFORMS="$PLATFORMS ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" - -while [ $# -gt 0 ]; do - case "$1" in - -j | --job) - JOB="$2" - shift 2 - ;; - -p | --platform) - PLATFORMS="$PLATFORMS $2" - shift 2 - ;; - *) - echo "Unknown option: $1" >&2 - exit 1 - ;; - esac - done - -set -- act --pull=false -for platform in $PLATFORMS; do - set -- "$@" --platform "$platform" -done -set -- "$@" --input ACT=true -if [ -n "$JOB" ]; then - set -- "$@" --job "$JOB" -fi - -printf 'Running: %s\n' "$*" -exec "$@" diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 3ecc14401..23c4f1276 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -8,7 +8,6 @@ if [ -z "${COMMON_SH_LOADED:-}" ]; then # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" fi -load_platform_versions "$script_dir" debug_log_script "scripts/android/avd.sh" detect_sdk_root() { @@ -40,6 +39,31 @@ avd_exists() { avdmanager list avd | grep -q "Name: ${name}" } +resolve_device() { + desired="$1" + if [ -z "$desired" ]; then + return 1 + fi + if avdmanager list device | grep -qi "Name: ${desired}$"; then + printf '%s\n' "$desired" + return 0 + fi + if avdmanager list device | grep -qi "Name: ${desired}"; then + printf '%s\n' "$desired" + return 0 + fi + if avdmanager list device | grep -qi "Name: pixel"; then + printf '%s\n' "pixel" + return 0 + fi + fallback="$(avdmanager list device | awk -F': ' '/Name:/{print $2; exit}')" + if [ -n "$fallback" ]; then + printf '%s\n' "$fallback" + return 0 + fi + return 1 +} + pick_image() { api="$1" tag="$2" @@ -129,63 +153,46 @@ android_setup() { platform_max_device="${PLATFORM_ANDROID_MAX_DEVICE:-medium_phone}" platform_image_tag="${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" - primary_api="${AVD_API:-${ANDROID_TARGET_API:-${ANDROID_MAX_API:-${platform_max_api:-${ANDROID_MIN_API:-$platform_min_api}}}}}" - primary_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" + target_sdk="${TARGET_SDK:-max}" + case "$target_sdk" in + min) + target_api="$platform_min_api" + target_device="$platform_min_device" + ;; + max) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + *) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + esac + + target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" + target_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" if [ -n "${AVD_DEVICE:-}" ]; then - primary_device="$AVD_DEVICE" - elif [ -n "$primary_api" ] && [ "$primary_api" = "$platform_min_api" ]; then - primary_device="$platform_min_device" - elif [ -n "$primary_api" ] && [ "$primary_api" = "$platform_max_api" ]; then - primary_device="$platform_max_device" - else - primary_device="pixel" + target_device="$AVD_DEVICE" fi - primary_preferred_abi="${AVD_ABI:-}" - - if debug_enabled; then - debug_log "primary_api=${primary_api} primary_device=${primary_device} primary_tag=${primary_tag} primary_preferred_abi=${primary_preferred_abi:-auto}" + resolved_device="$(resolve_device "$target_device" || true)" + if [ -n "$resolved_device" ]; then + target_device="$resolved_device" fi - - secondary_api="${AVD_SECONDARY_API:-${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}}" - secondary_tag="${AVD_SECONDARY_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}}" - secondary_device="${AVD_SECONDARY_DEVICE:-medium_phone}" - secondary_preferred_abi="${AVD_SECONDARY_ABI:-}" + target_preferred_abi="${AVD_ABI:-}" if debug_enabled; then - debug_log "secondary_api=${secondary_api} secondary_device=${secondary_device} secondary_tag=${secondary_tag} secondary_preferred_abi=${secondary_preferred_abi:-auto}" - fi - - primary_required=0 - if [ -n "${AVD_API:-}" ] || [ -n "${AVD_TAG:-}" ] || [ -n "${AVD_DEVICE:-}" ] || [ -n "${AVD_ABI:-}" ] || [ -n "${AVD_NAME:-}" ]; then - primary_required=1 + debug_log "target_sdk=${target_sdk} target_api=${target_api} target_device=${target_device} target_tag=${target_tag} target_preferred_abi=${target_preferred_abi:-auto}" fi - secondary_required=0 - if [ -n "${AVD_SECONDARY_API:-}" ] || [ -n "${AVD_SECONDARY_TAG:-}" ] || [ -n "${AVD_SECONDARY_DEVICE:-}" ] || [ -n "${AVD_SECONDARY_ABI:-}" ] || [ -n "${AVD_SECONDARY_NAME:-}" ]; then - secondary_required=1 - fi - - primary_dir="$ANDROID_SDK_ROOT/system-images/android-${primary_api}/${primary_tag}" - if [ -d "$primary_dir" ]; then - add_target "${primary_api}|${primary_tag}|${primary_device}|${primary_preferred_abi}|${AVD_NAME:-}" - elif [ "$primary_required" = "1" ]; then - echo "Expected API ${primary_api} system image (${primary_tag}) not found under ${primary_dir}." >&2 + target_dir="$ANDROID_SDK_ROOT/system-images/android-${target_api}/${target_tag}" + if [ -d "$target_dir" ]; then + add_target "${target_api}|${target_tag}|${target_device}|${target_preferred_abi}|${AVD_NAME:-}" + else + echo "Expected API ${target_api} system image (${target_tag}) not found under ${target_dir}." >&2 echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 exit 1 fi - secondary_dir="$ANDROID_SDK_ROOT/system-images/android-${secondary_api}/${secondary_tag}" - if [ -n "$secondary_api" ] && [ "$secondary_api" != "$primary_api" ]; then - if [ -d "$secondary_dir" ]; then - add_target "${secondary_api}|${secondary_tag}|${secondary_device}|${secondary_preferred_abi}|${AVD_SECONDARY_NAME:-}" - elif [ "$secondary_required" = "1" ]; then - echo "Expected API ${secondary_api} system image (${secondary_tag}) not found under ${secondary_dir}." >&2 - echo "Re-enter the devbox shell (flake should provide images) or rebuild Devbox to fetch them." >&2 - exit 1 - elif [ -d "$primary_dir" ]; then - echo "Warning: API ${secondary_api} system image (${secondary_tag}) not found; continuing with API ${primary_api} only." >&2 - fi - fi if [ -z "$TARGETS" ]; then echo "No compatible Android system images found under ${ANDROID_SDK_ROOT}/system-images for configured APIs." >&2 @@ -255,37 +262,68 @@ TARGET_EOF } android_start() { - flavor="${AVD_FLAVOR:-latest}" + target_sdk="${TARGET_SDK:-max}" headless="${EMU_HEADLESS:-}" port="${EMU_PORT:-5554}" avd="${DETOX_AVD:-}" + android_setup + + if [ -z "$avd" ] && [ -n "${AVD_NAME:-}" ]; then + avd="$AVD_NAME" + fi + if [ -z "$avd" ]; then - if [ "$flavor" = "latest" ]; then - host_arch="$(uname -m)" - if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then - abi="arm64_v8a" - else - abi="x86_64" - fi - avd="medium_phone_API33_${abi}" - else - if uname -m | grep -qi arm; then - abi="arm64_v8a" - else - abi="x86_64" - fi - avd="pixel_API21_${abi}" + platform_min_api="${PLATFORM_ANDROID_MIN_API:-21}" + platform_max_api="${PLATFORM_ANDROID_MAX_API:-33}" + platform_min_device="${PLATFORM_ANDROID_MIN_DEVICE:-pixel}" + platform_max_device="${PLATFORM_ANDROID_MAX_DEVICE:-medium_phone}" + platform_image_tag="${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" + + case "$target_sdk" in + min) + target_api="$platform_min_api" + target_device="$platform_min_device" + ;; + max) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + *) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + esac + + target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" + target_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" + if [ -n "${AVD_DEVICE:-}" ]; then + target_device="$AVD_DEVICE" + fi + resolved_device="$(resolve_device "$target_device" || true)" + if [ -n "$resolved_device" ]; then + target_device="$resolved_device" + fi + target_preferred_abi="${AVD_ABI:-}" + + api_image="$(pick_image "$target_api" "$target_tag" "$target_preferred_abi" 2>/dev/null || true)" + if [ -n "$api_image" ]; then + abi="${api_image##*;}" + abi_safe="$(printf '%s' "$abi" | tr '-' '_')" + avd="$(printf '%s_API%s_%s' "$target_device" "$target_api" "$abi_safe")" fi fi - android_setup + if [ -z "$avd" ]; then + echo "No AVD resolved; set DETOX_AVD or AVD_NAME explicitly." >&2 + exit 1 + fi target_serial="emulator-${port}" if command -v adb >/dev/null 2>&1; then adb devices | awk 'NR>1 && $2=="offline" {print $1}' | while read -r d; do adb -s "$d" emu kill >/dev/null 2>&1 || true; done fi - echo "Starting Android emulator: ${avd} (flavor ${flavor}, port ${port}, headless=${headless:-0})" + echo "Starting Android emulator: ${avd} (target ${target_sdk}, port ${port}, headless=${headless:-0})" if [ -n "$headless" ]; then headless_flag="-no-window" else diff --git a/scripts/android/env.sh b/scripts/android/env.sh index fe93a3ee3..366cd9acd 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -11,23 +11,8 @@ if [ -z "${COMMON_SH_LOADED:-}" ]; then # shellcheck disable=SC1090 . "$project_root/scripts/shared/common.sh" fi -load_platform_versions "$script_dir" debug_log_script "scripts/android/env.sh" -if [ -z "${PLATFORM_ANDROID_MIN_API:-}" ]; then - if ! command -v jq >/dev/null 2>&1; then - if [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then - PATH="$DEVBOX_PACKAGES_DIR/bin:$PATH" - fi - fi - project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" - if [ -z "$project_root" ]; then - project_root="$(cd "$script_dir/../.." && pwd)" - fi - # shellcheck disable=SC1090 - . "$project_root/scripts/platform-versions.sh" -fi - if [ -z "${ANDROID_MIN_API:-}" ] && [ -n "${PLATFORM_ANDROID_MIN_API:-}" ]; then ANDROID_MIN_API="$PLATFORM_ANDROID_MIN_API" fi @@ -191,13 +176,20 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO android_target_api="${AVD_API:-${ANDROID_TARGET_API:-}}" android_target_source="" if [ -z "$android_target_api" ]; then - if [ -n "$android_max_api" ]; then - android_target_api="$android_max_api" - android_target_source="max" - elif [ -n "$android_min_api" ]; then - android_target_api="$android_min_api" - android_target_source="min" - fi + case "${TARGET_SDK:-max}" in + min) + android_target_api="$android_min_api" + android_target_source="min" + ;; + max) + android_target_api="$android_max_api" + android_target_source="max" + ;; + *) + android_target_api="$android_max_api" + android_target_source="max" + ;; + esac elif [ -n "${AVD_API:-}" ]; then android_target_source="avd" elif [ -n "${ANDROID_TARGET_API:-}" ]; then @@ -206,10 +198,16 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO android_target_device="${AVD_DEVICE:-}" if [ -z "$android_target_device" ]; then - if [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_min_api" ]; then - android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" - elif [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_max_api" ]; then - android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" + case "${TARGET_SDK:-max}" in + min) android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" ;; + max) android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" ;; + esac + if [ -z "$android_target_device" ]; then + if [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_min_api" ]; then + android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" + elif [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_max_api" ]; then + android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" + fi fi fi @@ -256,6 +254,7 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO ANDROID_HOME_MAX \ ANDROID_MIN_API \ ANDROID_MAX_API \ + TARGET_SDK \ ANDROID_TARGET_API \ ANDROID_SYSTEM_IMAGE_TAG \ ANDROID_BUILD_TOOLS_VERSION \ diff --git a/scripts/android/run.sh b/scripts/android/run.sh new file mode 100644 index 000000000..cec005324 --- /dev/null +++ b/scripts/android/run.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env sh +set -eu + +script_dir="$(cd "$(dirname "$0")" && pwd)" + +if [ -z "${COMMON_SH_LOADED:-}" ]; then + # shellcheck disable=SC1090 + . "$script_dir/../shared/common.sh" +fi + +scripts_root="${SCRIPTS_DIR:-$(cd "$script_dir/.." && pwd)}" +debug_log_script "scripts/android/run.sh" + +android_run() { + action="${1:-}" + shift 1 || true + + # shellcheck disable=SC1090 + . "$scripts_root/android/env.sh" + + case "$action" in + test) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$scripts_root/android/avd.sh" + android_setup + yarn e2e install + yarn build + yarn e2e build:android + yarn e2e test:android + ;; + setup) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$scripts_root/android/avd.sh" + android_setup "$@" + ;; + start | stop | reset) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$scripts_root/android/avd.sh" + case "$action" in + start) android_start "$@" ;; + stop) android_stop "$@" ;; + reset) android_reset "$@" ;; + esac + ;; + *) + echo "Usage: run.sh android {test|setup|start|stop|reset} [args]" >&2 + exit 1 + ;; + esac +} + +if [ "${RUN_MAIN:-1}" = "1" ]; then + android_run "$@" +fi diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index 4ddd95ac9..000000000 --- a/scripts/build.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${COMMON_SH_LOADED:-}" ]; then - # shellcheck disable=SC1090 - . "$script_dir/shared/common.sh" -fi -debug_log_script "scripts/build.sh" - -build_project() { - yarn install --immutable - yarn build - yarn lint -} - -if [ "${RUN_MAIN:-1}" = "1" ]; then - build_project "$@" -fi diff --git a/scripts/devbox/init.sh b/scripts/devbox/init.sh deleted file mode 100644 index 4fd673eae..000000000 --- a/scripts/devbox/init.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env sh -set -eu - -script_dir="$(cd "$(dirname "$0")" && pwd)" -repo_root="$(cd "$script_dir/../.." && pwd)" - -PROJECT_ROOT="$repo_root" -SCRIPTS_DIR="$repo_root/scripts" -export PROJECT_ROOT SCRIPTS_DIR - -# shellcheck disable=SC1090 -. "$repo_root/scripts/shared/common.sh" - -if [ "${DEVBOX_INIT_IOS:-}" = "1" ] && [ "$(uname -s)" = "Darwin" ]; then - # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/env.sh" -fi - -if [ "${DEVBOX_INIT_ANDROID:-}" = "1" ]; then - # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/env.sh" - if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then - echo "Android SDK env configured (details: wiki/devbox.md#devbox-android)." - fi -fi diff --git a/nix/platform-versions.json b/scripts/env-defaults.json similarity index 89% rename from nix/platform-versions.json rename to scripts/env-defaults.json index 149c88e77..ed6738c7c 100644 --- a/nix/platform-versions.json +++ b/scripts/env-defaults.json @@ -16,6 +16,7 @@ "ANDROID": [ "ANDROID_SDK_USE_LOCAL", "ANDROID_SDK_FLAKE_OUTPUT", + "TARGET_SDK", "ANDROID_TARGET_API", "ANDROID_MIN_API", "ANDROID_MAX_API", @@ -29,11 +30,6 @@ "AVD_TAG", "AVD_ABI", "AVD_NAME", - "AVD_SECONDARY_API", - "AVD_SECONDARY_DEVICE", - "AVD_SECONDARY_TAG", - "AVD_SECONDARY_ABI", - "AVD_SECONDARY_NAME", "EMU_HEADLESS", "EMU_PORT", "DETOX_AVD" diff --git a/scripts/env-defaults.sh b/scripts/env-defaults.sh new file mode 100644 index 000000000..a8ffdf36b --- /dev/null +++ b/scripts/env-defaults.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env sh +# Load shared platform version defaults from JSON for a single source of truth. + +if [ -n "${ENV_DEFAULTS_LOADING:-}" ] || [ "${ENV_DEFAULTS_LOADED:-}" = "1" ]; then + return 0 2>/dev/null || exit 0 +fi + +ENV_DEFAULTS_LOADING=1 +export ENV_DEFAULTS_LOADING + +script_dir="$(cd "$(dirname "$0")" && pwd)" +repo_root="$(cd "$script_dir/.." && pwd)" +versions_json="${ENV_DEFAULTS_JSON:-${PLATFORM_VERSIONS_JSON:-$repo_root/scripts/env-defaults.json}}" + +if ! command -v debug_log_script >/dev/null 2>&1; then + if [ -f "$script_dir/shared/debug.sh" ]; then + # shellcheck disable=SC1090 + . "$script_dir/shared/debug.sh" + fi +fi + +debug_log_script "scripts/env-defaults.sh" + +jq_cmd="" +if command -v jq >/dev/null 2>&1; then + jq_cmd="jq" +elif [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then + jq_cmd="$DEVBOX_PACKAGES_DIR/bin/jq" +fi + +if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then + tab="$(printf '\t')" + while IFS="$tab" read -r key value; do + if [ -z "$key" ]; then + continue + fi + current="$(eval "printf '%s' \"\${$key-}\"")" + if [ -z "$current" ]; then + eval "$key=\"\$value\"" + export "$key" + fi + done </dev/null 2>&1; then - if [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then - PATH="$DEVBOX_PACKAGES_DIR/bin:$PATH" - fi - fi - # shellcheck disable=SC1090 - . "$repo_root/scripts/platform-versions.sh" - fi - ios_min_version="${IOS_MIN_VERSION:-${PLATFORM_IOS_MIN_VERSION:-}}" ios_max_version="${IOS_MAX_VERSION:-${PLATFORM_IOS_MAX_VERSION:-}}" ios_runtime="${IOS_RUNTIME:-}" diff --git a/scripts/entry/run.sh b/scripts/ios/run.sh similarity index 64% rename from scripts/entry/run.sh rename to scripts/ios/run.sh index 5a9f92e07..3ea6ede94 100644 --- a/scripts/entry/run.sh +++ b/scripts/ios/run.sh @@ -2,65 +2,29 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -repo_root="$(cd "$script_dir/../.." && pwd)" -# shellcheck disable=SC1090 -. "$repo_root/scripts/shared/common.sh" -debug_log_script "scripts/entry/run.sh" - -platform="${1:-}" -action="${2:-}" -shift 2 || true - -run_android() { +if [ -z "${COMMON_SH_LOADED:-}" ]; then # shellcheck disable=SC1090 - . "$repo_root/scripts/android/env.sh" + . "$script_dir/../shared/common.sh" +fi - case "$action" in - test) - RUN_MAIN=0 - # shellcheck disable=SC1090 - . "$repo_root/scripts/android/avd.sh" - android_setup - yarn e2e install - yarn build - yarn e2e build:android - yarn e2e test:android - ;; - setup) - RUN_MAIN=0 - # shellcheck disable=SC1090 - . "$repo_root/scripts/android/avd.sh" - android_setup "$@" - ;; - start | stop | reset) - RUN_MAIN=0 - # shellcheck disable=SC1090 - . "$repo_root/scripts/android/avd.sh" - case "$action" in - start) android_start "$@" ;; - stop) android_stop "$@" ;; - reset) android_reset "$@" ;; - esac - ;; - *) - echo "Usage: run.sh android {test|setup|start|stop|reset} [args]" >&2 - exit 1 - ;; - esac -} +scripts_root="${SCRIPTS_DIR:-$(cd "$script_dir/.." && pwd)}" +debug_log_script "scripts/ios/run.sh" + +ios_run() { + action="${1:-}" + shift 1 || true -run_ios() { if [ "$(uname -s)" = "Darwin" ]; then # shellcheck disable=SC1090 - . "$repo_root/scripts/ios/env.sh" + . "$scripts_root/ios/env.sh" fi case "$action" in test) RUN_MAIN=0 # shellcheck disable=SC1090 - . "$repo_root/scripts/ios/simctl.sh" + . "$scripts_root/ios/simctl.sh" ios_setup yarn e2e install yarn e2e pods @@ -71,13 +35,13 @@ run_ios() { setup) RUN_MAIN=0 # shellcheck disable=SC1090 - . "$repo_root/scripts/ios/simctl.sh" + . "$scripts_root/ios/simctl.sh" ios_setup "$@" ;; start | stop | reset) RUN_MAIN=0 # shellcheck disable=SC1090 - . "$repo_root/scripts/ios/simctl.sh" + . "$scripts_root/ios/simctl.sh" case "$action" in start) flavor="${IOS_FLAVOR:-latest}" @@ -131,17 +95,6 @@ run_ios() { esac } -case "$platform" in - android) run_android "$@" ;; - ios) run_ios "$@" ;; - build) - RUN_MAIN=0 - # shellcheck disable=SC1090 - . "$repo_root/scripts/build.sh" - build_project "$@" - ;; - *) - echo "Usage: run.sh {android|ios} [args] | run.sh build" >&2 - exit 1 - ;; -esac +if [ "${RUN_MAIN:-1}" = "1" ]; then + ios_run "$@" +fi diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index e9982e8b9..b650db369 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -6,7 +6,6 @@ if [ -z "${COMMON_SH_LOADED:-}" ]; then # shellcheck disable=SC1090 . "$script_dir/../shared/common.sh" fi -load_platform_versions "$script_dir" debug_log_script "scripts/ios/simctl.sh" ensure_core_sim_service() { diff --git a/scripts/platform-versions.sh b/scripts/platform-versions.sh deleted file mode 100644 index b2a51ccae..000000000 --- a/scripts/platform-versions.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env sh -# Load shared platform version defaults from JSON for a single source of truth. - -script_dir="$(cd "$(dirname "$0")" && pwd)" -repo_root="$(cd "$script_dir/.." && pwd)" -versions_json="${PLATFORM_VERSIONS_JSON:-$repo_root/nix/platform-versions.json}" - -if ! command -v debug_log_script >/dev/null 2>&1; then - if [ -f "$script_dir/shared/debug.sh" ]; then - # shellcheck disable=SC1090 - . "$script_dir/shared/debug.sh" - fi -fi - -debug_log_script "scripts/platform-versions.sh" - -jq_cmd="" -if command -v jq >/dev/null 2>&1; then - jq_cmd="jq" -elif [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then - jq_cmd="$DEVBOX_PACKAGES_DIR/bin/jq" -fi - -if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then - eval "$( - "$jq_cmd" -r 'if has("defaults") then .defaults else . end | to_entries[] | "\(.key)=\(.value|@sh)"' "$versions_json" - )" - if debug_enabled; then - if [ "${PLATFORM_VERSIONS_DEBUG_PRINTED:-}" != "1" ]; then - PLATFORM_VERSIONS_DEBUG_PRINTED=1 - export PLATFORM_VERSIONS_DEBUG_PRINTED - for key in \ - PLATFORM_ANDROID_MIN_API \ - PLATFORM_ANDROID_MAX_API \ - PLATFORM_ANDROID_BUILD_TOOLS_VERSION \ - PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION \ - PLATFORM_ANDROID_SYSTEM_IMAGE_TAG \ - PLATFORM_ANDROID_MIN_DEVICE \ - PLATFORM_ANDROID_MAX_DEVICE \ - PLATFORM_IOS_MIN_VERSION \ - PLATFORM_IOS_MAX_VERSION \ - PLATFORM_IOS_MIN_DEVICE \ - PLATFORM_IOS_MAX_DEVICE; do - value="$(eval "printf '%s' \"\${$key-}\"")" - printf 'DEBUG: %s=%s\n' "$key" "$value" - done - fi - fi -fi diff --git a/scripts/run.sh b/scripts/run.sh new file mode 100644 index 000000000..7e09e97df --- /dev/null +++ b/scripts/run.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env sh +set -eu + +script_dir="$(cd "$(dirname "$0")" && pwd)" + +# shellcheck disable=SC1090 +. "$script_dir/shared/common.sh" +debug_log_script "scripts/run.sh" + +scripts_root="${SCRIPTS_DIR:-$script_dir}" + +platform="${1:-}" +action="${2:-}" +shift 2 || true + +run_build() { + yarn install --immutable + yarn build + yarn lint +} + +run_act() { + workflow="${1:-}" + if [ -n "$workflow" ] && [ "${workflow#-}" = "$workflow" ]; then + shift 1 + case "$workflow" in + *.yml | *.yaml) + workflow_path="$workflow" + ;; + *) + workflow_path=".github/workflows/${workflow}.yml" + ;; + esac + else + workflow="" + workflow_path="" + fi + + JOB="" + PLATFORMS="" + + host_arch="$(uname -m)" + if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then + PLATFORMS="ubuntu-24.04-arm=ghcr.io/catthehacker/ubuntu:act-24.04" + else + PLATFORMS="ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04" + fi + PLATFORMS="$PLATFORMS ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" + + while [ $# -gt 0 ]; do + case "$1" in + -j | --job) + JOB="$2" + shift 2 + ;; + -p | --platform) + PLATFORMS="$PLATFORMS $2" + shift 2 + ;; + *) + echo "Unknown option: $1" >&2 + exit 1 + ;; + esac + done + + set -- act --pull=false + if [ -n "$workflow_path" ]; then + set -- "$@" -W "$workflow_path" + fi + for platform in $PLATFORMS; do + set -- "$@" --platform "$platform" + done + set -- "$@" --input ACT=true + if [ -n "$JOB" ]; then + set -- "$@" --job "$JOB" + fi + + printf 'Running: %s\n' "$*" + exec "$@" +} + +case "$platform" in + android) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$scripts_root/android/run.sh" + android_run "$action" "$@" + ;; + ios) + RUN_MAIN=0 + # shellcheck disable=SC1090 + . "$scripts_root/ios/run.sh" + ios_run "$action" "$@" + ;; + build) + run_build "$@" + ;; + act) + run_act "$@" + ;; + *) + echo "Usage: run.sh {android|ios} [args] | run.sh build | run.sh act [args]" >&2 + exit 1 + ;; +esac diff --git a/scripts/shared/common.sh b/scripts/shared/common.sh index 2a2c188a4..7b9c08065 100644 --- a/scripts/shared/common.sh +++ b/scripts/shared/common.sh @@ -26,9 +26,9 @@ ensure_project_root() { if [ -n "$git_root" ]; then PROJECT_ROOT="$git_root" - elif [ -f "$base_dir/../shared/common.sh" ] && [ -f "$base_dir/../build.sh" ]; then + elif [ -f "$base_dir/../shared/common.sh" ] && [ -f "$base_dir/../run.sh" ]; then PROJECT_ROOT="$(cd "$base_dir/.." && pwd)" - elif [ -f "$base_dir/shared/common.sh" ] && [ -f "$base_dir/build.sh" ]; then + elif [ -f "$base_dir/shared/common.sh" ] && [ -f "$base_dir/run.sh" ]; then PROJECT_ROOT="$(cd "$base_dir" && pwd)" fi @@ -37,15 +37,6 @@ ensure_project_root() { fi } -load_platform_versions() { - base_dir="$1" - platform_versions="${base_dir%/}/../platform-versions.sh" - if [ -f "$platform_versions" ]; then - # shellcheck disable=SC1090 - . "$platform_versions" - fi -} - ensure_project_root "${SCRIPT_DIR:-${script_dir:-${PWD}}}" if [ -z "${SCRIPTS_DIR:-}" ] && [ -n "${PROJECT_ROOT:-}" ]; then @@ -59,5 +50,10 @@ if [ -f "${SCRIPTS_DIR:-}/shared/debug.sh" ]; then debug_log_script "scripts/shared/common.sh" fi +if [ -f "${SCRIPTS_DIR:-}/env-defaults.sh" ] && [ "${ENV_DEFAULTS_LOADED:-}" != "1" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/env-defaults.sh" +fi + COMMON_SH_LOADED=1 export COMMON_SH_LOADED diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index edc75ce85..fcdb3658f 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -10,11 +10,11 @@ "shell": { "init_hook": [ "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", - "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" + "DEVBOX_INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" ], "scripts": { - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android setup"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android test"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android test"] } } } diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index e7603ac28..23e7c015f 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -10,11 +10,11 @@ "shell": { "init_hook": [ "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", - "DEVBOX_INIT_ANDROID=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" + "DEVBOX_INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" ], "scripts": { - "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android setup"], - "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh android test"] + "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], + "test-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android test"] } } } diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index af78dbea6..d0715ab8d 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -10,11 +10,11 @@ }, "shell": { "init_hook": [ - "DEVBOX_INIT_IOS=1 sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh" + "DEVBOX_INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" ], "scripts": { - "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh ios setup"], - "test-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh ios test"] + "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh ios setup"], + "test-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh ios test"] } } } diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index b26377ab9..c836ecc42 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -8,9 +8,9 @@ "shfmt": "latest" }, "shell": { - "init_hook": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/devbox/init.sh"], + "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh"], "scripts": { - "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/entry/run.sh build"], + "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh build"], "release": [ "npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}", "yarn install --immutable", diff --git a/wiki/devbox.md b/wiki/devbox.md index aaa7b041e..a2ceef794 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -17,8 +17,8 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s ### Emulator/AVD scripts -- `devbox run start-android` launches the default “latest” AVD (API 33, Medium Phone). On arm64 hosts it uses the arm64-v8a image; on Intel it uses x86_64. Override with `AVD_FLAVOR=minsdk` to launch the API 21 Pixel AVD instead. You can also set `DETOX_AVD` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. -- `devbox run start-android-latest` / `start-android-minsdk` explicitly launch the latest (API 33) or minsdk (API 21) AVDs. Both will create the AVD first via `scripts/android/avd.sh` if it does not exist. +- `devbox run start-android` launches the default “max” AVD (from `scripts/env-defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. +- `devbox run start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/android/avd.sh` if it does not exist. - `scripts/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. - `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. - `EMU_HEADLESS=1 devbox run start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. @@ -32,32 +32,32 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s ### Updating Android min/latest versions -- Bump pinned SDK versions in `nix/platform-versions.json` (platformVersions/buildToolsVersions/cmdLineToolsVersion). Refresh your devshell by running the `refresh` command while inside a devbox shell. +- Bump pinned SDK versions in `scripts/env-defaults.json` (platformVersions/buildToolsVersions/cmdLineToolsVersion). Refresh your devshell by running the `refresh` command while inside a devbox shell. - Update AVD defaults/names if you change API levels: - `devbox.json` (`start-android-*` scripts) for default AVD names. - `examples/E2E/.detoxrc.js` for the default `DETOX_AVD`. - CI matrix in `.github/workflows/ci-e2e-full.yml` (`android-min`/`android-latest` targets). -- Gradle uses `buildToolsVersion` from `examples/E2E/android/build.gradle`; Devbox exports `ANDROID_BUILD_TOOLS_VERSION` from `nix/platform-versions.json` (single source of truth) and you can override it if needed. +- Gradle uses `buildToolsVersion` from `examples/E2E/android/build.gradle`; Devbox exports `ANDROID_BUILD_TOOLS_VERSION` from `scripts/env-defaults.json` (single source of truth) and you can override it if needed. ## iOS iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `devbox run setup-ios` to provision simulators and validate Xcode tooling. Full Xcode is required for `simctl` (Command Line Tools alone are not enough). Make sure Xcode command line tools are selected (`xcode-select --print-path` or `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`) and that you have agreed to the license if prompted. -> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/entry/run.sh` re-applies it before running iOS E2E. +> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/run.sh` re-applies it before running iOS E2E. ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/platform-versions.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. -- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `nix/platform-versions.json`) or leave default for latest. Internally uses `scripts/entry/run.sh ios start`. +- `devbox run setup-ios` provisions simulators. Defaults are driven by `scripts/env-defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. +- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `scripts/env-defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. - `devbox run reset-ios` shuts down/erases and removes all local simulator devices. - `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). -- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/platform-versions.json`) and latest (iPhone 17). +- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `scripts/env-defaults.json`) and latest (iPhone 17). - `devbox run test-ios` runs `setup-ios` first to ensure simulators exist; Detox handles booting. Use `start-ios` if you want to pre-boot. ### Common env knobs -- Android: `AVD_FLAVOR` (minsdk/latest), `DETOX_AVD` (explicit AVD name), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). -- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `nix/platform-versions.json` as `PLATFORM_IOS_MIN_VERSION`/`PLATFORM_IOS_MAX_VERSION`. +- Android: `TARGET_SDK` (min/max), `DETOX_AVD` (explicit AVD name), `AVD_NAME` (explicit AVD name for create + start), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). +- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `scripts/env-defaults.json` as `PLATFORM_IOS_MIN_VERSION`/`PLATFORM_IOS_MAX_VERSION`. ### Releases @@ -65,7 +65,7 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Updating iOS min/latest versions -- Adjust platform defaults in `nix/platform-versions.json` and rebuild Devbox if you change Android SDK versions. +- Adjust platform defaults in `scripts/env-defaults.json` and rebuild Devbox if you change Android SDK versions. - Update Detox default device in `examples/E2E/.detoxrc.js` if the default device changes. - Update CI matrices in `.github/workflows/ci-e2e-full.yml` (ios-min/ios-latest rows) if you want to override the platform defaults in CI. diff --git a/wiki/nix.md b/wiki/nix.md index a589a5752..2a6d0db44 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -9,28 +9,28 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc - Defines the pinned Android SDK (emulator, system images, build tools). - Exposes an `android-sdk` output used by Devbox (`path:./nix#android-sdk`). -- `nix/platform-versions.json` +- `scripts/env-defaults.json` - Single source of truth for Android/iOS min and max targets. - Contains Android build tools + cmdline tools versions. -- `scripts/platform-versions.sh` - - Loads `nix/platform-versions.json` via `jq` and exports env vars for scripts and CI. +- `scripts/env-defaults.sh` + - Loads `scripts/env-defaults.json` via `jq` and exports env vars for scripts and CI. ## How versions flow -1. `nix/platform-versions.json` is updated. +1. `scripts/env-defaults.json` is updated. 2. `nix/flake.nix` reads those values when building the Android SDK output. -3. `scripts/platform-versions.sh` exports the same values for: +3. `scripts/env-defaults.sh` exports the same values for: - scripts under `scripts/android/` and `scripts/ios/` - CI workflows that set min/max targets ## Updating versions -1. Edit `nix/platform-versions.json`. +1. Edit `scripts/env-defaults.json`. 2. In a devbox shell, run `refresh` to rebuild the SDK. 3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. -4. `nix/platform-versions.json` now has a `defaults` section (exported by `scripts/platform-versions.sh`) and a `vars` section that lists supported env knobs. +4. `scripts/env-defaults.json` now has a `defaults` section (exported by `scripts/env-defaults.sh`) and a `vars` section that lists supported env knobs. ## CI targets diff --git a/wiki/scripts.md b/wiki/scripts.md index 268e7ba9a..05845822c 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -4,18 +4,18 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. ## Layout -- `scripts/build.sh`: JS build + lint for fast CI. -- `scripts/platform-versions.sh`: loads `nix/platform-versions.json` and exports platform vars for scripts. +- `scripts/run.sh`: entrypoint for devbox/CI tasks (build/test/act). +- `scripts/env-defaults.sh`: loads `scripts/env-defaults.json` and exports platform vars for scripts. - `scripts/shared/common.sh`: shared helpers (tool checks, platform version loader). - `scripts/android/`: Android SDK, AVD, and E2E helpers. - `scripts/ios/`: iOS simulator setup, toolchain fixups, and E2E helpers. -- `scripts/act-ci.sh`: local CI runner helper for `act`. +- `scripts/android/run.sh` + `scripts/ios/run.sh`: platform task dispatchers called by `scripts/run.sh`. ## Shared helpers - `scripts/shared/common.sh` - `require_tool`: asserts a tool exists (with an optional custom message). - - `load_platform_versions`: sources `scripts/platform-versions.sh` if present. + - `env-defaults.sh`: sourced once to load platform defaults for scripts. - `PROJECT_ROOT`: auto-detected git root when unset. - `SCRIPTS_DIR`: defaults to `$PROJECT_ROOT/scripts` when unset. @@ -25,14 +25,14 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). - Set `ANDROID_SDK_USE_LOCAL=1` to keep a pre-set local SDK instead. - - Loads platform defaults via `scripts/platform-versions.sh`. + - Loads platform defaults via `scripts/env-defaults.sh`. - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. - `scripts/android/avd.sh` - - Creates/ensures AVDs for min and max API levels, then starts/stops/resets emulators. + - Creates/ensures AVDs for the target API level, then starts/stops/resets emulators. - Depends on `sdkmanager`, `avdmanager`, `emulator` in PATH (Devbox shell). - - Uses platform defaults from `scripts/platform-versions.sh`. + - Uses platform defaults from `scripts/env-defaults.sh`. ## iOS scripts @@ -41,7 +41,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Workaround for Devbox macOS toolchain injection. - Removes Nix toolchain variables and re-selects system clang/Xcode. - - Sourced by devbox init hooks and re-applied in `scripts/entry/run.sh` for iOS tasks. + - Sourced by devbox init hooks and re-applied in `scripts/run.sh` for iOS tasks. - `scripts/ios/simctl.sh` @@ -53,19 +53,20 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. Root devbox (`devbox.json`) exposes: -- `build` -> `scripts/entry/run.sh build` -- `test-android` -> `scripts/entry/run.sh android test` -- `test-ios` -> `scripts/entry/run.sh ios test` -- `setup-android` -> `scripts/entry/run.sh android setup` -- `setup-ios` -> `scripts/entry/run.sh ios setup` -- `start-android*` -> `scripts/entry/run.sh android start` (uses `scripts/android/avd.sh`) -- `start-ios` -> `scripts/entry/run.sh ios start` +- `build` -> `scripts/run.sh build` +- `test-android` -> `scripts/run.sh android test` +- `test-ios` -> `scripts/run.sh ios test` +- `setup-android` -> `scripts/run.sh android setup` +- `setup-ios` -> `scripts/run.sh ios setup` +- `start-android*` -> `scripts/run.sh android start` (uses `scripts/android/avd.sh`) +- `start-ios` -> `scripts/run.sh ios start` +- `act` -> `scripts/run.sh act ` Slim CI shells: -- `shells/minimal/devbox.json` -> `scripts/entry/run.sh build` -- `shells/android-min/devbox.json` -> `scripts/entry/run.sh android test` -- `shells/android-max/devbox.json` -> `scripts/entry/run.sh android test` -- `shells/ios/devbox.json` -> `scripts/entry/run.sh ios test` +- `shells/minimal/devbox.json` -> `scripts/run.sh build` +- `shells/android-min/devbox.json` -> `scripts/run.sh android test` +- `shells/android-max/devbox.json` -> `scripts/run.sh android test` +- `shells/ios/devbox.json` -> `scripts/run.sh ios test` See `wiki/devbox.md` for usage and `wiki/nix.md` for platform version sources. From 2b0d7aabed7a1f7b0d307807c2155f2f3fbc2228 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 19:52:38 -0600 Subject: [PATCH 15/32] refactor vars --- .github/workflows/ci-e2e-full.yml | 18 +-------- .github/workflows/ci-e2e-latest.yml | 9 +---- .github/workflows/publish.yml | 18 +-------- package.json | 3 +- scripts/android/avd.sh | 52 +++++++++++++++++++------- scripts/android/env.sh | 37 +++++++----------- scripts/android/run.sh | 1 + scripts/env-defaults.json | 58 +++++++---------------------- scripts/env-defaults.sh | 24 ++++++------ scripts/ios/env.sh | 4 +- scripts/ios/run.sh | 20 ++++++++-- scripts/ios/simctl.sh | 2 +- wiki/devbox.md | 4 +- wiki/nix.md | 2 +- wiki/scripts.md | 33 ++++++++++++++++ 15 files changed, 141 insertions(+), 144 deletions(-) diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 18419baf1..ada62ca06 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -47,12 +47,7 @@ jobs: enable-cache: 'false' - name: Resolve iOS targets run: | - . scripts/platform-versions.sh - if [ "${{ matrix.name }}" = "ios-min" ]; then - echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MIN_DEVICE}" >> "$GITHUB_ENV" - else - echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" - fi + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const isMin='${{ matrix.name }}'==='ios-min';const device=isMin?d.IOS_MIN_DEVICE:d.IOS_MAX_DEVICE;process.stdout.write('DETOX_IOS_DEVICE=' + device + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios @@ -94,15 +89,6 @@ jobs: enable-cache: 'false' - name: Resolve Android targets run: | - . scripts/platform-versions.sh - if [ "${{ matrix.target }}" = "min" ]; then - api="$PLATFORM_ANDROID_MIN_API" - device="$PLATFORM_ANDROID_MIN_DEVICE" - else - api="$PLATFORM_ANDROID_MAX_API" - device="$PLATFORM_ANDROID_MAX_DEVICE" - fi - avd_name="${device}_API${api}_${AVD_ABI}" - echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const target='${{ matrix.target }}';const api=target==='min'?d.ANDROID_MIN_API:d.ANDROID_MAX_API;const device=target==='min'?d.ANDROID_MIN_DEVICE:d.ANDROID_MAX_DEVICE;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + device + '_API' + api + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 84f03849c..9466d7a25 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -41,8 +41,7 @@ jobs: enable-cache: 'false' - name: Resolve iOS targets run: | - . scripts/platform-versions.sh - echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;process.stdout.write('DETOX_IOS_DEVICE=' + d.IOS_MAX_DEVICE + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests (latest) run: devbox run --config=shells/ios/devbox.json test-ios @@ -77,10 +76,6 @@ jobs: enable-cache: 'false' - name: Resolve Android targets run: | - . scripts/platform-versions.sh - api="$PLATFORM_ANDROID_MAX_API" - device="$PLATFORM_ANDROID_MAX_DEVICE" - avd_name="${device}_API${api}_${AVD_ABI}" - echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + d.ANDROID_MAX_DEVICE + '_API' + d.ANDROID_MAX_API + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests (latest) run: devbox run --config=shells/android-max/devbox.json test-android diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 235fe0f73..2976b06a0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -60,12 +60,7 @@ jobs: enable-cache: 'false' - name: Resolve iOS targets run: | - . scripts/platform-versions.sh - if [ "${{ matrix.name }}" = "ios-min" ]; then - echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MIN_DEVICE}" >> "$GITHUB_ENV" - else - echo "DETOX_IOS_DEVICE=${PLATFORM_IOS_MAX_DEVICE}" >> "$GITHUB_ENV" - fi + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const isMin='${{ matrix.name }}'==='ios-min';const device=isMin?d.IOS_MIN_DEVICE:d.IOS_MAX_DEVICE;process.stdout.write('DETOX_IOS_DEVICE=' + device + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios @@ -108,16 +103,7 @@ jobs: enable-cache: 'false' - name: Resolve Android targets run: | - . scripts/platform-versions.sh - if [ "${{ matrix.target }}" = "min" ]; then - api="$PLATFORM_ANDROID_MIN_API" - device="$PLATFORM_ANDROID_MIN_DEVICE" - else - api="$PLATFORM_ANDROID_MAX_API" - device="$PLATFORM_ANDROID_MAX_DEVICE" - fi - avd_name="${device}_API${api}_${AVD_ABI}" - echo "DETOX_AVD=${avd_name}" >> "$GITHUB_ENV" + node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const target='${{ matrix.target }}';const api=target==='min'?d.ANDROID_MIN_API:d.ANDROID_MAX_API;const device=target==='min'?d.ANDROID_MIN_DEVICE:d.ANDROID_MAX_DEVICE;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + device + '_API' + api + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/package.json b/package.json index d6232414c..34981f99b 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,5 @@ "semantic-release-yarn": "^3.0.2", "ts-jest": "^29.1.1", "typescript": "^5.2.2" - }, - "packageManager": "yarn@4.1.0" + } } diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 23c4f1276..0a0e641f1 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -84,7 +84,7 @@ pick_image() { for abi in $candidates; do image="system-images;android-${api};${tag};${abi}" path="${ANDROID_SDK_ROOT}/system-images/android-${api}/${tag}/${abi}" - if [ -n "${ANDROID_SETUP_DEBUG:-}" ]; then + if debug_enabled; then if [ -d "$path" ]; then echo "Debug: found ABI path $path" >&2 else @@ -147,11 +147,11 @@ android_setup() { require_tool avdmanager require_tool emulator - platform_min_api="${PLATFORM_ANDROID_MIN_API:-21}" - platform_max_api="${PLATFORM_ANDROID_MAX_API:-33}" - platform_min_device="${PLATFORM_ANDROID_MIN_DEVICE:-pixel}" - platform_max_device="${PLATFORM_ANDROID_MAX_DEVICE:-medium_phone}" - platform_image_tag="${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" + platform_min_api="${ANDROID_MIN_API:-21}" + platform_max_api="${ANDROID_MAX_API:-33}" + platform_min_device="${ANDROID_MIN_DEVICE:-pixel}" + platform_max_device="${ANDROID_MAX_DEVICE:-medium_phone}" + platform_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" target_sdk="${TARGET_SDK:-max}" case "$target_sdk" in @@ -163,6 +163,18 @@ android_setup() { target_api="$platform_max_api" target_device="$platform_max_device" ;; + custom) + target_api="${ANDROID_CUSTOM_API:-}" + target_device="${ANDROID_CUSTOM_DEVICE:-}" + if [ -z "$target_api" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_API to be set." >&2 + exit 1 + fi + if [ -z "$target_device" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + ;; *) target_api="$platform_max_api" target_device="$platform_max_device" @@ -170,7 +182,7 @@ android_setup() { esac target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" - target_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" + target_tag="${AVD_TAG:-${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}}" if [ -n "${AVD_DEVICE:-}" ]; then target_device="$AVD_DEVICE" fi @@ -212,7 +224,7 @@ TARGET_EOF preferred_abi="${preferred_abi-}" name_override="${name_override-}" - if [ -n "${ANDROID_SETUP_DEBUG:-}" ]; then + if debug_enabled; then api_image="$(pick_image "$api" "$tag" "$preferred_abi" || true)" else api_image="$(pick_image "$api" "$tag" "$preferred_abi" 2>/dev/null || true)" @@ -274,11 +286,11 @@ android_start() { fi if [ -z "$avd" ]; then - platform_min_api="${PLATFORM_ANDROID_MIN_API:-21}" - platform_max_api="${PLATFORM_ANDROID_MAX_API:-33}" - platform_min_device="${PLATFORM_ANDROID_MIN_DEVICE:-pixel}" - platform_max_device="${PLATFORM_ANDROID_MAX_DEVICE:-medium_phone}" - platform_image_tag="${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" + platform_min_api="${ANDROID_MIN_API:-21}" + platform_max_api="${ANDROID_MAX_API:-33}" + platform_min_device="${ANDROID_MIN_DEVICE:-pixel}" + platform_max_device="${ANDROID_MAX_DEVICE:-medium_phone}" + platform_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" case "$target_sdk" in min) @@ -289,6 +301,18 @@ android_start() { target_api="$platform_max_api" target_device="$platform_max_device" ;; + custom) + target_api="${ANDROID_CUSTOM_API:-}" + target_device="${ANDROID_CUSTOM_DEVICE:-}" + if [ -z "$target_api" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_API to be set." >&2 + exit 1 + fi + if [ -z "$target_device" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + ;; *) target_api="$platform_max_api" target_device="$platform_max_device" @@ -296,7 +320,7 @@ android_start() { esac target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" - target_tag="${AVD_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}" + target_tag="${AVD_TAG:-${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}}" if [ -n "${AVD_DEVICE:-}" ]; then target_device="$AVD_DEVICE" fi diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 366cd9acd..cc85087ef 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -13,21 +13,7 @@ if [ -z "${COMMON_SH_LOADED:-}" ]; then fi debug_log_script "scripts/android/env.sh" -if [ -z "${ANDROID_MIN_API:-}" ] && [ -n "${PLATFORM_ANDROID_MIN_API:-}" ]; then - ANDROID_MIN_API="$PLATFORM_ANDROID_MIN_API" -fi -if [ -z "${ANDROID_MAX_API:-}" ] && [ -n "${PLATFORM_ANDROID_MAX_API:-}" ]; then - ANDROID_MAX_API="$PLATFORM_ANDROID_MAX_API" -fi -if [ -z "${ANDROID_BUILD_TOOLS_VERSION:-}" ] && [ -n "${PLATFORM_ANDROID_BUILD_TOOLS_VERSION:-}" ]; then - ANDROID_BUILD_TOOLS_VERSION="$PLATFORM_ANDROID_BUILD_TOOLS_VERSION" -fi -if [ -z "${ANDROID_CMDLINE_TOOLS_VERSION:-}" ] && [ -n "${PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION:-}" ]; then - ANDROID_CMDLINE_TOOLS_VERSION="$PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION" -fi -if [ -z "${ANDROID_SYSTEM_IMAGE_TAG:-}" ] && [ -n "${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-}" ]; then - ANDROID_SYSTEM_IMAGE_TAG="$PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" -fi + resolve_flake_sdk_root() { root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" @@ -168,10 +154,10 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO export DEVBOX_ANDROID_SDK_SUMMARY_PRINTED android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" - android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${PLATFORM_ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-${PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION:-30.0.3}}}}" - android_min_api="${ANDROID_MIN_API:-${PLATFORM_ANDROID_MIN_API:-21}}" - android_max_api="${ANDROID_MAX_API:-${PLATFORM_ANDROID_MAX_API:-33}}" - android_system_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-${PLATFORM_ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}" + android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-30.0.3}}" + android_min_api="${ANDROID_MIN_API:-21}" + android_max_api="${ANDROID_MAX_API:-33}" + android_system_image_tag="${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-google_apis}}" android_system_image_abi="" android_target_api="${AVD_API:-${ANDROID_TARGET_API:-}}" android_target_source="" @@ -185,6 +171,10 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO android_target_api="$android_max_api" android_target_source="max" ;; + custom) + android_target_api="${ANDROID_CUSTOM_API:-}" + android_target_source="custom" + ;; *) android_target_api="$android_max_api" android_target_source="max" @@ -199,14 +189,15 @@ if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIO android_target_device="${AVD_DEVICE:-}" if [ -z "$android_target_device" ]; then case "${TARGET_SDK:-max}" in - min) android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" ;; - max) android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" ;; + min) android_target_device="${ANDROID_MIN_DEVICE:-}" ;; + max) android_target_device="${ANDROID_MAX_DEVICE:-}" ;; + custom) android_target_device="${ANDROID_CUSTOM_DEVICE:-}" ;; esac if [ -z "$android_target_device" ]; then if [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_min_api" ]; then - android_target_device="${PLATFORM_ANDROID_MIN_DEVICE:-}" + android_target_device="${ANDROID_MIN_DEVICE:-}" elif [ -n "$android_target_api" ] && [ "$android_target_api" = "$android_max_api" ]; then - android_target_device="${PLATFORM_ANDROID_MAX_DEVICE:-}" + android_target_device="${ANDROID_MAX_DEVICE:-}" fi fi fi diff --git a/scripts/android/run.sh b/scripts/android/run.sh index cec005324..6fe526d17 100644 --- a/scripts/android/run.sh +++ b/scripts/android/run.sh @@ -24,6 +24,7 @@ android_run() { # shellcheck disable=SC1090 . "$scripts_root/android/avd.sh" android_setup + yarn install --immutable yarn e2e install yarn build yarn e2e build:android diff --git a/scripts/env-defaults.json b/scripts/env-defaults.json index ed6738c7c..2c64b14b0 100644 --- a/scripts/env-defaults.json +++ b/scripts/env-defaults.json @@ -1,48 +1,18 @@ { "defaults": { - "PLATFORM_ANDROID_MIN_API": "21", - "PLATFORM_ANDROID_MAX_API": "33", - "PLATFORM_ANDROID_BUILD_TOOLS_VERSION": "30.0.3", - "PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION": "19.0", - "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG": "google_apis", - "PLATFORM_ANDROID_MIN_DEVICE": "pixel", - "PLATFORM_ANDROID_MAX_DEVICE": "medium_phone", - "PLATFORM_IOS_MIN_VERSION": "15.0", - "PLATFORM_IOS_MAX_VERSION": "26.2", - "PLATFORM_IOS_MIN_DEVICE": "iPhone 13", - "PLATFORM_IOS_MAX_DEVICE": "iPhone 17" - }, - "vars": { - "ANDROID": [ - "ANDROID_SDK_USE_LOCAL", - "ANDROID_SDK_FLAKE_OUTPUT", - "TARGET_SDK", - "ANDROID_TARGET_API", - "ANDROID_MIN_API", - "ANDROID_MAX_API", - "ANDROID_SYSTEM_IMAGE_TAG", - "ANDROID_BUILD_TOOLS_VERSION", - "ANDROID_CMDLINE_TOOLS_VERSION" - ], - "ANDROID_AVD": [ - "AVD_API", - "AVD_DEVICE", - "AVD_TAG", - "AVD_ABI", - "AVD_NAME", - "EMU_HEADLESS", - "EMU_PORT", - "DETOX_AVD" - ], - "IOS": [ - "IOS_RUNTIME", - "IOS_MIN_VERSION", - "IOS_MAX_VERSION", - "IOS_DEVICE_NAMES", - "IOS_DEVELOPER_DIR", - "IOS_DOWNLOAD_RUNTIME", - "IOS_FLAVOR", - "DETOX_IOS_DEVICE" - ] + "ANDROID_SDK_USE_LOCAL": "0", + "ANDROID_MIN_API": "21", + "ANDROID_MAX_API": "33", + "ANDROID_SYSTEM_IMAGE_TAG": "google_apis", + "ANDROID_BUILD_TOOLS_VERSION": "30.0.3", + "ANDROID_CMDLINE_TOOLS_VERSION": "19.0", + "ANDROID_MIN_DEVICE": "pixel", + "ANDROID_MAX_DEVICE": "medium_phone", + "ANALYTICS_CI_DEBUG": "0", + "DEBUG": "0", + "IOS_MIN_VERSION": "15.0", + "IOS_MAX_VERSION": "26.2", + "IOS_MIN_DEVICE": "iPhone 13", + "IOS_MAX_DEVICE": "iPhone 17" } } diff --git a/scripts/env-defaults.sh b/scripts/env-defaults.sh index a8ffdf36b..6e4827591 100644 --- a/scripts/env-defaults.sh +++ b/scripts/env-defaults.sh @@ -10,7 +10,7 @@ export ENV_DEFAULTS_LOADING script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="$(cd "$script_dir/.." && pwd)" -versions_json="${ENV_DEFAULTS_JSON:-${PLATFORM_VERSIONS_JSON:-$repo_root/scripts/env-defaults.json}}" +versions_json="${ENV_DEFAULTS_JSON:-$repo_root/scripts/env-defaults.json}" if ! command -v debug_log_script >/dev/null 2>&1; then if [ -f "$script_dir/shared/debug.sh" ]; then @@ -47,17 +47,17 @@ EOF ENV_DEFAULTS_DEBUG_PRINTED=1 export ENV_DEFAULTS_DEBUG_PRINTED for key in \ - PLATFORM_ANDROID_MIN_API \ - PLATFORM_ANDROID_MAX_API \ - PLATFORM_ANDROID_BUILD_TOOLS_VERSION \ - PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION \ - PLATFORM_ANDROID_SYSTEM_IMAGE_TAG \ - PLATFORM_ANDROID_MIN_DEVICE \ - PLATFORM_ANDROID_MAX_DEVICE \ - PLATFORM_IOS_MIN_VERSION \ - PLATFORM_IOS_MAX_VERSION \ - PLATFORM_IOS_MIN_DEVICE \ - PLATFORM_IOS_MAX_DEVICE; do + ANDROID_MIN_API \ + ANDROID_MAX_API \ + ANDROID_BUILD_TOOLS_VERSION \ + ANDROID_CMDLINE_TOOLS_VERSION \ + ANDROID_SYSTEM_IMAGE_TAG \ + ANDROID_MIN_DEVICE \ + ANDROID_MAX_DEVICE \ + IOS_MIN_VERSION \ + IOS_MAX_VERSION \ + IOS_MIN_DEVICE \ + IOS_MAX_DEVICE; do value="$(eval "printf '%s' \"\${$key-}\"")" printf 'DEBUG: %s=%s\n' "$key" "$value" done diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index ebd3b7cf6..ace8f2c38 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -131,8 +131,8 @@ if [ -n "${DEVBOX_INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:- repo_root="$(cd "$(dirname "$0")/../.." && pwd)" fi - ios_min_version="${IOS_MIN_VERSION:-${PLATFORM_IOS_MIN_VERSION:-}}" - ios_max_version="${IOS_MAX_VERSION:-${PLATFORM_IOS_MAX_VERSION:-}}" + ios_min_version="${IOS_MIN_VERSION:-}" + ios_max_version="${IOS_MAX_VERSION:-}" ios_runtime="${IOS_RUNTIME:-}" if [ -z "$ios_runtime" ] && command -v xcrun >/dev/null 2>&1; then ios_runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" diff --git a/scripts/ios/run.sh b/scripts/ios/run.sh index 3ea6ede94..7647ab1ae 100644 --- a/scripts/ios/run.sh +++ b/scripts/ios/run.sh @@ -26,6 +26,7 @@ ios_run() { # shellcheck disable=SC1090 . "$scripts_root/ios/simctl.sh" ios_setup + yarn install --immutable yarn e2e install yarn e2e pods yarn build @@ -45,11 +46,22 @@ ios_run() { case "$action" in start) flavor="${IOS_FLAVOR:-latest}" - if [ "$flavor" = "minsdk" ]; then - IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}}}" + if [ "$flavor" = "custom" ]; then + if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then + echo "IOS_FLAVOR=custom requires IOS_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + if [ -n "${IOS_CUSTOM_VERSION:-}" ]; then + IOS_RUNTIME="${IOS_CUSTOM_VERSION}" + export IOS_RUNTIME + fi + IOS_DEVICE_NAMES="${IOS_CUSTOM_DEVICE}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_CUSTOM_DEVICE}}" + elif [ "$flavor" = "minsdk" ]; then + IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-iPhone 13}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-iPhone 13}}" else - IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" fi export IOS_DEVICE_NAMES DETOX_IOS_DEVICE diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index b650db369..c7975292d 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -186,7 +186,7 @@ ios_setup() { if ! ensure_core_sim_service; then return 1 fi - devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-${PLATFORM_IOS_MIN_DEVICE:-iPhone 13}},${IOS_MAX_DEVICE:-${PLATFORM_IOS_MAX_DEVICE:-iPhone 17}}}" + devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" runtime="${IOS_RUNTIME:-}" if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" diff --git a/wiki/devbox.md b/wiki/devbox.md index a2ceef794..0118028f0 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -32,7 +32,7 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s ### Updating Android min/latest versions -- Bump pinned SDK versions in `scripts/env-defaults.json` (platformVersions/buildToolsVersions/cmdLineToolsVersion). Refresh your devshell by running the `refresh` command while inside a devbox shell. +- Bump pinned SDK versions in `scripts/env-defaults.json`. Refresh your devshell by running the `refresh` command while inside a devbox shell. - Update AVD defaults/names if you change API levels: - `devbox.json` (`start-android-*` scripts) for default AVD names. - `examples/E2E/.detoxrc.js` for the default `DETOX_AVD`. @@ -57,7 +57,7 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Common env knobs - Android: `TARGET_SDK` (min/max), `DETOX_AVD` (explicit AVD name), `AVD_NAME` (explicit AVD name for create + start), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). -- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `scripts/env-defaults.json` as `PLATFORM_IOS_MIN_VERSION`/`PLATFORM_IOS_MAX_VERSION`. +- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `scripts/env-defaults.json` as `IOS_MIN_VERSION`/`IOS_MAX_VERSION`. ### Releases diff --git a/wiki/nix.md b/wiki/nix.md index 2a6d0db44..9fd27e718 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -30,7 +30,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc 1. Edit `scripts/env-defaults.json`. 2. In a devbox shell, run `refresh` to rebuild the SDK. 3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. -4. `scripts/env-defaults.json` now has a `defaults` section (exported by `scripts/env-defaults.sh`) and a `vars` section that lists supported env knobs. +4. `scripts/env-defaults.json` exports concrete defaults via the `defaults` section. ## CI targets diff --git a/wiki/scripts.md b/wiki/scripts.md index 05845822c..221fadb40 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -48,6 +48,39 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Helpers for runtime selection and simulator management. - Ensures Xcode tools are selected and simulators exist. +## User overrides + +These env vars can be set by users to override defaults or behavior. + +### Android + +- `ANDROID_SDK_USE_LOCAL`: use a local Android SDK instead of the Nix SDK. +- `ANDROID_SDK_FLAKE_OUTPUT`: force a specific flake output (e.g., `android-sdk-max`). +- `TARGET_SDK`: `min`, `max`, or `custom` (selects which API/device pairing to use). +- `ANDROID_MIN_API`, `ANDROID_MAX_API`: override the min/max API levels. +- `ANDROID_MIN_DEVICE`, `ANDROID_MAX_DEVICE`: override the min/max AVD device names. +- `ANDROID_SYSTEM_IMAGE_TAG`: override the system image tag (default `google_apis`). +- `ANDROID_BUILD_TOOLS_VERSION`, `ANDROID_CMDLINE_TOOLS_VERSION`: override build tools/cmdline tools versions. +- `ANDROID_CUSTOM_API`, `ANDROID_CUSTOM_DEVICE`, `ANDROID_CUSTOM_SYSTEM_IMAGE_TAG`: required/optional when `TARGET_SDK=custom`. +- `ANDROID_TARGET_API`: force a specific API, bypassing `TARGET_SDK`. +- `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`: override AVD creation/selection. +- `DETOX_AVD`: force a specific AVD name for Detox. +- `EMU_HEADLESS`: `1` to launch the emulator without a window. +- `EMU_PORT`: emulator port/serial (default `5554`). +- `DEBUG` / `ANALYTICS_CI_DEBUG`: enables verbose logging for script helpers. + +### iOS + +- `IOS_MIN_VERSION`, `IOS_MAX_VERSION`: override min/max iOS versions. +- `IOS_MIN_DEVICE`, `IOS_MAX_DEVICE`: override min/max device names. +- `IOS_RUNTIME`: preferred runtime (used by simctl). +- `IOS_DEVICE_NAMES`: comma-separated list of devices to create. +- `IOS_DEVELOPER_DIR`: override the Xcode path. +- `IOS_DOWNLOAD_RUNTIME`: set to `0` to skip `xcodebuild -downloadPlatform iOS`. +- `IOS_FLAVOR`: `minsdk`, `latest`, or `custom` (controls which device/runtime to boot). +- `IOS_CUSTOM_DEVICE`, `IOS_CUSTOM_VERSION`: used when `IOS_FLAVOR=custom`. +- `DETOX_IOS_DEVICE`: force a specific simulator name for Detox. + ## Devbox wiring From d30c363259267552f837c218806342d42d4120a9 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 19:55:58 -0600 Subject: [PATCH 16/32] update docs --- wiki/scripts.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/wiki/scripts.md b/wiki/scripts.md index 221fadb40..c1f2838a9 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -54,6 +54,8 @@ These env vars can be set by users to override defaults or behavior. ### Android +- `ENV_DEFAULTS_JSON`: path to an alternate `env-defaults.json` (advanced). +- `ANDROID_SDK_ROOT`, `ANDROID_HOME`: explicit SDK location (used with `ANDROID_SDK_USE_LOCAL=1`). - `ANDROID_SDK_USE_LOCAL`: use a local Android SDK instead of the Nix SDK. - `ANDROID_SDK_FLAKE_OUTPUT`: force a specific flake output (e.g., `android-sdk-max`). - `TARGET_SDK`: `min`, `max`, or `custom` (selects which API/device pairing to use). From 6a902ff43c949ded8d22ab46e6344a165032fb74 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 20:34:12 -0600 Subject: [PATCH 17/32] refactors --- devbox.json | 2 +- scripts/android/{run.sh => actions.sh} | 27 ++------ scripts/android/avd.sh | 34 +++++----- scripts/android/env.sh | 23 ++++--- scripts/env-defaults.sh | 91 -------------------------- scripts/env.sh | 45 +++++++++++++ scripts/ios/{run.sh => actions.sh} | 27 ++------ scripts/ios/env.sh | 25 +++++-- scripts/ios/simctl.sh | 38 +++++------ scripts/run.sh | 18 +++-- scripts/shared/common.sh | 59 ----------------- scripts/shared/debug.sh | 5 ++ scripts/shared/defaults.sh | 37 +++++++++++ scripts/shared/project.sh | 41 ++++++++++++ scripts/shared/tools.sh | 15 +++++ shells/android-max/devbox.json | 2 +- shells/android-min/devbox.json | 2 +- shells/ios/devbox.json | 2 +- shells/minimal/devbox.json | 2 +- wiki/nix.md | 6 +- wiki/scripts.md | 22 ++++--- 21 files changed, 258 insertions(+), 265 deletions(-) rename scripts/android/{run.sh => actions.sh} (58%) delete mode 100644 scripts/env-defaults.sh create mode 100644 scripts/env.sh rename scripts/ios/{run.sh => actions.sh} (85%) delete mode 100644 scripts/shared/common.sh create mode 100644 scripts/shared/defaults.sh create mode 100644 scripts/shared/project.sh create mode 100644 scripts/shared/tools.sh diff --git a/devbox.json b/devbox.json index 0e0731efa..6093f8a1d 100644 --- a/devbox.json +++ b/devbox.json @@ -19,7 +19,7 @@ "shell": { "init_hook": [ "echo 'Welcome to analytics-react-native devbox!' > /dev/null", - "DEVBOX_INIT_ANDROID=1 DEVBOX_INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/env-defaults.sh" + "INIT_ANDROID=1 INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/env.sh" ], "scripts": { "clean": [ diff --git a/scripts/android/run.sh b/scripts/android/actions.sh similarity index 58% rename from scripts/android/run.sh rename to scripts/android/actions.sh index 6fe526d17..e85a011e0 100644 --- a/scripts/android/run.sh +++ b/scripts/android/actions.sh @@ -1,28 +1,21 @@ #!/usr/bin/env sh -set -eu -script_dir="$(cd "$(dirname "$0")" && pwd)" - -if [ -z "${COMMON_SH_LOADED:-}" ]; then - # shellcheck disable=SC1090 - . "$script_dir/../shared/common.sh" +if ! (return 0 2>/dev/null); then + echo "scripts/android/actions.sh must be sourced." >&2 + exit 1 fi -scripts_root="${SCRIPTS_DIR:-$(cd "$script_dir/.." && pwd)}" -debug_log_script "scripts/android/run.sh" - android_run() { action="${1:-}" shift 1 || true # shellcheck disable=SC1090 - . "$scripts_root/android/env.sh" + . "$SCRIPTS_DIR/android/env.sh" case "$action" in test) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/android/avd.sh" + . "$SCRIPTS_DIR/android/avd.sh" android_setup yarn install --immutable yarn e2e install @@ -31,15 +24,13 @@ android_run() { yarn e2e test:android ;; setup) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/android/avd.sh" + . "$SCRIPTS_DIR/android/avd.sh" android_setup "$@" ;; start | stop | reset) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/android/avd.sh" + . "$SCRIPTS_DIR/android/avd.sh" case "$action" in start) android_start "$@" ;; stop) android_stop "$@" ;; @@ -52,7 +43,3 @@ android_run() { ;; esac } - -if [ "${RUN_MAIN:-1}" = "1" ]; then - android_run "$@" -fi diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 0a0e641f1..216b5576b 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -1,12 +1,25 @@ #!/usr/bin/env sh set -eu -# Android AVD setup + lifecycle helpers. +if ! (return 0 2>/dev/null); then + echo "scripts/android/avd.sh must be sourced via scripts/run.sh." >&2 + exit 1 +fi script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${COMMON_SH_LOADED:-}" ]; then +if [ -z "${SHARED_LOADED:-}" ]; then + init_path="$script_dir/../env.sh" + if [ ! -f "$init_path" ]; then + repo_root="" + if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" + fi + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then + init_path="$repo_root/scripts/env.sh" + fi + fi # shellcheck disable=SC1090 - . "$script_dir/../shared/common.sh" + . "$init_path" fi debug_log_script "scripts/android/avd.sh" @@ -389,18 +402,3 @@ android_reset() { rm -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub" echo "AVDs and adb keys removed. Recreate via start-android* as needed." } - -if [ "${RUN_MAIN:-1}" = "1" ]; then - action="${1:-}" - shift || true - case "$action" in - start) android_start "$@" ;; - stop) android_stop "$@" ;; - reset) android_reset "$@" ;; - setup) android_setup "$@" ;; - *) - echo "Usage: avd.sh {start|stop|reset|setup}" >&2 - exit 1 - ;; - esac -fi diff --git a/scripts/android/env.sh b/scripts/android/env.sh index cc85087ef..959d108ce 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -1,22 +1,27 @@ #!/usr/bin/env sh -# Sets ANDROID_SDK_ROOT/ANDROID_HOME and PATH to the flake-pinned SDK if not already set. -# Load shared platform versions if present. -project_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" +if ! (return 0 2>/dev/null); then + echo "scripts/android/env.sh must be sourced via scripts/run.sh or scripts/env.sh." >&2 + exit 1 +fi +project_root="${PROJECT_ROOT:-}" +if [ -z "$project_root" ] && command -v git >/dev/null 2>&1; then + project_root="$(git -C "$(dirname "$0")" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" +fi if [ -z "$project_root" ]; then project_root="$(cd "$(dirname "$0")/../.." && pwd)" fi script_dir="$project_root/scripts/android" -if [ -z "${COMMON_SH_LOADED:-}" ]; then +if [ -z "${SHARED_LOADED:-}" ]; then # shellcheck disable=SC1090 - . "$project_root/scripts/shared/common.sh" + . "$project_root/scripts/env.sh" fi debug_log_script "scripts/android/env.sh" resolve_flake_sdk_root() { - root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" + root="${PROJECT_ROOT:-}" if [ -z "$root" ]; then root="$(cd "$script_dir/../.." && pwd)" fi @@ -149,9 +154,9 @@ export ANDROID_ENV_LOADED esac fi fi -if [ -n "${DEVBOX_INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_ANDROID_SDK_SUMMARY_PRINTED:-}" ]; then - DEVBOX_ANDROID_SDK_SUMMARY_PRINTED=1 - export DEVBOX_ANDROID_SDK_SUMMARY_PRINTED +if [ -n "${INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${ANDROID_SDK_SUMMARY_PRINTED:-}" ]; then + ANDROID_SDK_SUMMARY_PRINTED=1 + export ANDROID_SDK_SUMMARY_PRINTED android_sdk_root="${ANDROID_SDK_ROOT:-${ANDROID_HOME:-}}" android_sdk_version="${ANDROID_BUILD_TOOLS_VERSION:-${ANDROID_CMDLINE_TOOLS_VERSION:-30.0.3}}" diff --git a/scripts/env-defaults.sh b/scripts/env-defaults.sh deleted file mode 100644 index 6e4827591..000000000 --- a/scripts/env-defaults.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env sh -# Load shared platform version defaults from JSON for a single source of truth. - -if [ -n "${ENV_DEFAULTS_LOADING:-}" ] || [ "${ENV_DEFAULTS_LOADED:-}" = "1" ]; then - return 0 2>/dev/null || exit 0 -fi - -ENV_DEFAULTS_LOADING=1 -export ENV_DEFAULTS_LOADING - -script_dir="$(cd "$(dirname "$0")" && pwd)" -repo_root="$(cd "$script_dir/.." && pwd)" -versions_json="${ENV_DEFAULTS_JSON:-$repo_root/scripts/env-defaults.json}" - -if ! command -v debug_log_script >/dev/null 2>&1; then - if [ -f "$script_dir/shared/debug.sh" ]; then - # shellcheck disable=SC1090 - . "$script_dir/shared/debug.sh" - fi -fi - -debug_log_script "scripts/env-defaults.sh" - -jq_cmd="" -if command -v jq >/dev/null 2>&1; then - jq_cmd="jq" -elif [ -n "${DEVBOX_PACKAGES_DIR:-}" ] && [ -x "$DEVBOX_PACKAGES_DIR/bin/jq" ]; then - jq_cmd="$DEVBOX_PACKAGES_DIR/bin/jq" -fi - -if [ -f "$versions_json" ] && [ -n "$jq_cmd" ]; then - tab="$(printf '\t')" - while IFS="$tab" read -r key value; do - if [ -z "$key" ]; then - continue - fi - current="$(eval "printf '%s' \"\${$key-}\"")" - if [ -z "$current" ]; then - eval "$key=\"\$value\"" - export "$key" - fi - done </dev/null); then + echo "scripts/env.sh must be sourced." >&2 + exit 1 +fi + +script_dir="$(cd "$(dirname "$0")" && pwd)" +repo_root="" +if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" +fi +if [ -z "$repo_root" ]; then + repo_root="$(cd "$script_dir/.." && pwd)" +fi + +if [ -z "${PROJECT_ROOT:-}" ]; then + PROJECT_ROOT="$repo_root" + export PROJECT_ROOT +fi + +if [ -z "${SCRIPTS_DIR:-}" ]; then + SCRIPTS_DIR="$repo_root/scripts" + export SCRIPTS_DIR +fi + +for shared_script in project.sh debug.sh tools.sh defaults.sh; do + if [ -f "$SCRIPTS_DIR/shared/$shared_script" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/shared/$shared_script" + fi +done + +if [ "${INIT_ANDROID:-}" = "1" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/android/env.sh" +fi + +if [ "${INIT_IOS:-}" = "1" ] && [ "$(uname -s)" = "Darwin" ]; then + # shellcheck disable=SC1090 + . "$SCRIPTS_DIR/ios/env.sh" +fi + +SHARED_LOADED=1 +export SHARED_LOADED diff --git a/scripts/ios/run.sh b/scripts/ios/actions.sh similarity index 85% rename from scripts/ios/run.sh rename to scripts/ios/actions.sh index 7647ab1ae..817d3d53e 100644 --- a/scripts/ios/run.sh +++ b/scripts/ios/actions.sh @@ -1,30 +1,23 @@ #!/usr/bin/env sh -set -eu -script_dir="$(cd "$(dirname "$0")" && pwd)" - -if [ -z "${COMMON_SH_LOADED:-}" ]; then - # shellcheck disable=SC1090 - . "$script_dir/../shared/common.sh" +if ! (return 0 2>/dev/null); then + echo "scripts/ios/actions.sh must be sourced." >&2 + exit 1 fi -scripts_root="${SCRIPTS_DIR:-$(cd "$script_dir/.." && pwd)}" -debug_log_script "scripts/ios/run.sh" - ios_run() { action="${1:-}" shift 1 || true if [ "$(uname -s)" = "Darwin" ]; then # shellcheck disable=SC1090 - . "$scripts_root/ios/env.sh" + . "$SCRIPTS_DIR/ios/env.sh" fi case "$action" in test) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/ios/simctl.sh" + . "$SCRIPTS_DIR/ios/simctl.sh" ios_setup yarn install --immutable yarn e2e install @@ -34,15 +27,13 @@ ios_run() { yarn e2e test:ios ;; setup) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/ios/simctl.sh" + . "$SCRIPTS_DIR/ios/simctl.sh" ios_setup "$@" ;; start | stop | reset) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/ios/simctl.sh" + . "$SCRIPTS_DIR/ios/simctl.sh" case "$action" in start) flavor="${IOS_FLAVOR:-latest}" @@ -106,7 +97,3 @@ ios_run() { ;; esac } - -if [ "${RUN_MAIN:-1}" = "1" ]; then - ios_run "$@" -fi diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index ace8f2c38..95c143844 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -1,10 +1,25 @@ #!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/ios/env.sh must be sourced via scripts/run.sh or scripts/env.sh." >&2 + exit 1 +fi set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${COMMON_SH_LOADED:-}" ]; then +if [ -z "${SHARED_LOADED:-}" ]; then + init_path="$script_dir/../env.sh" + if [ ! -f "$init_path" ]; then + repo_root="" + if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" + fi + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then + init_path="$repo_root/scripts/env.sh" + fi + fi # shellcheck disable=SC1090 - . "$script_dir/../shared/common.sh" + . "$init_path" fi debug_log_script "scripts/ios/env.sh" @@ -119,9 +134,9 @@ if debug_enabled; then fi fi -if [ -n "${DEVBOX_INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${DEVBOX_IOS_SDK_SUMMARY_PRINTED:-}" ]; then - DEVBOX_IOS_SDK_SUMMARY_PRINTED=1 - export DEVBOX_IOS_SDK_SUMMARY_PRINTED +if [ -n "${INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && [ -z "${IOS_SDK_SUMMARY_PRINTED:-}" ]; then + IOS_SDK_SUMMARY_PRINTED=1 + export IOS_SDK_SUMMARY_PRINTED repo_root="${PROJECT_ROOT:-${DEVBOX_PROJECT_ROOT:-}}" if [ -z "$repo_root" ] && [ -n "${SCRIPTS_DIR:-}" ]; then diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index c7975292d..e2eac700d 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -1,10 +1,25 @@ #!/usr/bin/env sh set -eu +if ! (return 0 2>/dev/null); then + echo "scripts/ios/simctl.sh must be sourced via scripts/run.sh." >&2 + exit 1 +fi + script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${COMMON_SH_LOADED:-}" ]; then +if [ -z "${SHARED_LOADED:-}" ]; then + init_path="$script_dir/../env.sh" + if [ ! -f "$init_path" ]; then + repo_root="" + if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" + fi + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then + init_path="$repo_root/scripts/env.sh" + fi + fi # shellcheck disable=SC1090 - . "$script_dir/../shared/common.sh" + . "$init_path" fi debug_log_script "scripts/ios/simctl.sh" @@ -135,13 +150,6 @@ ensure_device() { echo "Created ${display_name}" } -# Creates local iOS simulators for common targets. Requires Xcode command-line tools and jq. -# Env overrides: -# IOS_DEVICE_NAMES="iPhone 15,iPhone 17" (comma-separated) -# IOS_RUNTIME="26.1" (preferred runtime prefix; falls back to latest available) -# IOS_DOWNLOAD_RUNTIME=1 to attempt xcodebuild -downloadPlatform iOS when the preferred runtime is missing -# IOS_DEVELOPER_DIR="/Applications/Xcode.app/Contents/Developer" to override the Xcode path; defaults to xcode-select -p or the standard Xcode.app if found - ensure_developer_dir() { desired="${IOS_DEVELOPER_DIR:-}" if [ -z "$desired" ]; then @@ -201,15 +209,3 @@ ios_setup() { IFS="$ifs_backup" echo "Done. Launch via Xcode > Devices or 'xcrun simctl boot \"\"' then 'open -a Simulator'." } - -if [ "${RUN_MAIN:-1}" = "1" ]; then - action="${1:-}" - shift || true - case "$action" in - setup) ios_setup "$@" ;; - *) - echo "Usage: simctl.sh {setup}" >&2 - exit 1 - ;; - esac -fi diff --git a/scripts/run.sh b/scripts/run.sh index 7e09e97df..3697201c0 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -3,8 +3,18 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" +init_path="$script_dir/env.sh" +if [ ! -f "$init_path" ]; then + repo_root="" + if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" + fi + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then + init_path="$repo_root/scripts/env.sh" + fi +fi # shellcheck disable=SC1090 -. "$script_dir/shared/common.sh" +. "$init_path" debug_log_script "scripts/run.sh" scripts_root="${SCRIPTS_DIR:-$script_dir}" @@ -82,15 +92,13 @@ run_act() { case "$platform" in android) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/android/run.sh" + . "$scripts_root/android/actions.sh" android_run "$action" "$@" ;; ios) - RUN_MAIN=0 # shellcheck disable=SC1090 - . "$scripts_root/ios/run.sh" + . "$scripts_root/ios/actions.sh" ios_run "$action" "$@" ;; build) diff --git a/scripts/shared/common.sh b/scripts/shared/common.sh deleted file mode 100644 index 7b9c08065..000000000 --- a/scripts/shared/common.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env sh - -require_tool() { - tool="$1" - message="${2:-Missing required tool: $tool. Ensure devbox shell is active and required packages are installed.}" - if ! command -v "$tool" >/dev/null 2>&1; then - echo "$message" >&2 - exit 1 - fi -} - -ensure_project_root() { - if [ -n "${PROJECT_ROOT:-}" ]; then - return 0 - fi - - base_dir="${1:-}" - if [ -z "$base_dir" ]; then - base_dir="$PWD" - fi - - git_root="" - if command -v git >/dev/null 2>&1; then - git_root="$(git -C "$base_dir" rev-parse --show-toplevel 2>/dev/null || true)" - fi - - if [ -n "$git_root" ]; then - PROJECT_ROOT="$git_root" - elif [ -f "$base_dir/../shared/common.sh" ] && [ -f "$base_dir/../run.sh" ]; then - PROJECT_ROOT="$(cd "$base_dir/.." && pwd)" - elif [ -f "$base_dir/shared/common.sh" ] && [ -f "$base_dir/run.sh" ]; then - PROJECT_ROOT="$(cd "$base_dir" && pwd)" - fi - - if [ -n "${PROJECT_ROOT:-}" ]; then - export PROJECT_ROOT - fi -} - -ensure_project_root "${SCRIPT_DIR:-${script_dir:-${PWD}}}" - -if [ -z "${SCRIPTS_DIR:-}" ] && [ -n "${PROJECT_ROOT:-}" ]; then - SCRIPTS_DIR="$PROJECT_ROOT/scripts" - export SCRIPTS_DIR -fi - -if [ -f "${SCRIPTS_DIR:-}/shared/debug.sh" ]; then - # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/shared/debug.sh" - debug_log_script "scripts/shared/common.sh" -fi - -if [ -f "${SCRIPTS_DIR:-}/env-defaults.sh" ] && [ "${ENV_DEFAULTS_LOADED:-}" != "1" ]; then - # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/env-defaults.sh" -fi - -COMMON_SH_LOADED=1 -export COMMON_SH_LOADED diff --git a/scripts/shared/debug.sh b/scripts/shared/debug.sh index 51824b9ad..ddd568b37 100644 --- a/scripts/shared/debug.sh +++ b/scripts/shared/debug.sh @@ -1,4 +1,9 @@ #!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/shared/debug.sh must be sourced." >&2 + exit 1 +fi set -eu debug_enabled() { diff --git a/scripts/shared/defaults.sh b/scripts/shared/defaults.sh new file mode 100644 index 000000000..cfcfcff9b --- /dev/null +++ b/scripts/shared/defaults.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/shared/defaults.sh must be sourced." >&2 + exit 1 +fi + +if [ "${ENV_DEFAULTS_LOADED:-}" = "1" ]; then + return 0 2>/dev/null || exit 0 +fi + +if [ -n "${PROJECT_ROOT:-}" ]; then + defaults_json="${ENV_DEFAULTS_JSON:-$PROJECT_ROOT/scripts/env-defaults.json}" + jq_cmd="" + if command -v jq >/dev/null 2>&1; then + jq_cmd="jq" + fi + + if [ -f "$defaults_json" ] && [ -n "$jq_cmd" ]; then + tab="$(printf '\t')" + while IFS="$tab" read -r key value; do + if [ -z "$key" ]; then + continue + fi + current="$(eval "printf '%s' \"\${$key-}\"")" + if [ -z "$current" ]; then + eval "$key=\"\$value\"" + export "$key" + fi + done </dev/null); then + echo "scripts/shared/project.sh must be sourced." >&2 + exit 1 +fi + +ensure_project_root() { + if [ -n "${PROJECT_ROOT:-}" ]; then + return 0 + fi + + base_dir="${1:-}" + if [ -z "$base_dir" ]; then + base_dir="$PWD" + fi + + git_root="" + if command -v git >/dev/null 2>&1; then + git_root="$(git -C "$base_dir" rev-parse --show-toplevel 2>/dev/null || true)" + fi + + if [ -n "$git_root" ]; then + PROJECT_ROOT="$git_root" + elif [ -f "$base_dir/../shared/project.sh" ] && [ -f "$base_dir/../run.sh" ]; then + PROJECT_ROOT="$(cd "$base_dir/.." && pwd)" + elif [ -f "$base_dir/shared/project.sh" ] && [ -f "$base_dir/run.sh" ]; then + PROJECT_ROOT="$(cd "$base_dir" && pwd)" + fi + + if [ -n "${PROJECT_ROOT:-}" ]; then + export PROJECT_ROOT + fi +} + +ensure_project_root "${SCRIPT_DIR:-${script_dir:-${PWD}}}" + +if [ -z "${SCRIPTS_DIR:-}" ] && [ -n "${PROJECT_ROOT:-}" ]; then + SCRIPTS_DIR="$PROJECT_ROOT/scripts" + export SCRIPTS_DIR +fi diff --git a/scripts/shared/tools.sh b/scripts/shared/tools.sh new file mode 100644 index 000000000..64b503238 --- /dev/null +++ b/scripts/shared/tools.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/shared/tools.sh must be sourced." >&2 + exit 1 +fi + +require_tool() { + tool="$1" + message="${2:-Missing required tool: $tool. Ensure devbox shell is active and required packages are installed.}" + if ! command -v "$tool" >/dev/null 2>&1; then + echo "$message" >&2 + exit 1 + fi +} diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index fcdb3658f..f07f05af9 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -10,7 +10,7 @@ "shell": { "init_hook": [ "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", - "DEVBOX_INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" + "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" ], "scripts": { "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 23e7c015f..838b69c7e 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -10,7 +10,7 @@ "shell": { "init_hook": [ "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", - "DEVBOX_INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" + "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" ], "scripts": { "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index d0715ab8d..eea48488c 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -10,7 +10,7 @@ }, "shell": { "init_hook": [ - "DEVBOX_INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh" + "INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" ], "scripts": { "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh ios setup"], diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index c836ecc42..e59e71d53 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -8,7 +8,7 @@ "shfmt": "latest" }, "shell": { - "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/env-defaults.sh"], + "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/env.sh"], "scripts": { "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh build"], "release": [ diff --git a/wiki/nix.md b/wiki/nix.md index 9fd27e718..a169b4282 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -14,14 +14,14 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc - Single source of truth for Android/iOS min and max targets. - Contains Android build tools + cmdline tools versions. -- `scripts/env-defaults.sh` - - Loads `scripts/env-defaults.json` via `jq` and exports env vars for scripts and CI. +- `scripts/env.sh` + - Establishes `PROJECT_ROOT` and `SCRIPTS_DIR` for scripts and CI. ## How versions flow 1. `scripts/env-defaults.json` is updated. 2. `nix/flake.nix` reads those values when building the Android SDK output. -3. `scripts/env-defaults.sh` exports the same values for: +3. `scripts/shared/defaults.sh` loads defaults (via `jq`) and establishes script root context for: - scripts under `scripts/android/` and `scripts/ios/` - CI workflows that set min/max targets diff --git a/wiki/scripts.md b/wiki/scripts.md index c1f2838a9..90bdea08f 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -5,19 +5,23 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. ## Layout - `scripts/run.sh`: entrypoint for devbox/CI tasks (build/test/act). -- `scripts/env-defaults.sh`: loads `scripts/env-defaults.json` and exports platform vars for scripts. -- `scripts/shared/common.sh`: shared helpers (tool checks, platform version loader). +- `scripts/env.sh`: establishes `PROJECT_ROOT`/`SCRIPTS_DIR`, loads `scripts/shared/*`, and optionally initializes platforms when `INIT_ANDROID`/`INIT_IOS` are set. +- `scripts/shared/project.sh`: project root + scripts path helpers. +- `scripts/shared/tools.sh`: shared tool checks. +- `scripts/shared/defaults.sh`: loads `scripts/env-defaults.json` via `jq`. - `scripts/android/`: Android SDK, AVD, and E2E helpers. - `scripts/ios/`: iOS simulator setup, toolchain fixups, and E2E helpers. -- `scripts/android/run.sh` + `scripts/ios/run.sh`: platform task dispatchers called by `scripts/run.sh`. +- `scripts/android/actions.sh` + `scripts/ios/actions.sh`: platform task dispatchers called by `scripts/run.sh`. ## Shared helpers -- `scripts/shared/common.sh` - - `require_tool`: asserts a tool exists (with an optional custom message). - - `env-defaults.sh`: sourced once to load platform defaults for scripts. - - `PROJECT_ROOT`: auto-detected git root when unset. +- `scripts/shared/project.sh` + - `ensure_project_root`: resolves `PROJECT_ROOT`. - `SCRIPTS_DIR`: defaults to `$PROJECT_ROOT/scripts` when unset. +- `scripts/shared/tools.sh` + - `require_tool`: asserts a tool exists (with an optional custom message). +- `scripts/shared/defaults.sh` + - Loads `scripts/env-defaults.json` (via `jq`) to export default env vars when available. ## Android scripts @@ -25,14 +29,14 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). - Set `ANDROID_SDK_USE_LOCAL=1` to keep a pre-set local SDK instead. - - Loads platform defaults via `scripts/env-defaults.sh`. + - Loads platform defaults via `scripts/shared/defaults.sh` (from `scripts/env-defaults.json`). - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. - `scripts/android/avd.sh` - Creates/ensures AVDs for the target API level, then starts/stops/resets emulators. - Depends on `sdkmanager`, `avdmanager`, `emulator` in PATH (Devbox shell). - - Uses platform defaults from `scripts/env-defaults.sh`. + - Uses platform defaults from `scripts/shared/defaults.sh`. ## iOS scripts From 024e422367233a8f72e54317b202f73c397aaefc Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 20:46:53 -0600 Subject: [PATCH 18/32] more refactors --- .github/workflows/ci-e2e-full.yml | 10 ++++----- .github/workflows/ci-e2e-latest.yml | 8 ++----- .github/workflows/publish.yml | 10 ++++----- .../env-defaults.json => nix/defaults.json | 0 nix/flake.nix | 21 ++++++++++--------- scripts/ios/actions.sh | 8 +++---- scripts/shared/defaults.sh | 2 +- wiki/devbox.md | 16 +++++++------- wiki/nix.md | 8 +++---- wiki/scripts.md | 12 +++++------ 10 files changed, 44 insertions(+), 51 deletions(-) rename scripts/env-defaults.json => nix/defaults.json (100%) diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index ada62ca06..48c916e30 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -20,7 +20,9 @@ jobs: matrix: include: - name: ios-min + target: min - name: ios-latest + target: max steps: - uses: actions/checkout@v4 - name: Aggressive disk cleanup (macOS) @@ -45,11 +47,10 @@ jobs: with: project-path: shells/ios/devbox.json enable-cache: 'false' - - name: Resolve iOS targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const isMin='${{ matrix.name }}'==='ios-min';const device=isMin?d.IOS_MIN_DEVICE:d.IOS_MAX_DEVICE;process.stdout.write('DETOX_IOS_DEVICE=' + device + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios + env: + TARGET_SDK: ${{ matrix.target }} run-e2e-android: runs-on: ubuntu-latest @@ -87,8 +88,5 @@ jobs: with: project-path: shells/android-${{ matrix.target }}/devbox.json enable-cache: 'false' - - name: Resolve Android targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const target='${{ matrix.target }}';const api=target==='min'?d.ANDROID_MIN_API:d.ANDROID_MAX_API;const device=target==='min'?d.ANDROID_MIN_DEVICE:d.ANDROID_MAX_DEVICE;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + device + '_API' + api + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 9466d7a25..1248267d7 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -39,11 +39,10 @@ jobs: with: project-path: shells/ios/devbox.json enable-cache: 'false' - - name: Resolve iOS targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;process.stdout.write('DETOX_IOS_DEVICE=' + d.IOS_MAX_DEVICE + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests (latest) run: devbox run --config=shells/ios/devbox.json test-ios + env: + TARGET_SDK: max run-e2e-android: runs-on: ubuntu-latest @@ -74,8 +73,5 @@ jobs: with: project-path: shells/android-max/devbox.json enable-cache: 'false' - - name: Resolve Android targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + d.ANDROID_MAX_DEVICE + '_API' + d.ANDROID_MAX_API + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests (latest) run: devbox run --config=shells/android-max/devbox.json test-android diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2976b06a0..8c5d19c9b 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,7 +33,9 @@ jobs: matrix: include: - name: ios-min + target: min - name: ios-latest + target: max steps: - uses: actions/checkout@v4 - name: Aggressive disk cleanup (macOS) @@ -58,11 +60,10 @@ jobs: with: project-path: shells/ios/devbox.json enable-cache: 'false' - - name: Resolve iOS targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const isMin='${{ matrix.name }}'==='ios-min';const device=isMin?d.IOS_MIN_DEVICE:d.IOS_MAX_DEVICE;process.stdout.write('DETOX_IOS_DEVICE=' + device + '\n');" >> "$GITHUB_ENV" - name: iOS E2E Tests run: devbox run --config=shells/ios/devbox.json test-ios + env: + TARGET_SDK: ${{ matrix.target }} e2e-android: name: E2E Android (min/max) @@ -101,9 +102,6 @@ jobs: with: project-path: shells/android-${{ matrix.target }}/devbox.json enable-cache: 'false' - - name: Resolve Android targets - run: | - node -e "const fs=require('fs');const d=JSON.parse(fs.readFileSync('scripts/env-defaults.json','utf8')).defaults;const target='${{ matrix.target }}';const api=target==='min'?d.ANDROID_MIN_API:d.ANDROID_MAX_API;const device=target==='min'?d.ANDROID_MIN_DEVICE:d.ANDROID_MAX_DEVICE;const abi=process.env.AVD_ABI||'x86_64';process.stdout.write('DETOX_AVD=' + device + '_API' + api + '_' + abi + '\n');" >> "$GITHUB_ENV" - name: Android E2E Tests run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android diff --git a/scripts/env-defaults.json b/nix/defaults.json similarity index 100% rename from scripts/env-defaults.json rename to nix/defaults.json diff --git a/nix/flake.nix b/nix/flake.nix index 0b955cf17..a4ed0cad0 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -13,26 +13,27 @@ "aarch64-darwin" ]; - versionData = builtins.fromJSON (builtins.readFile ../scripts/env-defaults.json); + versionData = builtins.fromJSON (builtins.readFile ./defaults.json); defaultsData = if builtins.hasAttr "defaults" versionData then versionData.defaults else versionData; getVar = - name: default: - if builtins.hasAttr name defaultsData then toString (builtins.getAttr name defaultsData) else default; + name: + if builtins.hasAttr name defaultsData then toString (builtins.getAttr name defaultsData) + else builtins.throw "Missing required default in nix/defaults.json: ${name}"; androidSdkConfig = { platformVersions = [ - (getVar "PLATFORM_ANDROID_MIN_API" "21") - (getVar "PLATFORM_ANDROID_MAX_API" "33") + (getVar "ANDROID_MIN_API") + (getVar "ANDROID_MAX_API") ]; - buildToolsVersion = getVar "PLATFORM_ANDROID_BUILD_TOOLS_VERSION" "30.0.3"; - cmdLineToolsVersion = getVar "PLATFORM_ANDROID_CMDLINE_TOOLS_VERSION" "19.0"; - systemImageTypes = [ (getVar "PLATFORM_ANDROID_SYSTEM_IMAGE_TAG" "google_apis") ]; + buildToolsVersion = getVar "ANDROID_BUILD_TOOLS_VERSION"; + cmdLineToolsVersion = getVar "ANDROID_CMDLINE_TOOLS_VERSION"; + systemImageTypes = [ (getVar "ANDROID_SYSTEM_IMAGE_TAG") ]; }; androidSdkConfigMin = androidSdkConfig // { - platformVersions = [ (getVar "PLATFORM_ANDROID_MIN_API" "21") ]; + platformVersions = [ (getVar "ANDROID_MIN_API") ]; }; androidSdkConfigMax = androidSdkConfig // { - platformVersions = [ (getVar "PLATFORM_ANDROID_MAX_API" "33") ]; + platformVersions = [ (getVar "ANDROID_MAX_API") ]; }; forAllSystems = diff --git a/scripts/ios/actions.sh b/scripts/ios/actions.sh index 817d3d53e..726af90d0 100644 --- a/scripts/ios/actions.sh +++ b/scripts/ios/actions.sh @@ -36,10 +36,10 @@ ios_run() { . "$SCRIPTS_DIR/ios/simctl.sh" case "$action" in start) - flavor="${IOS_FLAVOR:-latest}" - if [ "$flavor" = "custom" ]; then + target_sdk="${TARGET_SDK:-max}" + if [ "$target_sdk" = "custom" ]; then if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then - echo "IOS_FLAVOR=custom requires IOS_CUSTOM_DEVICE to be set." >&2 + echo "TARGET_SDK=custom requires IOS_CUSTOM_DEVICE to be set." >&2 exit 1 fi if [ -n "${IOS_CUSTOM_VERSION:-}" ]; then @@ -48,7 +48,7 @@ ios_run() { fi IOS_DEVICE_NAMES="${IOS_CUSTOM_DEVICE}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_CUSTOM_DEVICE}}" - elif [ "$flavor" = "minsdk" ]; then + elif [ "$target_sdk" = "min" ]; then IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-iPhone 13}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-iPhone 13}}" else diff --git a/scripts/shared/defaults.sh b/scripts/shared/defaults.sh index cfcfcff9b..a1dae45dc 100644 --- a/scripts/shared/defaults.sh +++ b/scripts/shared/defaults.sh @@ -10,7 +10,7 @@ if [ "${ENV_DEFAULTS_LOADED:-}" = "1" ]; then fi if [ -n "${PROJECT_ROOT:-}" ]; then - defaults_json="${ENV_DEFAULTS_JSON:-$PROJECT_ROOT/scripts/env-defaults.json}" + defaults_json="${ENV_DEFAULTS_JSON:-$PROJECT_ROOT/nix/defaults.json}" jq_cmd="" if command -v jq >/dev/null 2>&1; then jq_cmd="jq" diff --git a/wiki/devbox.md b/wiki/devbox.md index 0118028f0..b181ab262 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -17,7 +17,7 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s ### Emulator/AVD scripts -- `devbox run start-android` launches the default “max” AVD (from `scripts/env-defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. +- `devbox run start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. - `devbox run start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/android/avd.sh` if it does not exist. - `scripts/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. - `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. @@ -32,12 +32,12 @@ By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-s ### Updating Android min/latest versions -- Bump pinned SDK versions in `scripts/env-defaults.json`. Refresh your devshell by running the `refresh` command while inside a devbox shell. +- Bump pinned SDK versions in `nix/defaults.json`. Refresh your devshell by running the `refresh` command while inside a devbox shell. - Update AVD defaults/names if you change API levels: - `devbox.json` (`start-android-*` scripts) for default AVD names. - `examples/E2E/.detoxrc.js` for the default `DETOX_AVD`. - CI matrix in `.github/workflows/ci-e2e-full.yml` (`android-min`/`android-latest` targets). -- Gradle uses `buildToolsVersion` from `examples/E2E/android/build.gradle`; Devbox exports `ANDROID_BUILD_TOOLS_VERSION` from `scripts/env-defaults.json` (single source of truth) and you can override it if needed. +- Gradle uses `buildToolsVersion` from `examples/E2E/android/build.gradle`; Devbox exports `ANDROID_BUILD_TOOLS_VERSION` from `nix/defaults.json` (single source of truth) and you can override it if needed. ## iOS @@ -47,17 +47,17 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `scripts/env-defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. -- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `IOS_FLAVOR=minsdk` to target the min sim (per `scripts/env-defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. +- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. +- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `TARGET_SDK=min` to target the min sim (per `nix/defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. - `devbox run reset-ios` shuts down/erases and removes all local simulator devices. - `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). -- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `scripts/env-defaults.json`) and latest (iPhone 17). +- Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/defaults.json`) and latest (iPhone 17). - `devbox run test-ios` runs `setup-ios` first to ensure simulators exist; Detox handles booting. Use `start-ios` if you want to pre-boot. ### Common env knobs - Android: `TARGET_SDK` (min/max), `DETOX_AVD` (explicit AVD name), `AVD_NAME` (explicit AVD name for create + start), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). -- iOS: `IOS_FLAVOR` (minsdk/latest), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `scripts/env-defaults.json` as `IOS_MIN_VERSION`/`IOS_MAX_VERSION`. +- iOS: `TARGET_SDK` (min/max/custom), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `nix/defaults.json` as `IOS_MIN_VERSION`/`IOS_MAX_VERSION`. ### Releases @@ -65,7 +65,7 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Updating iOS min/latest versions -- Adjust platform defaults in `scripts/env-defaults.json` and rebuild Devbox if you change Android SDK versions. +- Adjust platform defaults in `nix/defaults.json` and rebuild Devbox if you change Android SDK versions. - Update Detox default device in `examples/E2E/.detoxrc.js` if the default device changes. - Update CI matrices in `.github/workflows/ci-e2e-full.yml` (ios-min/ios-latest rows) if you want to override the platform defaults in CI. diff --git a/wiki/nix.md b/wiki/nix.md index a169b4282..9984992fd 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -9,7 +9,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc - Defines the pinned Android SDK (emulator, system images, build tools). - Exposes an `android-sdk` output used by Devbox (`path:./nix#android-sdk`). -- `scripts/env-defaults.json` +- `nix/defaults.json` - Single source of truth for Android/iOS min and max targets. - Contains Android build tools + cmdline tools versions. @@ -19,7 +19,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc ## How versions flow -1. `scripts/env-defaults.json` is updated. +1. `nix/defaults.json` is updated. 2. `nix/flake.nix` reads those values when building the Android SDK output. 3. `scripts/shared/defaults.sh` loads defaults (via `jq`) and establishes script root context for: - scripts under `scripts/android/` and `scripts/ios/` @@ -27,10 +27,10 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc ## Updating versions -1. Edit `scripts/env-defaults.json`. +1. Edit `nix/defaults.json`. 2. In a devbox shell, run `refresh` to rebuild the SDK. 3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. -4. `scripts/env-defaults.json` exports concrete defaults via the `defaults` section. +4. `nix/defaults.json` exports concrete defaults via the `defaults` section. ## CI targets diff --git a/wiki/scripts.md b/wiki/scripts.md index 90bdea08f..65044a431 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -8,7 +8,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `scripts/env.sh`: establishes `PROJECT_ROOT`/`SCRIPTS_DIR`, loads `scripts/shared/*`, and optionally initializes platforms when `INIT_ANDROID`/`INIT_IOS` are set. - `scripts/shared/project.sh`: project root + scripts path helpers. - `scripts/shared/tools.sh`: shared tool checks. -- `scripts/shared/defaults.sh`: loads `scripts/env-defaults.json` via `jq`. +- `scripts/shared/defaults.sh`: loads `nix/defaults.json` via `jq`. - `scripts/android/`: Android SDK, AVD, and E2E helpers. - `scripts/ios/`: iOS simulator setup, toolchain fixups, and E2E helpers. - `scripts/android/actions.sh` + `scripts/ios/actions.sh`: platform task dispatchers called by `scripts/run.sh`. @@ -21,7 +21,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `scripts/shared/tools.sh` - `require_tool`: asserts a tool exists (with an optional custom message). - `scripts/shared/defaults.sh` - - Loads `scripts/env-defaults.json` (via `jq`) to export default env vars when available. + - Loads `nix/defaults.json` (via `jq`) to export default env vars when available. ## Android scripts @@ -29,7 +29,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). - Set `ANDROID_SDK_USE_LOCAL=1` to keep a pre-set local SDK instead. - - Loads platform defaults via `scripts/shared/defaults.sh` (from `scripts/env-defaults.json`). + - Loads platform defaults via `scripts/shared/defaults.sh` (from `nix/defaults.json`). - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. - `scripts/android/avd.sh` @@ -58,7 +58,7 @@ These env vars can be set by users to override defaults or behavior. ### Android -- `ENV_DEFAULTS_JSON`: path to an alternate `env-defaults.json` (advanced). +- `ENV_DEFAULTS_JSON`: path to an alternate `nix/defaults.json` (advanced). - `ANDROID_SDK_ROOT`, `ANDROID_HOME`: explicit SDK location (used with `ANDROID_SDK_USE_LOCAL=1`). - `ANDROID_SDK_USE_LOCAL`: use a local Android SDK instead of the Nix SDK. - `ANDROID_SDK_FLAKE_OUTPUT`: force a specific flake output (e.g., `android-sdk-max`). @@ -83,8 +83,8 @@ These env vars can be set by users to override defaults or behavior. - `IOS_DEVICE_NAMES`: comma-separated list of devices to create. - `IOS_DEVELOPER_DIR`: override the Xcode path. - `IOS_DOWNLOAD_RUNTIME`: set to `0` to skip `xcodebuild -downloadPlatform iOS`. -- `IOS_FLAVOR`: `minsdk`, `latest`, or `custom` (controls which device/runtime to boot). -- `IOS_CUSTOM_DEVICE`, `IOS_CUSTOM_VERSION`: used when `IOS_FLAVOR=custom`. +- `TARGET_SDK`: `min`, `max`, or `custom` (controls which device/runtime to boot for iOS). +- `IOS_CUSTOM_DEVICE`, `IOS_CUSTOM_VERSION`: used when `TARGET_SDK=custom`. - `DETOX_IOS_DEVICE`: force a specific simulator name for Detox. From bf3b355d07ebc7885ee2854dc4120807a52d512e Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 22:02:04 -0600 Subject: [PATCH 19/32] workflow refactor --- .github/workflows/android-e2e.yml | 50 +++++ .github/workflows/ci-e2e-full.yml | 71 +------ .github/workflows/ci-e2e-latest.yml | 71 +------ .github/workflows/ios-e2e.yml | 87 +++++++++ .github/workflows/publish.yml | 71 +------ devbox.json | 12 +- devbox.lock | 284 ++++++++++++++++------------ nix/defaults.json | 5 +- nix/flake.nix | 13 +- scripts/android/avd.sh | 24 ++- scripts/android/env.sh | 11 +- scripts/env.sh | 8 +- scripts/ios/actions.sh | 35 +++- scripts/ios/env.sh | 20 +- scripts/ios/simctl.sh | 47 ++++- scripts/run.sh | 72 +------ scripts/shared/debug.sh | 6 + scripts/shared/defaults.sh | 10 +- scripts/shared/project.sh | 6 + scripts/shared/tools.sh | 6 + wiki/devbox.md | 5 +- wiki/scripts.md | 6 +- 22 files changed, 508 insertions(+), 412 deletions(-) create mode 100644 .github/workflows/android-e2e.yml create mode 100644 .github/workflows/ios-e2e.yml diff --git a/.github/workflows/android-e2e.yml b/.github/workflows/android-e2e.yml new file mode 100644 index 000000000..4aede427a --- /dev/null +++ b/.github/workflows/android-e2e.yml @@ -0,0 +1,50 @@ +name: Android E2E (Reusable) + +on: + workflow_call: + inputs: + target: + description: "TARGET_SDK value (min/max/custom)" + required: true + type: string + runs_on: + description: "GitHub runner label" + required: false + type: string + default: "ubuntu-latest" + +jobs: + android-e2e: + runs-on: ${{ inputs.runs_on }} + env: + ANALYTICS_CI_DEBUG: "1" + EMU_HEADLESS: 1 + AVD_ABI: x86_64 + steps: + - uses: actions/checkout@v4 + - name: Aggressive disk cleanup (Ubuntu) + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + sudo rm -rf /opt/hostedtoolcache/CodeQL + sudo rm -rf /usr/local/lib/android + sudo rm -rf /usr/local/lib/node_modules + sudo rm -rf /usr/local/share/boost + sudo rm -rf /usr/local/share/chromium + sudo rm -rf /usr/local/share/powershell + sudo rm -rf /usr/local/share/edge_driver + sudo rm -rf /usr/local/share/gecko_driver + sudo rm -rf /usr/local/share/phantomjs + sudo rm -rf "$HOME/.cache" + df -H + - name: Resolve devbox config + run: | + echo "DEVBOX_CONFIG=shells/android-${{ inputs.target }}/devbox.json" >> "$GITHUB_ENV" + - name: devbox installer + uses: jetify-com/devbox-install-action@v0.14.0 + with: + project-path: ${{ env.DEVBOX_CONFIG }} + enable-cache: 'false' + - name: Android E2E Tests + run: devbox run --config=${{ env.DEVBOX_CONFIG }} test-android diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 48c916e30..06994ae01 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -11,11 +11,6 @@ concurrency: jobs: run-e2e-ios: - runs-on: macos-26 - env: - ANALYTICS_CI_DEBUG: "1" - YARN_ENABLE_HARDENED_MODE: 0 - XCODE_VERSION: '26.2' strategy: matrix: include: @@ -23,41 +18,12 @@ jobs: target: min - name: ios-latest target: max - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (macOS) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /Applications/Android\ Studio.app - sudo rm -rf /usr/local/share/miniconda - sudo rm -rf /opt/homebrew - sudo rm -rf "$HOME/Library/Android" - sudo rm -rf "$HOME/.gradle" - sudo rm -rf "$HOME/Library/Developer/CoreSimulator/Devices" - sudo rm -rf "$HOME/Library/Developer/Xcode/DerivedData" - df -H - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: '26.2' - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/ios/devbox.json - enable-cache: 'false' - - name: iOS E2E Tests - run: devbox run --config=shells/ios/devbox.json test-ios - env: - TARGET_SDK: ${{ matrix.target }} + uses: ./.github/workflows/ios-e2e.yml + with: + target: ${{ matrix.target }} + secrets: inherit run-e2e-android: - runs-on: ubuntu-latest - env: - ANALYTICS_CI_DEBUG: "1" - EMU_HEADLESS: 1 - AVD_ABI: x86_64 strategy: matrix: include: @@ -65,28 +31,7 @@ jobs: target: min - name: android-latest target: max - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (Ubuntu) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo rm -rf /usr/local/lib/android - sudo rm -rf /usr/local/lib/node_modules - sudo rm -rf /usr/local/share/boost - sudo rm -rf /usr/local/share/chromium - sudo rm -rf /usr/local/share/powershell - sudo rm -rf /usr/local/share/edge_driver - sudo rm -rf /usr/local/share/gecko_driver - sudo rm -rf /usr/local/share/phantomjs - sudo rm -rf "$HOME/.cache" - df -H - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/android-${{ matrix.target }}/devbox.json - enable-cache: 'false' - - name: Android E2E Tests - run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android + uses: ./.github/workflows/android-e2e.yml + with: + target: ${{ matrix.target }} + secrets: inherit diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 1248267d7..4a53194c1 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -10,68 +10,13 @@ concurrency: jobs: run-e2e-ios: - runs-on: macos-26 - env: - ANALYTICS_CI_DEBUG: "1" - YARN_ENABLE_HARDENED_MODE: 0 - XCODE_VERSION: '26.2' - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (macOS) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /Applications/Android\ Studio.app - sudo rm -rf /usr/local/share/miniconda - sudo rm -rf /opt/homebrew - sudo rm -rf "$HOME/Library/Android" - sudo rm -rf "$HOME/.gradle" - sudo rm -rf "$HOME/Library/Developer/CoreSimulator/Devices" - sudo rm -rf "$HOME/Library/Developer/Xcode/DerivedData" - df -H - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: '26.2' - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/ios/devbox.json - enable-cache: 'false' - - name: iOS E2E Tests (latest) - run: devbox run --config=shells/ios/devbox.json test-ios - env: - TARGET_SDK: max + uses: ./.github/workflows/ios-e2e.yml + with: + target: max + secrets: inherit run-e2e-android: - runs-on: ubuntu-latest - env: - ANALYTICS_CI_DEBUG: "1" - EMU_HEADLESS: 1 - AVD_ABI: x86_64 - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (Ubuntu) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo rm -rf /usr/local/lib/android - sudo rm -rf /usr/local/lib/node_modules - sudo rm -rf /usr/local/share/boost - sudo rm -rf /usr/local/share/chromium - sudo rm -rf /usr/local/share/powershell - sudo rm -rf /usr/local/share/edge_driver - sudo rm -rf /usr/local/share/gecko_driver - sudo rm -rf /usr/local/share/phantomjs - sudo rm -rf "$HOME/.cache" - df -H - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/android-max/devbox.json - enable-cache: 'false' - - name: Android E2E Tests (latest) - run: devbox run --config=shells/android-max/devbox.json test-android + uses: ./.github/workflows/android-e2e.yml + with: + target: max + secrets: inherit diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml new file mode 100644 index 000000000..16ee3b648 --- /dev/null +++ b/.github/workflows/ios-e2e.yml @@ -0,0 +1,87 @@ +name: iOS E2E (Reusable) + +on: + workflow_call: + inputs: + target: + description: "TARGET_SDK value (min/max/custom)" + required: true + type: string + runtime: + description: "Xcode version to install and iOS runtime to require (optional override)" + required: false + type: string + default: "" + devbox_config: + description: "Devbox config to use" + required: false + type: string + default: "shells/ios/devbox.json" + runs_on: + description: "GitHub runner label" + required: false + type: string + default: "macos-26" + +jobs: + ios-e2e: + runs-on: ${{ inputs.runs_on }} + env: + ANALYTICS_CI_DEBUG: "1" + YARN_ENABLE_HARDENED_MODE: 0 + steps: + - uses: actions/checkout@v4 + - name: Resolve iOS runtime + id: runtime + run: | + runtime="${{ inputs.runtime }}" + min="$(jq -r '.defaults.IOS_RUNTIME_MIN' nix/defaults.json)" + max="$(jq -r '.defaults.IOS_RUNTIME_MAX' nix/defaults.json)" + custom="$(jq -r '.defaults.IOS_RUNTIME_CUSTOM // empty' nix/defaults.json)" + if [ -z "$runtime" ]; then + case "${{ inputs.target }}" in + min) runtime="$min" ;; + max) runtime="$max" ;; + custom) runtime="$custom" ;; + *) echo "Unknown target: ${{ inputs.target }}" >&2; exit 1 ;; + esac + fi + if [ -z "$runtime" ] || [ "$runtime" = "null" ]; then + echo "Missing runtime for target ${{ inputs.target }}" >&2 + exit 1 + fi + if [ -z "$min" ] || [ "$min" = "null" ] || [ -z "$max" ] || [ "$max" = "null" ]; then + echo "Missing IOS_RUNTIME_MIN/IOS_RUNTIME_MAX in nix/defaults.json" >&2 + exit 1 + fi + echo "runtime=$runtime" >> "$GITHUB_OUTPUT" + echo "runtime_min=$min" >> "$GITHUB_OUTPUT" + echo "runtime_max=$max" >> "$GITHUB_OUTPUT" + - name: Aggressive disk cleanup (macOS) + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf "/usr/local/share/boost" + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + sudo rm -rf /Applications/Android\ Studio.app + sudo rm -rf /usr/local/share/miniconda + sudo rm -rf /opt/homebrew + sudo rm -rf "$HOME/Library/Android" + sudo rm -rf "$HOME/.gradle" + sudo rm -rf "$HOME/Library/Developer/CoreSimulator/Devices" + sudo rm -rf "$HOME/Library/Developer/Xcode/DerivedData" + df -H + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: ${{ steps.runtime.outputs.runtime }} + - name: devbox installer + uses: jetify-com/devbox-install-action@v0.14.0 + with: + project-path: ${{ inputs.devbox_config }} + enable-cache: 'false' + - name: iOS E2E Tests + run: devbox run --config=${{ inputs.devbox_config }} test-ios + env: + TARGET_SDK: ${{ inputs.target }} + IOS_RUNTIME_MIN: ${{ steps.runtime.outputs.runtime_min }} + IOS_RUNTIME_MAX: ${{ steps.runtime.outputs.runtime_max }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8c5d19c9b..3088a6068 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -24,11 +24,6 @@ jobs: e2e-ios: name: E2E iOS (min/max) - runs-on: macos-26 - env: - ANALYTICS_CI_DEBUG: "1" - YARN_ENABLE_HARDENED_MODE: 0 - XCODE_VERSION: '26.2' strategy: matrix: include: @@ -36,42 +31,13 @@ jobs: target: min - name: ios-latest target: max - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (macOS) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "/usr/local/share/boost" - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /Applications/Android\ Studio.app - sudo rm -rf /usr/local/share/miniconda - sudo rm -rf /opt/homebrew - sudo rm -rf "$HOME/Library/Android" - sudo rm -rf "$HOME/.gradle" - sudo rm -rf "$HOME/Library/Developer/CoreSimulator/Devices" - sudo rm -rf "$HOME/Library/Developer/Xcode/DerivedData" - df -H - - uses: maxim-lobanov/setup-xcode@v1 - with: - xcode-version: '26.2' - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/ios/devbox.json - enable-cache: 'false' - - name: iOS E2E Tests - run: devbox run --config=shells/ios/devbox.json test-ios - env: - TARGET_SDK: ${{ matrix.target }} + uses: ./.github/workflows/ios-e2e.yml + with: + target: ${{ matrix.target }} + secrets: inherit e2e-android: name: E2E Android (min/max) - runs-on: ubuntu-latest - env: - ANALYTICS_CI_DEBUG: "1" - EMU_HEADLESS: 1 - AVD_ABI: x86_64 strategy: matrix: include: @@ -79,31 +45,10 @@ jobs: target: min - name: android-latest target: max - steps: - - uses: actions/checkout@v4 - - name: Aggressive disk cleanup (Ubuntu) - run: | - sudo rm -rf /usr/share/dotnet - sudo rm -rf /opt/ghc - sudo rm -rf "$AGENT_TOOLSDIRECTORY" - sudo rm -rf /opt/hostedtoolcache/CodeQL - sudo rm -rf /usr/local/lib/android - sudo rm -rf /usr/local/lib/node_modules - sudo rm -rf /usr/local/share/boost - sudo rm -rf /usr/local/share/chromium - sudo rm -rf /usr/local/share/powershell - sudo rm -rf /usr/local/share/edge_driver - sudo rm -rf /usr/local/share/gecko_driver - sudo rm -rf /usr/local/share/phantomjs - sudo rm -rf "$HOME/.cache" - df -H - - name: devbox installer - uses: jetify-com/devbox-install-action@v0.14.0 - with: - project-path: shells/android-${{ matrix.target }}/devbox.json - enable-cache: 'false' - - name: Android E2E Tests - run: devbox run --config=shells/android-${{ matrix.target }}/devbox.json test-android + uses: ./.github/workflows/android-e2e.yml + with: + target: ${{ matrix.target }} + secrets: inherit publish: name: Publish to npm diff --git a/devbox.json b/devbox.json index 6093f8a1d..938f5163e 100644 --- a/devbox.json +++ b/devbox.json @@ -13,8 +13,13 @@ "gradle": "latest", "jq": "latest", "netcat": "latest", - "path:./nix#android-sdk": "", - "path:./nix#android-sdk-max": "" + "act": "latest", + "path:./nix#android-sdk": "" + }, + "env": { + "ANDROID_CUSTOM_API": "29", + "ANDROID_CUSTOM_DEVICE": "pixel_6", + "IOS_CUSTOM_DEVICE": "iPhone 15" }, "shell": { "init_hook": [ @@ -34,9 +39,6 @@ "lint": ["treefmt --fail-on-change"], "test-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android test"], "test-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios test"], - "act": [ - "sh $DEVBOX_PROJECT_ROOT/scripts/run.sh act ci-fast --platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" - ], "setup-android": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android setup"], "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh ios setup"], "start-emulator": ["sh $DEVBOX_PROJECT_ROOT/scripts/run.sh android start"], diff --git a/devbox.lock b/devbox.lock index 81129d34f..e15917805 100644 --- a/devbox.lock +++ b/devbox.lock @@ -1,9 +1,57 @@ { "lockfile_version": "1", "packages": { + "act@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#act", + "source": "devbox-search", + "version": "0.2.84", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/60fx8ffpxxfl7chps435jz0yy40bgz7z-act-0.2.84", + "default": true + } + ], + "store_path": "/nix/store/60fx8ffpxxfl7chps435jz0yy40bgz7z-act-0.2.84" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jrbdrlv46d8jglg30v078ncxmmc7rfrj-act-0.2.84", + "default": true + } + ], + "store_path": "/nix/store/jrbdrlv46d8jglg30v078ncxmmc7rfrj-act-0.2.84" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/j49qnbhrsi7qhw4jn9852f818nxmmj9r-act-0.2.84", + "default": true + } + ], + "store_path": "/nix/store/j49qnbhrsi7qhw4jn9852f818nxmmj9r-act-0.2.84" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/29dp2s13wyawgm1m5kvsl8n4mh107h8r-act-0.2.84", + "default": true + } + ], + "store_path": "/nix/store/29dp2s13wyawgm1m5kvsl8n4mh107h8r-act-0.2.84" + } + } + }, "cocoapods@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#cocoapods", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#cocoapods", "source": "devbox-search", "version": "1.16.2", "systems": { @@ -11,21 +59,21 @@ "outputs": [ { "name": "out", - "path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2", + "path": "/nix/store/xmpbzlm4h97izn0nwf5r3flxa3hqiawa-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2" + "store_path": "/nix/store/xmpbzlm4h97izn0nwf5r3flxa3hqiawa-cocoapods-1.16.2" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2", + "path": "/nix/store/kk994ybb09jk38n2k2sp5mifgka5mixg-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2" + "store_path": "/nix/store/kk994ybb09jk38n2k2sp5mifgka5mixg-cocoapods-1.16.2" } } }, @@ -34,51 +82,51 @@ "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, "gradle@latest": { - "last_modified": "2025-12-31T03:27:36Z", + "last_modified": "2026-01-26T09:54:05Z", "plugin_version": "0.0.1", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#gradle", + "resolved": "github:NixOS/nixpkgs/5b265bda51b42a2a85af0a543c3e57b778b01b7d#gradle", "source": "devbox-search", - "version": "8.14.3", + "version": "8.14.4", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3", + "path": "/nix/store/yb98qaa8if1gvdihj9vngyv822kqs88v-gradle-8.14.4", "default": true } ], - "store_path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3" + "store_path": "/nix/store/yb98qaa8if1gvdihj9vngyv822kqs88v-gradle-8.14.4" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3", + "path": "/nix/store/xbn16nkgbaj09mf3vgzs7y582m67bm9s-gradle-8.14.4", "default": true } ], - "store_path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3" + "store_path": "/nix/store/xbn16nkgbaj09mf3vgzs7y582m67bm9s-gradle-8.14.4" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3", + "path": "/nix/store/m0xaca5z53sg9n6jqlkvm6cq0cn7ny28-gradle-8.14.4", "default": true } ], - "store_path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3" + "store_path": "/nix/store/m0xaca5z53sg9n6jqlkvm6cq0cn7ny28-gradle-8.14.4" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3", + "path": "/nix/store/7nhijwwp2cdwnj2f19c5qdp2igf6cqb9-gradle-8.14.4", "default": true } ], - "store_path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3" + "store_path": "/nix/store/7nhijwwp2cdwnj2f19c5qdp2igf6cqb9-gradle-8.14.4" } } }, @@ -111,8 +159,8 @@ } }, "jq@latest": { - "last_modified": "2026-01-12T00:44:08Z", - "resolved": "github:NixOS/nixpkgs/3fbab70c6e69c87ea2b6e48aa6629da2aa6a23b0#jq", + "last_modified": "2026-01-26T13:12:53Z", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#jq", "source": "devbox-search", "version": "1.8.1", "systems": { @@ -120,115 +168,115 @@ "outputs": [ { "name": "bin", - "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/jlpyybc7pdh4gk17dc266d6a1szm7dk6-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/bhryp10d5w5h9rsav5k9m9jb55z26bsl-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/238sn0gg3i3i9v6kgx4g1k6b19frzy49-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/n64h0247s3674kry90l6kszx06zyrgfn-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/2pjwv0ab8nilrg1lvjazf9y9w6g6pk5y-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "path": "/nix/store/2sy4y09ddbi64pbg4is078110z70jsdw-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "path": "/nix/store/vx81xggapqwdd2l64mmxrkbafih461jc-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "path": "/nix/store/cfhajjz1k7gf31krbj18q9acb54xp5z9-jq-1.8.1" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/vx840ik1sj1h8fhqwa40aglvrgpa0r18-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/bmg2xfw86wavg7fm062nyf6v48xzxh0j-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/pp2hrljvalrrwyxh7is69nnlmxb2m7lk-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/h05xaf7fsasgp8cpyar2195cc8lbgih8-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/6mh88qsh57ivh31c5nqxc43n0hv9xhbk-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/d73i1fvhrqms0sbfrvqaynsr8iva216v-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/3ynrp4ypwv1g1jgsk638443p8lpd9g8f-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/fgsvqffyvcpjqs093wwf2d6dzxnmnqnv-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin" } } }, "netcat@latest": { - "last_modified": "2026-01-20T02:11:35Z", - "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#netcat", + "last_modified": "2026-01-24T15:20:28Z", + "resolved": "github:NixOS/nixpkgs/ab9fbbcf4858bd6d40ba2bbec37ceb4ab6e1f562#netcat", "source": "devbox-search", "version": "4.2.1", "systems": { @@ -236,119 +284,119 @@ "outputs": [ { "name": "nc", - "path": "/nix/store/y2i4f3bwmgpxw4m6dl99dz9d7zp5axz2-libressl-4.2.1-nc", + "path": "/nix/store/gvknval1kw4gcwiihh61zck3qiz6qa5c-libressl-4.2.1-nc", "default": true }, { "name": "bin", - "path": "/nix/store/ycvwxl29jb6ajjzgkq2jgy1nqpahq5k4-libressl-4.2.1-bin", + "path": "/nix/store/27px9spniwk94lzkh3vbs0sxsbszlb55-libressl-4.2.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/2b61bckfnaiw3n5ppjg70avgd9rn60bp-libressl-4.2.1-man", + "path": "/nix/store/65l6sf3drz0j5zrjllwbf86lbpnh3206-libressl-4.2.1-man", "default": true }, { - "name": "out", - "path": "/nix/store/fm6zdqw6856i2snd4fikcsi9d1qagj5j-libressl-4.2.1" + "name": "dev", + "path": "/nix/store/9l41sz77w2am5svwv9bzkj3r77l7faa4-libressl-4.2.1-dev" }, { - "name": "dev", - "path": "/nix/store/bz5h2baa7bkpz8sgjc9ld8fr7cg5wapg-libressl-4.2.1-dev" + "name": "out", + "path": "/nix/store/209fqqlykqgvbmhqkxns8hxf661kvggr-libressl-4.2.1" } ], - "store_path": "/nix/store/y2i4f3bwmgpxw4m6dl99dz9d7zp5axz2-libressl-4.2.1-nc" + "store_path": "/nix/store/gvknval1kw4gcwiihh61zck3qiz6qa5c-libressl-4.2.1-nc" }, "aarch64-linux": { "outputs": [ { "name": "nc", - "path": "/nix/store/0dzxkwilv9lgd7j0429s2rmshy7p8gw7-libressl-4.2.1-nc", + "path": "/nix/store/5i8jpl10mgy8yy14ab3wcw96dknhcd52-libressl-4.2.1-nc", "default": true }, { "name": "bin", - "path": "/nix/store/5ama6wp3yi03hbixdcm5jy2ya9ikvzjz-libressl-4.2.1-bin", + "path": "/nix/store/xzmdycii4k6rxcb3pf6b7c6r0m8q6giq-libressl-4.2.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/vr4wlcvj5ba6wdmhj2aidalzqk33lrph-libressl-4.2.1-man", + "path": "/nix/store/nmngfbi6bxxcif5x450fqkixjrf9ajjz-libressl-4.2.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/hs5c0yvhf7n60xijr7bmpi592n45pb6i-libressl-4.2.1-dev" + "name": "out", + "path": "/nix/store/dmingcfvh3bqh1lz9f0b4wz0lyqg22p6-libressl-4.2.1" }, { - "name": "out", - "path": "/nix/store/fiy9987ph2kqr5drlr136w7hvm3v6rvg-libressl-4.2.1" + "name": "dev", + "path": "/nix/store/8jdkrf3bpb3v4pv6knnkfz9yny3pmsyp-libressl-4.2.1-dev" } ], - "store_path": "/nix/store/0dzxkwilv9lgd7j0429s2rmshy7p8gw7-libressl-4.2.1-nc" + "store_path": "/nix/store/5i8jpl10mgy8yy14ab3wcw96dknhcd52-libressl-4.2.1-nc" }, "x86_64-darwin": { "outputs": [ { "name": "nc", - "path": "/nix/store/vmrm6nr9hfhw7x8ln3ms98gszq709bfa-libressl-4.2.1-nc", + "path": "/nix/store/73gpj7z4j7xqvjbbsv3c9pnh37pxaysp-libressl-4.2.1-nc", "default": true }, { "name": "bin", - "path": "/nix/store/7kafgvpwc6s8pnzar90bd8017wc3cnvx-libressl-4.2.1-bin", + "path": "/nix/store/c41c038h81hma6y17xzm4ih70ayz0jw1-libressl-4.2.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/jwdgv2x1a2a84v2jkj964xvm2s0kymps-libressl-4.2.1-man", + "path": "/nix/store/dv4bd93ia2sd2ppydggh7s5jvng7w2ln-libressl-4.2.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/sjiz0iphbc7dvddlrbrk8k7kkqi3swz3-libressl-4.2.1-dev" + "path": "/nix/store/a98pxfnpxmk8hdfxcfyhvd4lrj91s7zj-libressl-4.2.1-dev" }, { "name": "out", - "path": "/nix/store/rn10w2jbdkz3f7p1q1fl6aml9b0352ki-libressl-4.2.1" + "path": "/nix/store/klv7jfk255vbrs29znh3r88zb7fy7ywn-libressl-4.2.1" } ], - "store_path": "/nix/store/vmrm6nr9hfhw7x8ln3ms98gszq709bfa-libressl-4.2.1-nc" + "store_path": "/nix/store/73gpj7z4j7xqvjbbsv3c9pnh37pxaysp-libressl-4.2.1-nc" }, "x86_64-linux": { "outputs": [ { "name": "nc", - "path": "/nix/store/54hijwy3gpc728s3468rv3sdw78ksakh-libressl-4.2.1-nc", + "path": "/nix/store/n17al8mklxgzp888406yyfi2wqf49bam-libressl-4.2.1-nc", "default": true }, { "name": "bin", - "path": "/nix/store/l5vvbs0vl734mshifahals0054pimlx4-libressl-4.2.1-bin", + "path": "/nix/store/jhg0gcahxc6yqc156fc1hkqi0ps6f705-libressl-4.2.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/j26qyc85gk95bk06dq0fi0c9q8y7livx-libressl-4.2.1-man", + "path": "/nix/store/a4slaj05ph1m0vdb9vsw16mc24za8n4d-libressl-4.2.1-man", "default": true }, { - "name": "out", - "path": "/nix/store/4f21prki98shrvp29r88pnxhzw2y4qr2-libressl-4.2.1" + "name": "dev", + "path": "/nix/store/la1ilprnsj96dlaara2nk45lcd29f0as-libressl-4.2.1-dev" }, { - "name": "dev", - "path": "/nix/store/0dndzgjzx25y7v1942c2rys20narddp8-libressl-4.2.1-dev" + "name": "out", + "path": "/nix/store/x03afgp2cbxb6xmxs3i716wfq7zbgfdn-libressl-4.2.1" } ], - "store_path": "/nix/store/54hijwy3gpc728s3468rv3sdw78ksakh-libressl-4.2.1-nc" + "store_path": "/nix/store/n17al8mklxgzp888406yyfi2wqf49bam-libressl-4.2.1-nc" } } }, "nixfmt@latest": { - "last_modified": "2026-01-09T13:41:53Z", - "resolved": "github:NixOS/nixpkgs/5f02c91314c8ba4afe83b256b023756412218535#nixfmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#nixfmt", "source": "devbox-search", "version": "1.2.0", "systems": { @@ -356,47 +404,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0", + "path": "/nix/store/lvb2z93xn3m0m2hw0w6cc0c3bsl2s8pp-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0" + "store_path": "/nix/store/lvb2z93xn3m0m2hw0w6cc0c3bsl2s8pp-nixfmt-1.2.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0", + "path": "/nix/store/0qdx7ah7b1dwyxa03fblhcdjnpi29q25-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0" + "store_path": "/nix/store/0qdx7ah7b1dwyxa03fblhcdjnpi29q25-nixfmt-1.2.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0", + "path": "/nix/store/jicz2kx49mqif3hkl1m2wbwvx2lg457l-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0" + "store_path": "/nix/store/jicz2kx49mqif3hkl1m2wbwvx2lg457l-nixfmt-1.2.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0", + "path": "/nix/store/b5m1h822ln0s493r30sgns77618ws59n-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0" + "store_path": "/nix/store/b5m1h822ln0s493r30sgns77618ws59n-nixfmt-1.2.0" } } }, "shfmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#shfmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#shfmt", "source": "devbox-search", "version": "3.12.0", "systems": { @@ -404,47 +452,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0", + "path": "/nix/store/5ywb1qkbd829kazxxkcfxb356m7hljjw-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0" + "store_path": "/nix/store/5ywb1qkbd829kazxxkcfxb356m7hljjw-shfmt-3.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0", + "path": "/nix/store/bii41pz9k7xf3z3f80s1ip29l42488ry-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0" + "store_path": "/nix/store/bii41pz9k7xf3z3f80s1ip29l42488ry-shfmt-3.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0", + "path": "/nix/store/a8l3l8rdzs3agq7garh59m0xn8h3zgpq-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0" + "store_path": "/nix/store/a8l3l8rdzs3agq7garh59m0xn8h3zgpq-shfmt-3.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0", + "path": "/nix/store/r3pj36ll7v3ss2z679arpwkg7pnka3s3-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0" + "store_path": "/nix/store/r3pj36ll7v3ss2z679arpwkg7pnka3s3-shfmt-3.12.0" } } }, "treefmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#treefmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#treefmt", "source": "devbox-search", "version": "2.4.0", "systems": { @@ -452,47 +500,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0", + "path": "/nix/store/37qcrdrfdf8b9pyli0j0vj9d69dykmpr-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0" + "store_path": "/nix/store/37qcrdrfdf8b9pyli0j0vj9d69dykmpr-treefmt-2.4.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0", + "path": "/nix/store/ccv7dxwff3xpivsdhrjbq3mpk0br5v7d-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0" + "store_path": "/nix/store/ccv7dxwff3xpivsdhrjbq3mpk0br5v7d-treefmt-2.4.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0", + "path": "/nix/store/sbq2psv4q9hvfvalk00g0pkqjl2912m1-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0" + "store_path": "/nix/store/sbq2psv4q9hvfvalk00g0pkqjl2912m1-treefmt-2.4.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0", + "path": "/nix/store/z8xrjfswqqpydc42lyas064pp8kxgnl0-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0" + "store_path": "/nix/store/z8xrjfswqqpydc42lyas064pp8kxgnl0-treefmt-2.4.0" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#yarn-berry", "source": "devbox-search", "version": "4.12.0", "systems": { @@ -500,41 +548,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0" } } } diff --git a/nix/defaults.json b/nix/defaults.json index 2c64b14b0..69597468a 100644 --- a/nix/defaults.json +++ b/nix/defaults.json @@ -3,6 +3,7 @@ "ANDROID_SDK_USE_LOCAL": "0", "ANDROID_MIN_API": "21", "ANDROID_MAX_API": "33", + "ANDROID_CUSTOM_API": "29", "ANDROID_SYSTEM_IMAGE_TAG": "google_apis", "ANDROID_BUILD_TOOLS_VERSION": "30.0.3", "ANDROID_CMDLINE_TOOLS_VERSION": "19.0", @@ -10,8 +11,8 @@ "ANDROID_MAX_DEVICE": "medium_phone", "ANALYTICS_CI_DEBUG": "0", "DEBUG": "0", - "IOS_MIN_VERSION": "15.0", - "IOS_MAX_VERSION": "26.2", + "IOS_RUNTIME_MIN": "15.5", + "IOS_RUNTIME_MAX": "26.2", "IOS_MIN_DEVICE": "iPhone 13", "IOS_MAX_DEVICE": "iPhone 17" } diff --git a/nix/flake.nix b/nix/flake.nix index a4ed0cad0..0802c8823 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -20,10 +20,17 @@ if builtins.hasAttr name defaultsData then toString (builtins.getAttr name defaultsData) else builtins.throw "Missing required default in nix/defaults.json: ${name}"; + unique = + list: + builtins.foldl' ( + acc: item: if builtins.elem item acc then acc else acc ++ [ item ] + ) [ ] list; + androidSdkConfig = { - platformVersions = [ + platformVersions = unique [ (getVar "ANDROID_MIN_API") (getVar "ANDROID_MAX_API") + (getVar "ANDROID_CUSTOM_API") ]; buildToolsVersion = getVar "ANDROID_BUILD_TOOLS_VERSION"; cmdLineToolsVersion = getVar "ANDROID_CMDLINE_TOOLS_VERSION"; @@ -35,6 +42,9 @@ androidSdkConfigMax = androidSdkConfig // { platformVersions = [ (getVar "ANDROID_MAX_API") ]; }; + androidSdkConfigCustom = androidSdkConfig // { + platformVersions = [ (getVar "ANDROID_CUSTOM_API") ]; + }; forAllSystems = f: @@ -77,6 +87,7 @@ android-sdk = (androidPkgs androidSdkConfig).androidsdk; android-sdk-min = (androidPkgs androidSdkConfigMin).androidsdk; android-sdk-max = (androidPkgs androidSdkConfigMax).androidsdk; + android-sdk-custom = (androidPkgs androidSdkConfigCustom).androidsdk; default = (androidPkgs androidSdkConfig).androidsdk; } ); diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 216b5576b..e43d3b80a 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -7,7 +7,7 @@ if ! (return 0 2>/dev/null); then fi script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${SHARED_LOADED:-}" ]; then +if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then init_path="$script_dir/../env.sh" if [ ! -f "$init_path" ]; then repo_root="" @@ -398,7 +398,25 @@ android_stop() { } android_reset() { - rm -rf "$HOME/.android/avd" - rm -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub" + rm_bin="rm" + if [ "$(uname -s)" = "Darwin" ] && [ -x /bin/rm ]; then + rm_bin="/bin/rm" + fi + avd_dir="$HOME/.android/avd" + if [ -d "$avd_dir" ]; then + if command -v chflags >/dev/null 2>&1; then + chflags -R nouchg "$avd_dir" >/dev/null 2>&1 || true + fi + chmod -R u+w "$avd_dir" >/dev/null 2>&1 || true + if ! "$rm_bin" -rf "$avd_dir"; then + echo "Failed to remove $avd_dir. Check permissions or Full Disk Access for your terminal." >&2 + return 1 + fi + fi + + if ! "$rm_bin" -f "$HOME/.android/adbkey" "$HOME/.android/adbkey.pub"; then + echo "Failed to remove adb keys under $HOME/.android. Check permissions." >&2 + return 1 + fi echo "AVDs and adb keys removed. Recreate via start-android* as needed." } diff --git a/scripts/android/env.sh b/scripts/android/env.sh index 959d108ce..dd512a9e2 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -12,7 +12,7 @@ if [ -z "$project_root" ]; then project_root="$(cd "$(dirname "$0")/../.." && pwd)" fi script_dir="$project_root/scripts/android" -if [ -z "${SHARED_LOADED:-}" ]; then +if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then # shellcheck disable=SC1090 . "$project_root/scripts/env.sh" fi @@ -66,6 +66,13 @@ if [ -n "$prefer_local" ]; then fi else preferred_output="${ANDROID_SDK_FLAKE_OUTPUT:-}" + if [ -z "$preferred_output" ]; then + case "${TARGET_SDK:-max}" in + min) preferred_output="android-sdk-min" ;; + custom) preferred_output="android-sdk-custom" ;; + *) preferred_output="android-sdk-max" ;; + esac + fi sdk_root_max="" sdk_root_min="" @@ -118,7 +125,7 @@ fi export ANDROID_SDK_ROOT ANDROID_HOME export ANDROID_BUILD_TOOLS_VERSION ANDROID_ENV_LOADED=1 -export ANDROID_ENV_LOADED +ANDROID_ENV_LOADED_PID="$$" if [ -n "${ANDROID_SDK_ROOT:-}" ]; then # Prefer cmdline-tools;latest, or fall back to the highest numbered cmdline-tools folder. diff --git a/scripts/env.sh b/scripts/env.sh index 56269050b..e14dde3bb 100644 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -5,6 +5,12 @@ if ! (return 0 2>/dev/null); then exit 1 fi +if [ "${ENV_SH_LOADED:-}" = "1" ] && [ "${ENV_SH_LOADED_PID:-}" = "$$" ]; then + return 0 2>/dev/null || exit 0 +fi +ENV_SH_LOADED=1 +ENV_SH_LOADED_PID="$$" + script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="" if command -v git >/dev/null 2>&1; then @@ -42,4 +48,4 @@ if [ "${INIT_IOS:-}" = "1" ] && [ "$(uname -s)" = "Darwin" ]; then fi SHARED_LOADED=1 -export SHARED_LOADED +SHARED_LOADED_PID="$$" diff --git a/scripts/ios/actions.sh b/scripts/ios/actions.sh index 726af90d0..42be577e3 100644 --- a/scripts/ios/actions.sh +++ b/scripts/ios/actions.sh @@ -37,33 +37,54 @@ ios_run() { case "$action" in start) target_sdk="${TARGET_SDK:-max}" + runtime_version="" if [ "$target_sdk" = "custom" ]; then if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then echo "TARGET_SDK=custom requires IOS_CUSTOM_DEVICE to be set." >&2 exit 1 fi - if [ -n "${IOS_CUSTOM_VERSION:-}" ]; then - IOS_RUNTIME="${IOS_CUSTOM_VERSION}" - export IOS_RUNTIME - fi + runtime_version="${IOS_RUNTIME_CUSTOM:-}" IOS_DEVICE_NAMES="${IOS_CUSTOM_DEVICE}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_CUSTOM_DEVICE}}" elif [ "$target_sdk" = "min" ]; then + runtime_version="${IOS_RUNTIME_MIN:-}" IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-iPhone 13}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-iPhone 13}}" else + runtime_version="${IOS_RUNTIME_MAX:-}" IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" fi export IOS_DEVICE_NAMES DETOX_IOS_DEVICE + if [ -n "$runtime_version" ]; then + if ! resolve_runtime_name_strict "$runtime_version"; then + exit 1 + fi + IOS_RUNTIME="$runtime_version" + export IOS_RUNTIME + fi ios_setup sim_device="${DETOX_IOS_DEVICE}" - if ! xcrun simctl list devices | grep -q "${sim_device}"; then + runtime_name="$(resolve_runtime_name "${runtime_version:-}" || true)" + display_name="$sim_device" + if [ -n "$runtime_name" ]; then + display_name="${sim_device} (${runtime_name})" + fi + + sim_udid="$(existing_device_udid_any_runtime "$display_name")" + if [ -z "$sim_udid" ]; then + sim_udid="$(existing_device_udid_any_runtime "$sim_device")" + fi + if [ -z "$sim_udid" ]; then + ensure_device "$sim_device" "${runtime_version:-}" + sim_udid="$(existing_device_udid_any_runtime "$display_name")" + fi + if [ -z "$sim_udid" ]; then echo "Simulator ${sim_device} not found; ensure setup-ios created it." >&2 exit 1 fi - echo "Starting iOS simulator: ${sim_device} (runtime ${IOS_RUNTIME:-})" - xcrun simctl boot "$sim_device" || true + echo "Starting iOS simulator: ${sim_device} (runtime ${runtime_version:-})" + xcrun simctl boot "$sim_udid" || true if [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ]; then open -a Simulator fi diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index 95c143844..d7febe029 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -7,7 +7,7 @@ fi set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${SHARED_LOADED:-}" ]; then +if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then init_path="$script_dir/../env.sh" if [ ! -f "$init_path" ]; then repo_root="" @@ -98,7 +98,7 @@ devbox_omit_nix_env() { devbox_omit_nix_env IOS_ENV_LOADED=1 -export IOS_ENV_LOADED +IOS_ENV_LOADED_PID="$$" if debug_enabled; then if [ "${IOS_ENV_DEBUG_PRINTED:-}" != "1" ]; then @@ -106,8 +106,9 @@ if debug_enabled; then export IOS_ENV_DEBUG_PRINTED debug_dump_vars \ IOS_RUNTIME \ - IOS_MIN_VERSION \ - IOS_MAX_VERSION \ + IOS_RUNTIME_MIN \ + IOS_RUNTIME_MAX \ + IOS_RUNTIME_CUSTOM \ IOS_DEVICE_NAMES \ DETOX_IOS_DEVICE \ IOS_DEVELOPER_DIR \ @@ -146,15 +147,10 @@ if [ -n "${INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && repo_root="$(cd "$(dirname "$0")/../.." && pwd)" fi - ios_min_version="${IOS_MIN_VERSION:-}" - ios_max_version="${IOS_MAX_VERSION:-}" - ios_runtime="${IOS_RUNTIME:-}" + ios_runtime="${IOS_RUNTIME_MAX:-}" if [ -z "$ios_runtime" ] && command -v xcrun >/dev/null 2>&1; then ios_runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" fi - if [ -z "$ios_max_version" ]; then - ios_max_version="$ios_runtime" - fi xcode_dir="${DEVELOPER_DIR:-}" if [ -z "$xcode_dir" ] && command -v xcode-select >/dev/null 2>&1; then @@ -167,8 +163,8 @@ if [ -n "${INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && fi echo "Resolved iOS SDK" - echo " IOS_MIN_VERSION: ${ios_min_version:-not set}" - echo " IOS_MAX_VERSION: ${ios_max_version:-not set}" + echo " IOS_RUNTIME_MIN: ${IOS_RUNTIME_MIN:-not set}" + echo " IOS_RUNTIME_MAX: ${IOS_RUNTIME_MAX:-not set}" echo " IOS_RUNTIME: ${ios_runtime:-not set}" echo " xcodebuild: ${xcode_version:-unknown}" echo " DEVELOPER_DIR: ${xcode_dir:-not set}" diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index e2eac700d..5fc648b67 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -7,7 +7,7 @@ if ! (return 0 2>/dev/null); then fi script_dir="$(cd "$(dirname "$0")" && pwd)" -if [ -z "${SHARED_LOADED:-}" ]; then +if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then init_path="$script_dir/../env.sh" if [ ! -f "$init_path" ]; then repo_root="" @@ -84,6 +84,49 @@ resolve_runtime() { pick_runtime "$preferred" } +resolve_runtime_strict() { + preferred="$1" + if choice="$(pick_runtime "$preferred")"; then + printf '%s\n' "$choice" + return 0 + fi + + if [ "${IOS_DOWNLOAD_RUNTIME:-1}" != "0" ] && command -v xcodebuild >/dev/null 2>&1; then + echo "Preferred runtime iOS ${preferred} not found. Attempting to download via xcodebuild -downloadPlatform iOS..." >&2 + if xcodebuild -downloadPlatform iOS; then + if choice="$(pick_runtime "$preferred")"; then + printf '%s\n' "$choice" + return 0 + fi + else + echo "xcodebuild -downloadPlatform iOS failed." >&2 + fi + fi + + echo "Preferred runtime iOS ${preferred} not found." >&2 + return 1 +} + +resolve_runtime_name() { + preferred="$1" + choice="$(resolve_runtime "$preferred" || true)" + if [ -n "$choice" ]; then + printf '%s\n' "$choice" | cut -d'|' -f2 + return 0 + fi + return 1 +} + +resolve_runtime_name_strict() { + preferred="$1" + choice="$(resolve_runtime_strict "$preferred" || true)" + if [ -n "$choice" ]; then + printf '%s\n' "$choice" | cut -d'|' -f2 + return 0 + fi + return 1 +} + existing_device_udid_any_runtime() { name="$1" xcrun simctl list devices -j | jq -r --arg name "$name" '.devices[]?[]? | select(.name == $name) | .udid' | head -n1 @@ -195,7 +238,7 @@ ios_setup() { return 1 fi devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" - runtime="${IOS_RUNTIME:-}" + runtime="${IOS_RUNTIME:-${IOS_RUNTIME_MAX:-}}" if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" fi diff --git a/scripts/run.sh b/scripts/run.sh index 3697201c0..7c5f6e771 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -3,6 +3,13 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" +if [ "${RUN_SH_ACTIVE:-}" = "1" ]; then + echo "scripts/run.sh is already running." >&2 + exit 1 +fi +RUN_SH_ACTIVE=1 +export RUN_SH_ACTIVE + init_path="$script_dir/env.sh" if [ ! -f "$init_path" ]; then repo_root="" @@ -29,66 +36,6 @@ run_build() { yarn lint } -run_act() { - workflow="${1:-}" - if [ -n "$workflow" ] && [ "${workflow#-}" = "$workflow" ]; then - shift 1 - case "$workflow" in - *.yml | *.yaml) - workflow_path="$workflow" - ;; - *) - workflow_path=".github/workflows/${workflow}.yml" - ;; - esac - else - workflow="" - workflow_path="" - fi - - JOB="" - PLATFORMS="" - - host_arch="$(uname -m)" - if [ "$host_arch" = "arm64" ] || [ "$host_arch" = "aarch64" ]; then - PLATFORMS="ubuntu-24.04-arm=ghcr.io/catthehacker/ubuntu:act-24.04" - else - PLATFORMS="ubuntu-24.04=ghcr.io/catthehacker/ubuntu:act-24.04" - fi - PLATFORMS="$PLATFORMS ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-24.04" - - while [ $# -gt 0 ]; do - case "$1" in - -j | --job) - JOB="$2" - shift 2 - ;; - -p | --platform) - PLATFORMS="$PLATFORMS $2" - shift 2 - ;; - *) - echo "Unknown option: $1" >&2 - exit 1 - ;; - esac - done - - set -- act --pull=false - if [ -n "$workflow_path" ]; then - set -- "$@" -W "$workflow_path" - fi - for platform in $PLATFORMS; do - set -- "$@" --platform "$platform" - done - set -- "$@" --input ACT=true - if [ -n "$JOB" ]; then - set -- "$@" --job "$JOB" - fi - - printf 'Running: %s\n' "$*" - exec "$@" -} case "$platform" in android) @@ -104,11 +51,8 @@ case "$platform" in build) run_build "$@" ;; - act) - run_act "$@" - ;; *) - echo "Usage: run.sh {android|ios} [args] | run.sh build | run.sh act [args]" >&2 + echo "Usage: run.sh {android|ios} [args] | run.sh build" >&2 exit 1 ;; esac diff --git a/scripts/shared/debug.sh b/scripts/shared/debug.sh index ddd568b37..9d8bed8ef 100644 --- a/scripts/shared/debug.sh +++ b/scripts/shared/debug.sh @@ -4,6 +4,12 @@ if ! (return 0 2>/dev/null); then echo "scripts/shared/debug.sh must be sourced." >&2 exit 1 fi + +if [ "${DEBUG_SH_LOADED:-}" = "1" ] && [ "${DEBUG_SH_LOADED_PID:-}" = "$$" ]; then + return 0 2>/dev/null || exit 0 +fi +DEBUG_SH_LOADED=1 +DEBUG_SH_LOADED_PID="$$" set -eu debug_enabled() { diff --git a/scripts/shared/defaults.sh b/scripts/shared/defaults.sh index a1dae45dc..e737fd07d 100644 --- a/scripts/shared/defaults.sh +++ b/scripts/shared/defaults.sh @@ -5,7 +5,13 @@ if ! (return 0 2>/dev/null); then exit 1 fi -if [ "${ENV_DEFAULTS_LOADED:-}" = "1" ]; then +if [ "${DEFAULTS_SH_LOADED:-}" = "1" ] && [ "${DEFAULTS_SH_LOADED_PID:-}" = "$$" ]; then + return 0 2>/dev/null || exit 0 +fi +DEFAULTS_SH_LOADED=1 +DEFAULTS_SH_LOADED_PID="$$" + +if [ "${ENV_DEFAULTS_LOADED:-}" = "1" ] && [ "${ENV_DEFAULTS_LOADED_PID:-}" = "$$" ]; then return 0 2>/dev/null || exit 0 fi @@ -34,4 +40,4 @@ EOF fi ENV_DEFAULTS_LOADED=1 -export ENV_DEFAULTS_LOADED +ENV_DEFAULTS_LOADED_PID="$$" diff --git a/scripts/shared/project.sh b/scripts/shared/project.sh index 0e0260fba..546641ad2 100644 --- a/scripts/shared/project.sh +++ b/scripts/shared/project.sh @@ -5,6 +5,12 @@ if ! (return 0 2>/dev/null); then exit 1 fi +if [ "${PROJECT_SH_LOADED:-}" = "1" ] && [ "${PROJECT_SH_LOADED_PID:-}" = "$$" ]; then + return 0 2>/dev/null || exit 0 +fi +PROJECT_SH_LOADED=1 +PROJECT_SH_LOADED_PID="$$" + ensure_project_root() { if [ -n "${PROJECT_ROOT:-}" ]; then return 0 diff --git a/scripts/shared/tools.sh b/scripts/shared/tools.sh index 64b503238..e79308d64 100644 --- a/scripts/shared/tools.sh +++ b/scripts/shared/tools.sh @@ -5,6 +5,12 @@ if ! (return 0 2>/dev/null); then exit 1 fi +if [ "${TOOLS_SH_LOADED:-}" = "1" ] && [ "${TOOLS_SH_LOADED_PID:-}" = "$$" ]; then + return 0 2>/dev/null || exit 0 +fi +TOOLS_SH_LOADED=1 +TOOLS_SH_LOADED_PID="$$" + require_tool() { tool="$1" message="${2:-Missing required tool: $tool. Ensure devbox shell is active and required packages are installed.}" diff --git a/wiki/devbox.md b/wiki/devbox.md index b181ab262..928494333 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -15,6 +15,9 @@ Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_SDK_USE_LOCAL=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_SDK_USE_LOCAL` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/avd.sh`). Version sources are documented in `wiki/nix.md`. +Example custom targets (root `devbox.json` sets these via `shell.env` for testing): +`ANDROID_CUSTOM_API=29` `ANDROID_CUSTOM_DEVICE=pixel_6` `IOS_CUSTOM_DEVICE="iPhone 15"` + ### Emulator/AVD scripts - `devbox run start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. @@ -57,7 +60,7 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Common env knobs - Android: `TARGET_SDK` (min/max), `DETOX_AVD` (explicit AVD name), `AVD_NAME` (explicit AVD name for create + start), `EMU_HEADLESS` (1 for headless), `EMU_PORT` (emulator port/serial), `ANDROID_BUILD_TOOLS_VERSION` (override build-tools). -- iOS: `TARGET_SDK` (min/max/custom), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_RUNTIME` (preferred runtime), `IOS_DEVICE_NAMES` (comma list to create), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The default min/max iOS versions live in `nix/defaults.json` as `IOS_MIN_VERSION`/`IOS_MAX_VERSION`. +- iOS: `TARGET_SDK` (min/max/custom), `DETOX_IOS_DEVICE` (explicit sim device), `IOS_DEVICE_NAMES` (comma list to create), `IOS_RUNTIME_MIN`/`IOS_RUNTIME_MAX` (runtime versions for min/max), `IOS_RUNTIME_CUSTOM` (runtime for custom), `IOS_DEVELOPER_DIR` (Xcode path), `IOS_DOWNLOAD_RUNTIME` (0 to skip runtime download attempt). The simulator runtime must exist in the active Xcode install. ### Releases diff --git a/wiki/scripts.md b/wiki/scripts.md index 65044a431..e0b8c9bc5 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -77,14 +77,14 @@ These env vars can be set by users to override defaults or behavior. ### iOS -- `IOS_MIN_VERSION`, `IOS_MAX_VERSION`: override min/max iOS versions. - `IOS_MIN_DEVICE`, `IOS_MAX_DEVICE`: override min/max device names. -- `IOS_RUNTIME`: preferred runtime (used by simctl). +- `IOS_RUNTIME_MIN`, `IOS_RUNTIME_MAX`: required iOS simulator runtimes for min/max. +- `IOS_RUNTIME_CUSTOM`: required runtime when `TARGET_SDK=custom`. - `IOS_DEVICE_NAMES`: comma-separated list of devices to create. - `IOS_DEVELOPER_DIR`: override the Xcode path. - `IOS_DOWNLOAD_RUNTIME`: set to `0` to skip `xcodebuild -downloadPlatform iOS`. - `TARGET_SDK`: `min`, `max`, or `custom` (controls which device/runtime to boot for iOS). -- `IOS_CUSTOM_DEVICE`, `IOS_CUSTOM_VERSION`: used when `TARGET_SDK=custom`. +- `IOS_CUSTOM_DEVICE`: used when `TARGET_SDK=custom`. - `DETOX_IOS_DEVICE`: force a specific simulator name for Detox. From 2de0047064416f6ea3d3562476103d4c0ca67bc3 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 22:23:09 -0600 Subject: [PATCH 20/32] use nix android sdk by default --- nix/defaults.json | 2 +- scripts/android/env.sh | 20 +++++++++++++------- scripts/ios/actions.sh | 3 +++ scripts/ios/env.sh | 22 ++++++++++++++++++---- scripts/shared/debug.sh | 1 - wiki/devbox.md | 2 +- wiki/scripts.md | 6 +++--- 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/nix/defaults.json b/nix/defaults.json index 69597468a..dee7ead7f 100644 --- a/nix/defaults.json +++ b/nix/defaults.json @@ -1,6 +1,6 @@ { "defaults": { - "ANDROID_SDK_USE_LOCAL": "0", + "ANDROID_LOCAL_SDK": "0", "ANDROID_MIN_API": "21", "ANDROID_MAX_API": "33", "ANDROID_CUSTOM_API": "29", diff --git a/scripts/android/env.sh b/scripts/android/env.sh index dd512a9e2..a0a91d8d0 100755 --- a/scripts/android/env.sh +++ b/scripts/android/env.sh @@ -56,7 +56,15 @@ detect_sdk_root_from_sdkmanager() { return 1 } -prefer_local="${ANDROID_SDK_USE_LOCAL:-}" +prefer_local="${ANDROID_LOCAL_SDK:-}" +case "$prefer_local" in + 1 | true | TRUE | yes | YES | on | ON) + prefer_local=1 + ;; + *) + prefer_local="" + ;; +esac if [ -n "$prefer_local" ]; then if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "${ANDROID_HOME:-}" ]; then ANDROID_SDK_ROOT="$ANDROID_HOME" @@ -153,10 +161,10 @@ ANDROID_ENV_LOADED_PID="$$" echo "Using Android SDK: $ANDROID_SDK_ROOT" case "$ANDROID_SDK_ROOT" in /nix/store/*) - echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_SDK_USE_LOCAL=1 before starting devbox shell." + echo "Source: Nix flake (reproducible, pinned). To use your local SDK instead, set ANDROID_LOCAL_SDK=1 before starting devbox shell." ;; *) - echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT and ensure ANDROID_SDK_USE_LOCAL is not set before starting devbox shell." + echo "Source: User/local SDK. To use the pinned Nix SDK, unset ANDROID_HOME/ANDROID_SDK_ROOT and ensure ANDROID_LOCAL_SDK is not set before starting devbox shell." ;; esac fi @@ -249,7 +257,7 @@ if [ -n "${INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" debug_dump_vars \ ANDROID_SDK_ROOT \ ANDROID_HOME \ - ANDROID_SDK_USE_LOCAL \ + ANDROID_LOCAL_SDK \ ANDROID_SDK_FLAKE_OUTPUT \ ANDROID_SDK_ROOT_MIN \ ANDROID_HOME_MIN \ @@ -268,10 +276,8 @@ if [ -n "${INIT_ANDROID:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" echo "Resolved Android SDK" echo " ANDROID_SDK_ROOT: ${android_sdk_root:-not set}" echo " ANDROID_BUILD_TOOLS_VERSION: ${android_sdk_version:-30.0.3}" - echo " ANDROID_MIN_API: ${android_min_api:-21}" - echo " ANDROID_MAX_API: ${android_max_api:-33}" - echo " ANDROID_TARGET_API: ${android_target_api:-not set}${android_target_source:+ (${android_target_source})}" echo " ANDROID_AVD_TARGET: api=${android_target_api:-not set} device=${android_target_device:-unknown} image=${android_system_image_summary:-google_apis}" + echo " Tip: use a local SDK with ANDROID_LOCAL_SDK=1 ANDROID_SDK_ROOT=/path/to/sdk (or ANDROID_HOME)." fi else if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/ios/actions.sh b/scripts/ios/actions.sh index 42be577e3..9b5f73a53 100644 --- a/scripts/ios/actions.sh +++ b/scripts/ios/actions.sh @@ -36,6 +36,9 @@ ios_run() { . "$SCRIPTS_DIR/ios/simctl.sh" case "$action" in start) + ensure_developer_dir + require_tool jq + ensure_simctl target_sdk="${TARGET_SDK:-max}" runtime_version="" if [ "$target_sdk" = "custom" ]; then diff --git a/scripts/ios/env.sh b/scripts/ios/env.sh index d7febe029..5e26c2e65 100755 --- a/scripts/ios/env.sh +++ b/scripts/ios/env.sh @@ -162,10 +162,24 @@ if [ -n "${INIT_IOS:-}" ] && [ -z "${CI:-}" ] && [ -z "${GITHUB_ACTIONS:-}" ] && xcode_version="$(xcodebuild -version 2>/dev/null | awk 'NR==1{print $2}')" fi + ios_target_device="${DETOX_IOS_DEVICE:-}" + if [ -z "$ios_target_device" ]; then + if [ -n "${IOS_DEVICE_NAMES:-}" ]; then + ios_target_device="$(printf '%s' "$IOS_DEVICE_NAMES" | cut -d',' -f1 | xargs)" + else + case "${TARGET_SDK:-max}" in + min) ios_target_device="${IOS_MIN_DEVICE:-}" ;; + max) ios_target_device="${IOS_MAX_DEVICE:-}" ;; + custom) ios_target_device="${IOS_CUSTOM_DEVICE:-}" ;; + *) ios_target_device="${IOS_MAX_DEVICE:-}" ;; + esac + fi + fi + ios_target_runtime="${IOS_RUNTIME:-$ios_runtime}" + echo "Resolved iOS SDK" - echo " IOS_RUNTIME_MIN: ${IOS_RUNTIME_MIN:-not set}" - echo " IOS_RUNTIME_MAX: ${IOS_RUNTIME_MAX:-not set}" - echo " IOS_RUNTIME: ${ios_runtime:-not set}" - echo " xcodebuild: ${xcode_version:-unknown}" echo " DEVELOPER_DIR: ${xcode_dir:-not set}" + echo " XCODE_VERSION: ${xcode_version:-unknown}" + echo " IOS_RUNTIME: ${ios_runtime:-not set}" + echo " IOS_SIM_TARGET: device=${ios_target_device:-unknown} runtime=${ios_target_runtime:-not set}" fi diff --git a/scripts/shared/debug.sh b/scripts/shared/debug.sh index 9d8bed8ef..253ed5db8 100644 --- a/scripts/shared/debug.sh +++ b/scripts/shared/debug.sh @@ -10,7 +10,6 @@ if [ "${DEBUG_SH_LOADED:-}" = "1" ] && [ "${DEBUG_SH_LOADED_PID:-}" = "$$" ]; th fi DEBUG_SH_LOADED=1 DEBUG_SH_LOADED_PID="$$" -set -eu debug_enabled() { [ "${ANALYTICS_CI_DEBUG:-}" = "1" ] || [ "${DEBUG:-}" = "1" ] diff --git a/wiki/devbox.md b/wiki/devbox.md index 928494333..4901fa929 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -13,7 +13,7 @@ Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT ## Android -By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_SDK_USE_LOCAL=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_SDK_USE_LOCAL` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/avd.sh`). Version sources are documented in `wiki/nix.md`. +By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_LOCAL_SDK=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_LOCAL_SDK` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/avd.sh`). Version sources are documented in `wiki/nix.md`. Example custom targets (root `devbox.json` sets these via `shell.env` for testing): `ANDROID_CUSTOM_API=29` `ANDROID_CUSTOM_DEVICE=pixel_6` `IOS_CUSTOM_DEVICE="iPhone 15"` diff --git a/wiki/scripts.md b/wiki/scripts.md index e0b8c9bc5..24284d40c 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -28,7 +28,7 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `scripts/android/env.sh` - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). - - Set `ANDROID_SDK_USE_LOCAL=1` to keep a pre-set local SDK instead. + - Set `ANDROID_LOCAL_SDK=1` to keep a pre-set local SDK instead. - Loads platform defaults via `scripts/shared/defaults.sh` (from `nix/defaults.json`). - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. @@ -59,8 +59,8 @@ These env vars can be set by users to override defaults or behavior. ### Android - `ENV_DEFAULTS_JSON`: path to an alternate `nix/defaults.json` (advanced). -- `ANDROID_SDK_ROOT`, `ANDROID_HOME`: explicit SDK location (used with `ANDROID_SDK_USE_LOCAL=1`). -- `ANDROID_SDK_USE_LOCAL`: use a local Android SDK instead of the Nix SDK. +- `ANDROID_SDK_ROOT`, `ANDROID_HOME`: explicit SDK location (used with `ANDROID_LOCAL_SDK=1`). +- `ANDROID_LOCAL_SDK`: use a local Android SDK instead of the Nix SDK. - `ANDROID_SDK_FLAKE_OUTPUT`: force a specific flake output (e.g., `android-sdk-max`). - `TARGET_SDK`: `min`, `max`, or `custom` (selects which API/device pairing to use). - `ANDROID_MIN_API`, `ANDROID_MAX_API`: override the min/max API levels. From 815162d1fe2eea1fdae2fab563a7ae7f55c5986a Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 22:24:48 -0600 Subject: [PATCH 21/32] dry run test --- .github/workflows/release-dry-run.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index b6fdff49a..b6a918335 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -2,6 +2,9 @@ name: Release Dry Run on: workflow_dispatch: + pull_request: + branches: + - master jobs: release-dry-run: From f702b6b4a1d7a5d30b7a9237c5579bb014a27805 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 22:31:08 -0600 Subject: [PATCH 22/32] fix minimal tasks --- shells/minimal/devbox.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index e59e71d53..c4b975083 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -12,12 +12,14 @@ "scripts": { "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh build"], "release": [ + "cd $DEVBOX_PROJECT_ROOT/../..", "npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}", "yarn install --immutable", "yarn build", "yarn release" ], "release-dry-run": [ + "cd $DEVBOX_PROJECT_ROOT/../..", "yarn install --immutable", "yarn build", "yarn multi-semantic-release --dry-run" From 8b3771a720b38975df5fb3de3a03677d45ecd403 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Wed, 28 Jan 2026 22:57:46 -0600 Subject: [PATCH 23/32] fixes --- .github/workflows/ios-e2e.yml | 14 +++++++++----- scripts/android/avd.sh | 8 ++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index 16ee3b648..24b3e40fa 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -32,7 +32,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Resolve iOS runtime - id: runtime + id: defaults run: | runtime="${{ inputs.runtime }}" min="$(jq -r '.defaults.IOS_RUNTIME_MIN' nix/defaults.json)" @@ -71,9 +71,13 @@ jobs: sudo rm -rf "$HOME/Library/Developer/CoreSimulator/Devices" sudo rm -rf "$HOME/Library/Developer/Xcode/DerivedData" df -H - - uses: maxim-lobanov/setup-xcode@v1 + - uses: maxim-lobanov/setup-xcode@v1.6.0 with: - xcode-version: ${{ steps.runtime.outputs.runtime }} + xcode-version: ${{ steps.defaults.outputs.runtime }} + - name: Install Xcode components + run: | + sudo xcodebuild -runFirstLaunch + sudo xcodebuild -downloadPlatform iOS - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: @@ -83,5 +87,5 @@ jobs: run: devbox run --config=${{ inputs.devbox_config }} test-ios env: TARGET_SDK: ${{ inputs.target }} - IOS_RUNTIME_MIN: ${{ steps.runtime.outputs.runtime_min }} - IOS_RUNTIME_MAX: ${{ steps.runtime.outputs.runtime_max }} + IOS_RUNTIME_MIN: ${{ steps.defaults.outputs.runtime_min }} + IOS_RUNTIME_MAX: ${{ steps.defaults.outputs.runtime_max }} diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index e43d3b80a..18c1645b5 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -142,6 +142,7 @@ ${target_line}" android_setup() { TARGETS="" + resolved_avd_name="" detected_sdk_root="$(detect_sdk_root 2>/dev/null || true)" if [ -z "${ANDROID_SDK_ROOT:-}" ] && [ -n "$detected_sdk_root" ]; then @@ -275,6 +276,9 @@ TARGET_EOF else avd_name="$(printf '%s_API%s_%s' "$device" "$api" "$abi_safe")" fi + if [ -z "$resolved_avd_name" ]; then + resolved_avd_name="$avd_name" + fi create_avd "$avd_name" "$device" "$api_image" if avd_exists "$avd_name"; then @@ -283,6 +287,10 @@ TARGET_EOF done IFS="$ifs_backup" + if [ -z "${DETOX_AVD:-}" ] && [ -n "$resolved_avd_name" ]; then + DETOX_AVD="$resolved_avd_name" + export DETOX_AVD + fi echo "AVDs ready. Boot with: emulator -avd --netdelay none --netspeed full" } From 41ae7553c070c463d0ff3bad91b117edced29fca Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 10:05:14 -0600 Subject: [PATCH 24/32] debug info --- .github/workflows/ios-e2e.yml | 36 ++++++++++++++++++++- examples/E2E-73/.detoxrc.js | 20 ++++++++++-- examples/E2E/.detoxrc.js | 18 +++++++++-- scripts/android/avd.sh | 37 ++++++++++++--------- scripts/ci/env-check.sh | 61 +++++++++++++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 21 deletions(-) create mode 100644 scripts/ci/env-check.sh diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index 24b3e40fa..c96b77ccb 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -74,9 +74,43 @@ jobs: - uses: maxim-lobanov/setup-xcode@v1.6.0 with: xcode-version: ${{ steps.defaults.outputs.runtime }} + - name: Environment check + run: sh scripts/ci/env-check.sh + - name: Xcode diagnostics + run: | + set -euo pipefail + echo "Xcode path: $(xcode-select -p)" + xcodebuild -version + xcodebuild -showsdks + echo "Swift toolchain libs (simulator):" + ls -la "$(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator" || true + echo "Swift runtime libs (SDK):" + ls -la "$(xcode-select -p)/Platforms/iPhoneSimulator.platform/Developer/SDKs" || true + sdk_path="$(xcrun --sdk iphonesimulator --show-sdk-path 2>/dev/null || true)" + if [ -n "$sdk_path" ]; then + ls -la "$sdk_path/usr/lib/swift" || true + fi + - name: Verify Swift compatibility libs + run: | + set -euo pipefail + toolchain_swift_dir="$(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator" + sdk_path="$(xcrun --sdk iphonesimulator --show-sdk-path 2>/dev/null || true)" + sdk_swift_dir="${sdk_path}/usr/lib/swift" + missing="" + for lib in swiftCompatibilityPacks swiftCompatibility56 swiftCompatibilityConcurrency; do + if [ ! -e "${toolchain_swift_dir}/lib${lib}.dylib" ] && [ ! -e "${sdk_swift_dir}/lib${lib}.dylib" ]; then + missing="${missing} ${lib}" + fi + done + if [ -n "$missing" ]; then + echo "Missing Swift compatibility libraries:${missing}" >&2 + echo "toolchain_swift_dir=${toolchain_swift_dir}" >&2 + echo "sdk_swift_dir=${sdk_swift_dir}" >&2 + exit 1 + fi - name: Install Xcode components run: | - sudo xcodebuild -runFirstLaunch + sudo xcodebuild -runFirstLaunch -checkForNewerComponents sudo xcodebuild -downloadPlatform iOS - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 diff --git a/examples/E2E-73/.detoxrc.js b/examples/E2E-73/.detoxrc.js index 1a19352a6..5536ce204 100644 --- a/examples/E2E-73/.detoxrc.js +++ b/examples/E2E-73/.detoxrc.js @@ -1,3 +1,19 @@ +const {execSync} = require('child_process'); + +const resolveGradleCmd = () => { + if (process.env.GRADLE_CMD) { + return process.env.GRADLE_CMD; + } + try { + execSync('command -v gradle', {stdio: 'ignore'}); + return 'gradle'; + } catch (_) { + return './gradlew'; + } +}; + +const gradleCmd = resolveGradleCmd(); + /** @type {Detox.DetoxConfig} */ module.exports = { testRunner: { @@ -41,14 +57,14 @@ module.exports = { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk', build: - 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug', + `cd android && ${gradleCmd} assembleDebug assembleAndroidTest -DtestBuildType=debug`, reversePorts: [8081], }, 'android.release': { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/release/app-release.apk', build: - 'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release', + `cd android && ${gradleCmd} assembleRelease assembleAndroidTest -DtestBuildType=release`, }, }, devices: { diff --git a/examples/E2E/.detoxrc.js b/examples/E2E/.detoxrc.js index f944e52b0..7544da841 100644 --- a/examples/E2E/.detoxrc.js +++ b/examples/E2E/.detoxrc.js @@ -18,6 +18,20 @@ const safeParseJSON = cmd => { } }; +const resolveGradleCmd = () => { + if (process.env.GRADLE_CMD) { + return process.env.GRADLE_CMD; + } + try { + execSync('command -v gradle', {stdio: 'ignore'}); + return 'gradle'; + } catch (_) { + return './gradlew'; + } +}; + +const gradleCmd = resolveGradleCmd(); + const listAvailableDevices = () => { const parsed = safeParseJSON('xcrun simctl list devices -j'); if (!parsed || !parsed.devices) return []; @@ -119,14 +133,14 @@ module.exports = { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/debug/app-debug.apk', build: - 'cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug', + `cd android && ${gradleCmd} assembleDebug assembleAndroidTest -DtestBuildType=debug`, reversePorts: [8081], }, 'android.release': { type: 'android.apk', binaryPath: 'android/app/build/outputs/apk/release/app-release.apk', build: - 'cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release', + `cd android && ${gradleCmd} assembleRelease assembleAndroidTest -DtestBuildType=release`, }, }, devices: { diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 18c1645b5..299c33380 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -57,23 +57,28 @@ resolve_device() { if [ -z "$desired" ]; then return 1 fi - if avdmanager list device | grep -qi "Name: ${desired}$"; then - printf '%s\n' "$desired" - return 0 - fi - if avdmanager list device | grep -qi "Name: ${desired}"; then - printf '%s\n' "$desired" - return 0 - fi - if avdmanager list device | grep -qi "Name: pixel"; then - printf '%s\n' "pixel" - return 0 - fi - fallback="$(avdmanager list device | awk -F': ' '/Name:/{print $2; exit}')" - if [ -n "$fallback" ]; then - printf '%s\n' "$fallback" - return 0 + devices="$(avdmanager list device | awk -F': ' '/Name:/{print $2}')" + if [ -z "$devices" ]; then + return 1 fi + + normalize_name() { + printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]' + } + + desired_norm="$(normalize_name "$desired")" + desired_alt_norm="$(normalize_name "$(printf '%s' "$desired" | tr '_-' ' ')")" + + while IFS= read -r name; do + name_norm="$(normalize_name "$name")" + if [ "$name_norm" = "$desired_norm" ] || [ "$name_norm" = "$desired_alt_norm" ]; then + printf '%s\n' "$name" + return 0 + fi + done </dev/null 2>&1; then + sw_vers +fi +echo + +if command -v xcode-select >/dev/null 2>&1; then + echo "xcode-select: $(xcode-select -p 2>/dev/null || true)" +fi + +if command -v xcodebuild >/dev/null 2>&1; then + xcodebuild -version + xcodebuild -showsdks +fi +echo + +if command -v xcrun >/dev/null 2>&1; then + sdk_path="$(xcrun --sdk iphonesimulator --show-sdk-path 2>/dev/null || true)" + platform_path="$(xcrun --sdk iphonesimulator --show-sdk-platform-path 2>/dev/null || true)" + swift_toolchain_path="$(xcrun --sdk iphonesimulator --show-sdk-toolchain-path 2>/dev/null || true)" + echo "iphonesimulator sdk path: ${sdk_path:-unknown}" + echo "iphonesimulator platform path: ${platform_path:-unknown}" + echo "iphonesimulator toolchain path: ${swift_toolchain_path:-unknown}" +fi +echo + +toolchain_swift_dir="$(xcode-select -p 2>/dev/null)/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator" +sdk_swift_dir="${sdk_path:-}/usr/lib/swift" + +echo "Swift toolchain libs (simulator): ${toolchain_swift_dir}" +ls -la "$toolchain_swift_dir" 2>/dev/null || true +echo + +echo "Swift runtime libs (SDK): ${sdk_swift_dir}" +ls -la "$sdk_swift_dir" 2>/dev/null || true +echo + +for lib in swiftCompatibilityPacks swiftCompatibility56 swiftCompatibilityConcurrency; do + toolchain_dylib="${toolchain_swift_dir}/lib${lib}.dylib" + toolchain_static="${toolchain_swift_dir}/lib${lib}.a" + sdk_dylib="${sdk_swift_dir}/lib${lib}.dylib" + sdk_static="${sdk_swift_dir}/lib${lib}.a" + if [ -e "$toolchain_dylib" ]; then + echo "FOUND toolchain ${lib}: ${toolchain_dylib}" + elif [ -e "$toolchain_static" ]; then + echo "FOUND toolchain ${lib}: ${toolchain_static}" + elif [ -e "$sdk_dylib" ]; then + echo "FOUND sdk ${lib}: ${sdk_dylib}" + elif [ -e "$sdk_static" ]; then + echo "FOUND sdk ${lib}: ${sdk_static}" + else + echo "MISSING ${lib}" + fi +done From fbb05ecb1bb5a3b432901c5665fb1146f3538850 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 10:35:38 -0600 Subject: [PATCH 25/32] android fixes --- devbox.json | 2 +- devbox.lock | 24 +-- .../project.pbxproj | 4 + scripts/android/avd.sh | 159 ++++++------------ scripts/android/lib.sh | 67 ++++++++ scripts/run.sh | 14 +- shells/android-max/devbox.json | 2 +- shells/android-max/devbox.lock | 102 +++++------ shells/android-min/devbox.json | 2 +- shells/android-min/devbox.lock | 102 +++++------ shells/ios/devbox.lock | 90 +++++----- shells/minimal/devbox.lock | 138 +++++++-------- 12 files changed, 358 insertions(+), 348 deletions(-) create mode 100644 scripts/android/lib.sh diff --git a/devbox.json b/devbox.json index 938f5163e..cc0d31727 100644 --- a/devbox.json +++ b/devbox.json @@ -10,7 +10,7 @@ "nixfmt": "latest", "shfmt": "latest", "jdk17": "latest", - "gradle": "latest", + "gradle": "8.0.1", "jq": "latest", "netcat": "latest", "act": "latest", diff --git a/devbox.lock b/devbox.lock index e15917805..07fb8283c 100644 --- a/devbox.lock +++ b/devbox.lock @@ -81,52 +81,52 @@ "last_modified": "2026-01-27T15:18:14Z", "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, - "gradle@latest": { - "last_modified": "2026-01-26T09:54:05Z", + "gradle@8.0.1": { + "last_modified": "2023-07-24T21:56:31Z", "plugin_version": "0.0.1", - "resolved": "github:NixOS/nixpkgs/5b265bda51b42a2a85af0a543c3e57b778b01b7d#gradle", + "resolved": "github:NixOS/nixpkgs/dfcffbd74fd6f0419370d8240e445252a39f4d10#gradle", "source": "devbox-search", - "version": "8.14.4", + "version": "8.0.1", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/yb98qaa8if1gvdihj9vngyv822kqs88v-gradle-8.14.4", + "path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/yb98qaa8if1gvdihj9vngyv822kqs88v-gradle-8.14.4" + "store_path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/xbn16nkgbaj09mf3vgzs7y582m67bm9s-gradle-8.14.4", + "path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/xbn16nkgbaj09mf3vgzs7y582m67bm9s-gradle-8.14.4" + "store_path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m0xaca5z53sg9n6jqlkvm6cq0cn7ny28-gradle-8.14.4", + "path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/m0xaca5z53sg9n6jqlkvm6cq0cn7ny28-gradle-8.14.4" + "store_path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/7nhijwwp2cdwnj2f19c5qdp2igf6cqb9-gradle-8.14.4", + "path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/7nhijwwp2cdwnj2f19c5qdp2igf6cqb9-gradle-8.14.4" + "store_path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1" } } }, diff --git a/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj b/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj index 073a7fdb4..7fe7b261e 100644 --- a/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj +++ b/examples/E2E/ios/AnalyticsReactNativeE2E.xcodeproj/project.pbxproj @@ -606,6 +606,8 @@ ); OTHER_LDFLAGS = ( "$(inherited)", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; @@ -678,6 +680,8 @@ ); OTHER_LDFLAGS = ( "$(inherited)", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; diff --git a/scripts/android/avd.sh b/scripts/android/avd.sh index 299c33380..788eb5dd4 100644 --- a/scripts/android/avd.sh +++ b/scripts/android/avd.sh @@ -6,23 +6,18 @@ if ! (return 0 2>/dev/null); then exit 1 fi -script_dir="$(cd "$(dirname "$0")" && pwd)" +scripts_root="${SCRIPTS_DIR:-$(cd "$(dirname "$0")" && pwd)}" +android_dir="$scripts_root/android" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then - init_path="$script_dir/../env.sh" - if [ ! -f "$init_path" ]; then - repo_root="" - if command -v git >/dev/null 2>&1; then - repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" - fi - if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then - init_path="$repo_root/scripts/env.sh" - fi - fi # shellcheck disable=SC1090 - . "$init_path" + . "$scripts_root/lib/bootstrap.sh" + load_env "$scripts_root" fi debug_log_script "scripts/android/avd.sh" +# shellcheck disable=SC1090 +. "$android_dir/lib.sh" + detect_sdk_root() { if [ -n "${ANDROID_SDK_ROOT:-}" ]; then printf '%s\n' "$ANDROID_SDK_ROOT" @@ -57,22 +52,38 @@ resolve_device() { if [ -z "$desired" ]; then return 1 fi - devices="$(avdmanager list device | awk -F': ' '/Name:/{print $2}')" + devices="$(avdmanager list device | awk -F': ' ' + /^id: /{ + id=$2 + if (index(id, "\"") > 0) { + q=index(id, "\"") + rest=substr(id, q + 1) + q2=index(rest, "\"") + if (q2 > 0) { id=substr(rest, 1, q2 - 1) } + } else { + split(id, parts, " ") + id=parts[1] + } + next + } + /^[[:space:]]*Name: /{ + name=$2 + if (id != "") { print id "\t" name; id="" } + } + ')" if [ -z "$devices" ]; then return 1 fi - normalize_name() { - printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]' - } - - desired_norm="$(normalize_name "$desired")" - desired_alt_norm="$(normalize_name "$(printf '%s' "$desired" | tr '_-' ' ')")" + desired_norm="$(android_normalize_name "$desired")" + desired_alt_norm="$(android_normalize_name "$(printf '%s' "$desired" | tr '_-' ' ')")" - while IFS= read -r name; do - name_norm="$(normalize_name "$name")" - if [ "$name_norm" = "$desired_norm" ] || [ "$name_norm" = "$desired_alt_norm" ]; then - printf '%s\n' "$name" + while IFS=$'\t' read -r id name; do + id_norm="$(android_normalize_name "$id")" + name_norm="$(android_normalize_name "$name")" + if [ "$id_norm" = "$desired_norm" ] || [ "$id_norm" = "$desired_alt_norm" ] || \ + [ "$name_norm" = "$desired_norm" ] || [ "$name_norm" = "$desired_alt_norm" ]; then + printf '%s\n' "$id" return 0 fi done <&2 - exit 1 - fi - if [ -z "$target_device" ]; then - echo "TARGET_SDK=custom requires ANDROID_CUSTOM_DEVICE to be set." >&2 - exit 1 - fi - ;; - *) - target_api="$platform_max_api" - target_device="$platform_max_device" - ;; - esac - - target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" - target_tag="${AVD_TAG:-${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}}" - if [ -n "${AVD_DEVICE:-}" ]; then - target_device="$AVD_DEVICE" - fi + IFS='|' read -r target_api target_device target_tag target_preferred_abi <&2 + exit 1 + fi + avd_name="$(printf '%s_API%s_%s' "$safe_device" "$api" "$abi_safe")" fi if [ -z "$resolved_avd_name" ]; then resolved_avd_name="$avd_name" @@ -312,55 +292,22 @@ android_start() { fi if [ -z "$avd" ]; then - platform_min_api="${ANDROID_MIN_API:-21}" - platform_max_api="${ANDROID_MAX_API:-33}" - platform_min_device="${ANDROID_MIN_DEVICE:-pixel}" - platform_max_device="${ANDROID_MAX_DEVICE:-medium_phone}" - platform_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" - - case "$target_sdk" in - min) - target_api="$platform_min_api" - target_device="$platform_min_device" - ;; - max) - target_api="$platform_max_api" - target_device="$platform_max_device" - ;; - custom) - target_api="${ANDROID_CUSTOM_API:-}" - target_device="${ANDROID_CUSTOM_DEVICE:-}" - if [ -z "$target_api" ]; then - echo "TARGET_SDK=custom requires ANDROID_CUSTOM_API to be set." >&2 - exit 1 - fi - if [ -z "$target_device" ]; then - echo "TARGET_SDK=custom requires ANDROID_CUSTOM_DEVICE to be set." >&2 - exit 1 - fi - ;; - *) - target_api="$platform_max_api" - target_device="$platform_max_device" - ;; - esac - - target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" - target_tag="${AVD_TAG:-${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}}" - if [ -n "${AVD_DEVICE:-}" ]; then - target_device="$AVD_DEVICE" - fi + IFS='|' read -r target_api target_device target_tag target_preferred_abi </dev/null || true)" if [ -n "$api_image" ]; then abi="${api_image##*;}" abi_safe="$(printf '%s' "$abi" | tr '-' '_')" - avd="$(printf '%s_API%s_%s' "$target_device" "$target_api" "$abi_safe")" + safe_device="$(android_sanitize_avd_name "$target_device" || true)" + if [ -n "$safe_device" ]; then + avd="$(printf '%s_API%s_%s' "$safe_device" "$target_api" "$abi_safe")" + fi fi fi diff --git a/scripts/android/lib.sh b/scripts/android/lib.sh new file mode 100644 index 000000000..cf86fcc51 --- /dev/null +++ b/scripts/android/lib.sh @@ -0,0 +1,67 @@ +#!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/android/lib.sh must be sourced." >&2 + exit 1 +fi + +android_normalize_name() { + printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | tr -cd '[:alnum:]' +} + +android_sanitize_avd_name() { + raw="$1" + if [ -z "$raw" ]; then + return 1 + fi + cleaned="$(printf '%s' "$raw" | tr ' ' '_' | tr -cd 'A-Za-z0-9._-')" + if [ -z "$cleaned" ]; then + return 1 + fi + printf '%s\n' "$cleaned" +} + +android_resolve_target() { + platform_min_api="${ANDROID_MIN_API:-21}" + platform_max_api="${ANDROID_MAX_API:-33}" + platform_min_device="${ANDROID_MIN_DEVICE:-pixel}" + platform_max_device="${ANDROID_MAX_DEVICE:-medium_phone}" + platform_image_tag="${ANDROID_SYSTEM_IMAGE_TAG:-google_apis}" + + target_sdk="${TARGET_SDK:-max}" + case "$target_sdk" in + min) + target_api="$platform_min_api" + target_device="$platform_min_device" + ;; + max) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + custom) + target_api="${ANDROID_CUSTOM_API:-}" + target_device="${ANDROID_CUSTOM_DEVICE:-}" + if [ -z "$target_api" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_API to be set." >&2 + exit 1 + fi + if [ -z "$target_device" ]; then + echo "TARGET_SDK=custom requires ANDROID_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + ;; + *) + target_api="$platform_max_api" + target_device="$platform_max_device" + ;; + esac + + target_api="${AVD_API:-${ANDROID_TARGET_API:-$target_api}}" + target_tag="${AVD_TAG:-${ANDROID_CUSTOM_SYSTEM_IMAGE_TAG:-${ANDROID_SYSTEM_IMAGE_TAG:-$platform_image_tag}}}" + if [ -n "${AVD_DEVICE:-}" ]; then + target_device="$AVD_DEVICE" + fi + target_preferred_abi="${AVD_ABI:-}" + + printf '%s|%s|%s|%s\n' "$target_api" "$target_device" "$target_tag" "$target_preferred_abi" +} diff --git a/scripts/run.sh b/scripts/run.sh index 7c5f6e771..96afbefc1 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -2,6 +2,7 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" +lib_dir="$script_dir/lib" if [ "${RUN_SH_ACTIVE:-}" = "1" ]; then echo "scripts/run.sh is already running." >&2 @@ -10,18 +11,9 @@ fi RUN_SH_ACTIVE=1 export RUN_SH_ACTIVE -init_path="$script_dir/env.sh" -if [ ! -f "$init_path" ]; then - repo_root="" - if command -v git >/dev/null 2>&1; then - repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" - fi - if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then - init_path="$repo_root/scripts/env.sh" - fi -fi # shellcheck disable=SC1090 -. "$init_path" +. "$lib_dir/bootstrap.sh" +load_env "$script_dir" debug_log_script "scripts/run.sh" scripts_root="${SCRIPTS_DIR:-$script_dir}" diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index f07f05af9..a9bc4bea8 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -3,7 +3,7 @@ "packages": { "yarn-berry": "latest", "jdk17": "latest", - "gradle": "latest", + "gradle": "8.0.1", "jq": "latest", "path:../../nix#android-sdk-max": "" }, diff --git a/shells/android-max/devbox.lock b/shells/android-max/devbox.lock index 92847cffd..f15292572 100644 --- a/shells/android-max/devbox.lock +++ b/shells/android-max/devbox.lock @@ -5,52 +5,52 @@ "last_modified": "2026-01-27T15:18:14Z", "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, - "gradle@latest": { - "last_modified": "2025-12-31T03:27:36Z", + "gradle@8.0.1": { + "last_modified": "2023-07-24T21:56:31Z", "plugin_version": "0.0.1", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#gradle", + "resolved": "github:NixOS/nixpkgs/dfcffbd74fd6f0419370d8240e445252a39f4d10#gradle", "source": "devbox-search", - "version": "8.14.3", + "version": "8.0.1", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3", + "path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3" + "store_path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3", + "path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3" + "store_path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3", + "path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3" + "store_path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3", + "path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3" + "store_path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1" } } }, @@ -83,8 +83,8 @@ } }, "jq@latest": { - "last_modified": "2026-01-20T02:11:35Z", - "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "last_modified": "2026-01-26T13:12:53Z", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#jq", "source": "devbox-search", "version": "1.8.1", "systems": { @@ -92,115 +92,115 @@ "outputs": [ { "name": "bin", - "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/jlpyybc7pdh4gk17dc266d6a1szm7dk6-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/bhryp10d5w5h9rsav5k9m9jb55z26bsl-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/238sn0gg3i3i9v6kgx4g1k6b19frzy49-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/n64h0247s3674kry90l6kszx06zyrgfn-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/2pjwv0ab8nilrg1lvjazf9y9w6g6pk5y-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "path": "/nix/store/2sy4y09ddbi64pbg4is078110z70jsdw-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "path": "/nix/store/vx81xggapqwdd2l64mmxrkbafih461jc-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "path": "/nix/store/cfhajjz1k7gf31krbj18q9acb54xp5z9-jq-1.8.1" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/vx840ik1sj1h8fhqwa40aglvrgpa0r18-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/bmg2xfw86wavg7fm062nyf6v48xzxh0j-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/pp2hrljvalrrwyxh7is69nnlmxb2m7lk-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/h05xaf7fsasgp8cpyar2195cc8lbgih8-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/6mh88qsh57ivh31c5nqxc43n0hv9xhbk-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/d73i1fvhrqms0sbfrvqaynsr8iva216v-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/3ynrp4ypwv1g1jgsk638443p8lpd9g8f-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/fgsvqffyvcpjqs093wwf2d6dzxnmnqnv-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#yarn-berry", "source": "devbox-search", "version": "4.12.0", "systems": { @@ -208,41 +208,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0" } } } diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 838b69c7e..68b3f2c6d 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -3,7 +3,7 @@ "packages": { "yarn-berry": "latest", "jdk17": "latest", - "gradle": "latest", + "gradle": "8.0.1", "jq": "latest", "path:../../nix#android-sdk-min": "" }, diff --git a/shells/android-min/devbox.lock b/shells/android-min/devbox.lock index 92847cffd..f15292572 100644 --- a/shells/android-min/devbox.lock +++ b/shells/android-min/devbox.lock @@ -5,52 +5,52 @@ "last_modified": "2026-01-27T15:18:14Z", "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, - "gradle@latest": { - "last_modified": "2025-12-31T03:27:36Z", + "gradle@8.0.1": { + "last_modified": "2023-07-24T21:56:31Z", "plugin_version": "0.0.1", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#gradle", + "resolved": "github:NixOS/nixpkgs/dfcffbd74fd6f0419370d8240e445252a39f4d10#gradle", "source": "devbox-search", - "version": "8.14.3", + "version": "8.0.1", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3", + "path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/v2xbkgrvn0b4g4qq7j5x60va0d4gf0kw-gradle-8.14.3" + "store_path": "/nix/store/lrh7pjhni25c21llri3v1ya6n3nylng4-gradle-8.0.1" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3", + "path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/mvs8d5c60yyx3sxpppg1r67yjvlrrhhh-gradle-8.14.3" + "store_path": "/nix/store/5h0z90r6r8c4s9x72ik0jp6sf782h4j0-gradle-8.0.1" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3", + "path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/jy3fpkvcymjaglzi9z2gbpzcyqypgfxh-gradle-8.14.3" + "store_path": "/nix/store/7k8494nxy4x2sh8d0rzpmmh6pmk1q1wf-gradle-8.0.1" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3", + "path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1", "default": true } ], - "store_path": "/nix/store/80fgl9ffaxlxl9s4i1jb37krcljx669g-gradle-8.14.3" + "store_path": "/nix/store/83jn6p607rjb784jvypvx5r30pgq7kwa-gradle-8.0.1" } } }, @@ -83,8 +83,8 @@ } }, "jq@latest": { - "last_modified": "2026-01-20T02:11:35Z", - "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "last_modified": "2026-01-26T13:12:53Z", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#jq", "source": "devbox-search", "version": "1.8.1", "systems": { @@ -92,115 +92,115 @@ "outputs": [ { "name": "bin", - "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/jlpyybc7pdh4gk17dc266d6a1szm7dk6-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/bhryp10d5w5h9rsav5k9m9jb55z26bsl-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/238sn0gg3i3i9v6kgx4g1k6b19frzy49-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/n64h0247s3674kry90l6kszx06zyrgfn-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/2pjwv0ab8nilrg1lvjazf9y9w6g6pk5y-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "path": "/nix/store/2sy4y09ddbi64pbg4is078110z70jsdw-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "path": "/nix/store/vx81xggapqwdd2l64mmxrkbafih461jc-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "path": "/nix/store/cfhajjz1k7gf31krbj18q9acb54xp5z9-jq-1.8.1" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/vx840ik1sj1h8fhqwa40aglvrgpa0r18-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/bmg2xfw86wavg7fm062nyf6v48xzxh0j-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/pp2hrljvalrrwyxh7is69nnlmxb2m7lk-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/h05xaf7fsasgp8cpyar2195cc8lbgih8-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/6mh88qsh57ivh31c5nqxc43n0hv9xhbk-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/d73i1fvhrqms0sbfrvqaynsr8iva216v-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/3ynrp4ypwv1g1jgsk638443p8lpd9g8f-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/fgsvqffyvcpjqs093wwf2d6dzxnmnqnv-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#yarn-berry", "source": "devbox-search", "version": "4.12.0", "systems": { @@ -208,41 +208,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0" } } } diff --git a/shells/ios/devbox.lock b/shells/ios/devbox.lock index ae82190ba..62575eddb 100644 --- a/shells/ios/devbox.lock +++ b/shells/ios/devbox.lock @@ -2,8 +2,8 @@ "lockfile_version": "1", "packages": { "cocoapods@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#cocoapods", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#cocoapods", "source": "devbox-search", "version": "1.16.2", "systems": { @@ -11,21 +11,21 @@ "outputs": [ { "name": "out", - "path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2", + "path": "/nix/store/xmpbzlm4h97izn0nwf5r3flxa3hqiawa-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2" + "store_path": "/nix/store/xmpbzlm4h97izn0nwf5r3flxa3hqiawa-cocoapods-1.16.2" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2", + "path": "/nix/store/kk994ybb09jk38n2k2sp5mifgka5mixg-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2" + "store_path": "/nix/store/kk994ybb09jk38n2k2sp5mifgka5mixg-cocoapods-1.16.2" } } }, @@ -34,8 +34,8 @@ "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, "jq@latest": { - "last_modified": "2026-01-20T02:11:35Z", - "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "last_modified": "2026-01-26T13:12:53Z", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#jq", "source": "devbox-search", "version": "1.8.1", "systems": { @@ -43,115 +43,115 @@ "outputs": [ { "name": "bin", - "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/jlpyybc7pdh4gk17dc266d6a1szm7dk6-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/bhryp10d5w5h9rsav5k9m9jb55z26bsl-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/238sn0gg3i3i9v6kgx4g1k6b19frzy49-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/n64h0247s3674kry90l6kszx06zyrgfn-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/2pjwv0ab8nilrg1lvjazf9y9w6g6pk5y-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "path": "/nix/store/2sy4y09ddbi64pbg4is078110z70jsdw-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "path": "/nix/store/vx81xggapqwdd2l64mmxrkbafih461jc-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "path": "/nix/store/cfhajjz1k7gf31krbj18q9acb54xp5z9-jq-1.8.1" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/vx840ik1sj1h8fhqwa40aglvrgpa0r18-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/bmg2xfw86wavg7fm062nyf6v48xzxh0j-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/pp2hrljvalrrwyxh7is69nnlmxb2m7lk-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/h05xaf7fsasgp8cpyar2195cc8lbgih8-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/6mh88qsh57ivh31c5nqxc43n0hv9xhbk-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/d73i1fvhrqms0sbfrvqaynsr8iva216v-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/3ynrp4ypwv1g1jgsk638443p8lpd9g8f-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/fgsvqffyvcpjqs093wwf2d6dzxnmnqnv-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#yarn-berry", "source": "devbox-search", "version": "4.12.0", "systems": { @@ -159,41 +159,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0" } } } diff --git a/shells/minimal/devbox.lock b/shells/minimal/devbox.lock index 9a97af8ed..9e6335872 100644 --- a/shells/minimal/devbox.lock +++ b/shells/minimal/devbox.lock @@ -6,8 +6,8 @@ "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, "jq@latest": { - "last_modified": "2026-01-20T02:11:35Z", - "resolved": "github:NixOS/nixpkgs/ed142ab1b3a092c4d149245d0c4126a5d7ea00b0#jq", + "last_modified": "2026-01-26T13:12:53Z", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#jq", "source": "devbox-search", "version": "1.8.1", "systems": { @@ -15,115 +15,115 @@ "outputs": [ { "name": "bin", - "path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin", + "path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/jlpyybc7pdh4gk17dc266d6a1szm7dk6-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/bhryp10d5w5h9rsav5k9m9jb55z26bsl-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/238sn0gg3i3i9v6kgx4g1k6b19frzy49-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/n64h0247s3674kry90l6kszx06zyrgfn-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/qjs0qndyz1g97rsc1zp4cd692y5iph64-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/2pjwv0ab8nilrg1lvjazf9y9w6g6pk5y-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "path": "/nix/store/2sy4y09ddbi64pbg4is078110z70jsdw-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "path": "/nix/store/vx81xggapqwdd2l64mmxrkbafih461jc-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "path": "/nix/store/cfhajjz1k7gf31krbj18q9acb54xp5z9-jq-1.8.1" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/c1qm5fsn6qbl09xdjx649vifabypyywd-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/vx840ik1sj1h8fhqwa40aglvrgpa0r18-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/bmg2xfw86wavg7fm062nyf6v48xzxh0j-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/pp2hrljvalrrwyxh7is69nnlmxb2m7lk-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/h05xaf7fsasgp8cpyar2195cc8lbgih8-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/51343hgchh7by4l8r1g244ma05ny3x0b-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/6mh88qsh57ivh31c5nqxc43n0hv9xhbk-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/d73i1fvhrqms0sbfrvqaynsr8iva216v-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/3ynrp4ypwv1g1jgsk638443p8lpd9g8f-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/fgsvqffyvcpjqs093wwf2d6dzxnmnqnv-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/qnaw7i777j52fpgbl5pgmzkq85znp083-jq-1.8.1-bin" } } }, "nixfmt@latest": { - "last_modified": "2026-01-09T13:41:53Z", - "resolved": "github:NixOS/nixpkgs/5f02c91314c8ba4afe83b256b023756412218535#nixfmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#nixfmt", "source": "devbox-search", "version": "1.2.0", "systems": { @@ -131,47 +131,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0", + "path": "/nix/store/lvb2z93xn3m0m2hw0w6cc0c3bsl2s8pp-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0" + "store_path": "/nix/store/lvb2z93xn3m0m2hw0w6cc0c3bsl2s8pp-nixfmt-1.2.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0", + "path": "/nix/store/0qdx7ah7b1dwyxa03fblhcdjnpi29q25-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0" + "store_path": "/nix/store/0qdx7ah7b1dwyxa03fblhcdjnpi29q25-nixfmt-1.2.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0", + "path": "/nix/store/jicz2kx49mqif3hkl1m2wbwvx2lg457l-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0" + "store_path": "/nix/store/jicz2kx49mqif3hkl1m2wbwvx2lg457l-nixfmt-1.2.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0", + "path": "/nix/store/b5m1h822ln0s493r30sgns77618ws59n-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0" + "store_path": "/nix/store/b5m1h822ln0s493r30sgns77618ws59n-nixfmt-1.2.0" } } }, "shfmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#shfmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#shfmt", "source": "devbox-search", "version": "3.12.0", "systems": { @@ -179,47 +179,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0", + "path": "/nix/store/5ywb1qkbd829kazxxkcfxb356m7hljjw-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0" + "store_path": "/nix/store/5ywb1qkbd829kazxxkcfxb356m7hljjw-shfmt-3.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0", + "path": "/nix/store/bii41pz9k7xf3z3f80s1ip29l42488ry-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0" + "store_path": "/nix/store/bii41pz9k7xf3z3f80s1ip29l42488ry-shfmt-3.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0", + "path": "/nix/store/a8l3l8rdzs3agq7garh59m0xn8h3zgpq-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0" + "store_path": "/nix/store/a8l3l8rdzs3agq7garh59m0xn8h3zgpq-shfmt-3.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0", + "path": "/nix/store/r3pj36ll7v3ss2z679arpwkg7pnka3s3-shfmt-3.12.0", "default": true } ], - "store_path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0" + "store_path": "/nix/store/r3pj36ll7v3ss2z679arpwkg7pnka3s3-shfmt-3.12.0" } } }, "treefmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#treefmt", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#treefmt", "source": "devbox-search", "version": "2.4.0", "systems": { @@ -227,47 +227,47 @@ "outputs": [ { "name": "out", - "path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0", + "path": "/nix/store/37qcrdrfdf8b9pyli0j0vj9d69dykmpr-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0" + "store_path": "/nix/store/37qcrdrfdf8b9pyli0j0vj9d69dykmpr-treefmt-2.4.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0", + "path": "/nix/store/ccv7dxwff3xpivsdhrjbq3mpk0br5v7d-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0" + "store_path": "/nix/store/ccv7dxwff3xpivsdhrjbq3mpk0br5v7d-treefmt-2.4.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0", + "path": "/nix/store/sbq2psv4q9hvfvalk00g0pkqjl2912m1-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0" + "store_path": "/nix/store/sbq2psv4q9hvfvalk00g0pkqjl2912m1-treefmt-2.4.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0", + "path": "/nix/store/z8xrjfswqqpydc42lyas064pp8kxgnl0-treefmt-2.4.0", "default": true } ], - "store_path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0" + "store_path": "/nix/store/z8xrjfswqqpydc42lyas064pp8kxgnl0-treefmt-2.4.0" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#yarn-berry", "source": "devbox-search", "version": "4.12.0", "systems": { @@ -275,41 +275,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/k9bh72bpyqjnfq1nd3c6p1z2ijkx2yg6-yarn-berry-4.12.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/mcvbqzb1kir87g5pm5624c5ysnfh89wp-yarn-berry-4.12.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/hn3j954rlcc0gx8nm41sgfzbx0qwfq3c-yarn-berry-4.12.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/2pmvaaggpi7ikx9xmhy3x2j0rpklaqrv-yarn-berry-4.12.0" } } } From 16787a93037a99ee629f26ab36a2aa2645941198 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 10:58:51 -0600 Subject: [PATCH 26/32] fixes --- .github/workflows/android-e2e.yml | 10 ++- .github/workflows/ci-e2e-full.yml | 1 + .github/workflows/ci-e2e-latest.yml | 1 - .github/workflows/ios-e2e.yml | 10 +++ scripts/ios/actions.sh | 98 ++++++++++++++++++++++++----- scripts/ios/simctl.sh | 5 +- shells/android-max/devbox.json | 1 + shells/android-min/devbox.json | 1 + 8 files changed, 107 insertions(+), 20 deletions(-) diff --git a/.github/workflows/android-e2e.yml b/.github/workflows/android-e2e.yml index 4aede427a..2373a2f12 100644 --- a/.github/workflows/android-e2e.yml +++ b/.github/workflows/android-e2e.yml @@ -40,7 +40,15 @@ jobs: df -H - name: Resolve devbox config run: | - echo "DEVBOX_CONFIG=shells/android-${{ inputs.target }}/devbox.json" >> "$GITHUB_ENV" + case "${{ inputs.target }}" in + min|max) + echo "DEVBOX_CONFIG=shells/android-${{ inputs.target }}/devbox.json" >> "$GITHUB_ENV" + ;; + *) + echo "Unsupported target '${{ inputs.target }}' for CI. Use min or max." >&2 + exit 1 + ;; + esac - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 06994ae01..32cb8aa96 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -4,6 +4,7 @@ on: schedule: - cron: '0 6 * * *' workflow_dispatch: + pull_request: concurrency: group: e2e-full-${{ github.ref }} diff --git a/.github/workflows/ci-e2e-latest.yml b/.github/workflows/ci-e2e-latest.yml index 4a53194c1..3fa66bf64 100644 --- a/.github/workflows/ci-e2e-latest.yml +++ b/.github/workflows/ci-e2e-latest.yml @@ -2,7 +2,6 @@ name: E2E (Latest) on: workflow_dispatch: - pull_request: concurrency: group: e2e-latest-${{ github.ref }} diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index c96b77ccb..bf8317b25 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -31,6 +31,16 @@ jobs: YARN_ENABLE_HARDENED_MODE: 0 steps: - uses: actions/checkout@v4 + - name: Validate target + run: | + case "${{ inputs.target }}" in + min|max) + ;; + *) + echo "Unsupported target '${{ inputs.target }}' for CI. Use min or max." >&2 + exit 1 + ;; + esac - name: Resolve iOS runtime id: defaults run: | diff --git a/scripts/ios/actions.sh b/scripts/ios/actions.sh index 9b5f73a53..46394c79d 100644 --- a/scripts/ios/actions.sh +++ b/scripts/ios/actions.sh @@ -18,6 +18,52 @@ ios_run() { test) # shellcheck disable=SC1090 . "$SCRIPTS_DIR/ios/simctl.sh" + target_sdk="${TARGET_SDK:-max}" + runtime_version="" + device_name="" + case "$target_sdk" in + custom) + if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then + echo "TARGET_SDK=custom requires IOS_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + if [ -z "${IOS_RUNTIME_CUSTOM:-}" ]; then + echo "TARGET_SDK=custom requires IOS_RUNTIME_CUSTOM to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_CUSTOM}" + device_name="${IOS_CUSTOM_DEVICE}" + ;; + min) + if [ -z "${IOS_RUNTIME_MIN:-}" ]; then + echo "TARGET_SDK=min requires IOS_RUNTIME_MIN to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_MIN}" + device_name="${IOS_MIN_DEVICE:-iPhone 13}" + ;; + max) + if [ -z "${IOS_RUNTIME_MAX:-}" ]; then + echo "TARGET_SDK=max requires IOS_RUNTIME_MAX to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_MAX}" + device_name="${IOS_MAX_DEVICE:-iPhone 17}" + ;; + *) + echo "Unsupported TARGET_SDK '${target_sdk}'. Use min, max, or custom." >&2 + exit 1 + ;; + esac + + IOS_RUNTIME="$runtime_version" + IOS_DEVICE_NAMES="$device_name" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-$device_name}" + export IOS_RUNTIME IOS_DEVICE_NAMES DETOX_IOS_DEVICE + + if ! resolve_runtime_name_strict "$runtime_version"; then + exit 1 + fi ios_setup yarn install --immutable yarn e2e install @@ -41,23 +87,43 @@ ios_run() { ensure_simctl target_sdk="${TARGET_SDK:-max}" runtime_version="" - if [ "$target_sdk" = "custom" ]; then - if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then - echo "TARGET_SDK=custom requires IOS_CUSTOM_DEVICE to be set." >&2 + case "$target_sdk" in + custom) + if [ -z "${IOS_CUSTOM_DEVICE:-}" ]; then + echo "TARGET_SDK=custom requires IOS_CUSTOM_DEVICE to be set." >&2 + exit 1 + fi + if [ -z "${IOS_RUNTIME_CUSTOM:-}" ]; then + echo "TARGET_SDK=custom requires IOS_RUNTIME_CUSTOM to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_CUSTOM}" + IOS_DEVICE_NAMES="${IOS_CUSTOM_DEVICE}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_CUSTOM_DEVICE}}" + ;; + min) + if [ -z "${IOS_RUNTIME_MIN:-}" ]; then + echo "TARGET_SDK=min requires IOS_RUNTIME_MIN to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_MIN}" + IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-iPhone 13}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-iPhone 13}}" + ;; + max) + if [ -z "${IOS_RUNTIME_MAX:-}" ]; then + echo "TARGET_SDK=max requires IOS_RUNTIME_MAX to be set." >&2 + exit 1 + fi + runtime_version="${IOS_RUNTIME_MAX}" + IOS_DEVICE_NAMES="${IOS_MAX_DEVICE:-iPhone 17}" + DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MAX_DEVICE:-iPhone 17}}" + ;; + *) + echo "Unsupported TARGET_SDK '${target_sdk}'. Use min, max, or custom." >&2 exit 1 - fi - runtime_version="${IOS_RUNTIME_CUSTOM:-}" - IOS_DEVICE_NAMES="${IOS_CUSTOM_DEVICE}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_CUSTOM_DEVICE}}" - elif [ "$target_sdk" = "min" ]; then - runtime_version="${IOS_RUNTIME_MIN:-}" - IOS_DEVICE_NAMES="${IOS_MIN_DEVICE:-iPhone 13}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-${IOS_MIN_DEVICE:-iPhone 13}}" - else - runtime_version="${IOS_RUNTIME_MAX:-}" - IOS_DEVICE_NAMES="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" - DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-iPhone 17}" - fi + ;; + esac export IOS_DEVICE_NAMES DETOX_IOS_DEVICE if [ -n "$runtime_version" ]; then if ! resolve_runtime_name_strict "$runtime_version"; then diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index 5fc648b67..dde0f7903 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -239,8 +239,9 @@ ios_setup() { fi devices_list="${IOS_DEVICE_NAMES:-${IOS_MIN_DEVICE:-iPhone 13},${IOS_MAX_DEVICE:-iPhone 17}}" runtime="${IOS_RUNTIME:-${IOS_RUNTIME_MAX:-}}" - if [ -z "$runtime" ] && command -v xcrun >/dev/null 2>&1; then - runtime="$(xcrun --sdk iphonesimulator --show-sdk-version 2>/dev/null || true)" + if [ -z "$runtime" ]; then + echo "IOS_RUNTIME (or IOS_RUNTIME_MAX) must be set to create simulators." >&2 + return 1 fi ifs_backup="$IFS" diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index a9bc4bea8..33ee2a444 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -9,6 +9,7 @@ }, "shell": { "init_hook": [ + "export TARGET_SDK=max", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" ], diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 68b3f2c6d..bdff41f98 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -9,6 +9,7 @@ }, "shell": { "init_hook": [ + "export TARGET_SDK=min", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" ], From c1289dd6c5499193ea27a53ebfc169c0c70caf96 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 11:09:42 -0600 Subject: [PATCH 27/32] .xcode.env --- examples/AnalyticsReactNativeExample/.gitignore | 1 + examples/E2E-73/.gitignore | 1 + examples/E2E/.gitignore | 1 + examples/E2E/ios/.xcode.env | 11 ----------- scripts/env.sh | 13 +++++++++++++ scripts/ios/simctl.sh | 13 +++++++++++++ 6 files changed, 29 insertions(+), 11 deletions(-) delete mode 100644 examples/E2E/ios/.xcode.env diff --git a/examples/AnalyticsReactNativeExample/.gitignore b/examples/AnalyticsReactNativeExample/.gitignore index 0cab2ac6f..f6ca9014e 100644 --- a/examples/AnalyticsReactNativeExample/.gitignore +++ b/examples/AnalyticsReactNativeExample/.gitignore @@ -21,6 +21,7 @@ DerivedData *.ipa *.xcuserstate ios/.xcode.env.local +ios/.xcode.env # Android/IntelliJ # diff --git a/examples/E2E-73/.gitignore b/examples/E2E-73/.gitignore index 0cab2ac6f..f6ca9014e 100644 --- a/examples/E2E-73/.gitignore +++ b/examples/E2E-73/.gitignore @@ -21,6 +21,7 @@ DerivedData *.ipa *.xcuserstate ios/.xcode.env.local +ios/.xcode.env # Android/IntelliJ # diff --git a/examples/E2E/.gitignore b/examples/E2E/.gitignore index 0cab2ac6f..f6ca9014e 100644 --- a/examples/E2E/.gitignore +++ b/examples/E2E/.gitignore @@ -21,6 +21,7 @@ DerivedData *.ipa *.xcuserstate ios/.xcode.env.local +ios/.xcode.env # Android/IntelliJ # diff --git a/examples/E2E/ios/.xcode.env b/examples/E2E/ios/.xcode.env deleted file mode 100644 index 3d5782c71..000000000 --- a/examples/E2E/ios/.xcode.env +++ /dev/null @@ -1,11 +0,0 @@ -# This `.xcode.env` file is versioned and is used to source the environment -# used when running script phases inside Xcode. -# To customize your local environment, you can create an `.xcode.env.local` -# file that is not versioned. - -# NODE_BINARY variable contains the PATH to the node executable. -# -# Customize the NODE_BINARY variable here. -# For example, to use nvm with brew, add the following line -# . "$(brew --prefix nvm)/nvm.sh" --no-use -export NODE_BINARY=$(command -v node) diff --git a/scripts/env.sh b/scripts/env.sh index e14dde3bb..ce5388a8b 100644 --- a/scripts/env.sh +++ b/scripts/env.sh @@ -37,6 +37,19 @@ for shared_script in project.sh debug.sh tools.sh defaults.sh; do fi done +if [ -z "${IOS_NODE_BINARY:-}" ] && command -v node >/dev/null 2>&1; then + IOS_NODE_BINARY="$(command -v node)" + export IOS_NODE_BINARY +fi + +if [ -z "${IOS_XCODE_ENV_PATH:-}" ] && [ -n "${PROJECT_ROOT:-}" ]; then + xcode_env_path="$PROJECT_ROOT/examples/E2E/ios/.xcode.env" + if [ -d "$PROJECT_ROOT/examples/E2E/ios" ]; then + IOS_XCODE_ENV_PATH="$xcode_env_path" + export IOS_XCODE_ENV_PATH + fi +fi + if [ "${INIT_ANDROID:-}" = "1" ]; then # shellcheck disable=SC1090 . "$SCRIPTS_DIR/android/env.sh" diff --git a/scripts/ios/simctl.sh b/scripts/ios/simctl.sh index dde0f7903..ecb444d4b 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/ios/simctl.sh @@ -229,6 +229,19 @@ EOM } ios_setup() { + if [ -n "${IOS_XCODE_ENV_PATH:-}" ]; then + node_binary="${IOS_NODE_BINARY:-${NODE_BINARY:-}}" + if [ -z "$node_binary" ]; then + echo "IOS_XCODE_ENV_PATH is set but IOS_NODE_BINARY/NODE_BINARY is empty." >&2 + return 1 + fi + env_dir="$(dirname "$IOS_XCODE_ENV_PATH")" + if [ ! -d "$env_dir" ]; then + echo "IOS_XCODE_ENV_PATH directory does not exist: ${env_dir}" >&2 + return 1 + fi + printf 'export NODE_BINARY=%s\n' "$node_binary" >"$IOS_XCODE_ENV_PATH" + fi ensure_developer_dir require_tool xcrun "Missing required tool: xcrun. Install Xcode CLI tools before running (xcode-select --install or Xcode.app + xcode-select -s)." require_tool jq From 54a5845d9a46b4516ca9a84447ad602e3c75702b Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 11:26:32 -0600 Subject: [PATCH 28/32] some refactors --- .github/workflows/ios-e2e.yml | 10 +++--- devbox.json | 2 +- scripts/{ => bootstrap}/env.sh | 6 ++-- scripts/bootstrap/init.sh | 22 +++++++++++++ scripts/{ => platforms}/android/actions.sh | 10 +++--- scripts/{ => platforms}/android/avd.sh | 12 ++++--- scripts/{ => platforms}/android/env.sh | 8 ++--- scripts/{ => platforms}/android/lib.sh | 2 +- scripts/{ => platforms}/ios/actions.sh | 10 +++--- scripts/{ => platforms}/ios/env.sh | 10 +++--- scripts/{ => platforms}/ios/simctl.sh | 25 +++++++------- scripts/run.sh | 8 ++--- scripts/{ci => shared}/env-check.sh | 0 scripts/shared/tools.sh | 38 ++++++++++++++++++++++ shells/android-max/devbox.json | 2 +- shells/android-min/devbox.json | 2 +- shells/ios/devbox.json | 2 +- shells/minimal/devbox.json | 2 +- wiki/devbox.md | 12 +++---- wiki/nix.md | 4 +-- wiki/scripts.md | 28 +++++++++------- 21 files changed, 141 insertions(+), 74 deletions(-) rename scripts/{ => bootstrap}/env.sh (91%) create mode 100644 scripts/bootstrap/init.sh rename scripts/{ => platforms}/android/actions.sh (75%) rename scripts/{ => platforms}/android/avd.sh (94%) rename scripts/{ => platforms}/android/env.sh (97%) rename scripts/{ => platforms}/android/lib.sh (96%) rename scripts/{ => platforms}/ios/actions.sh (96%) rename scripts/{ => platforms}/ios/env.sh (94%) rename scripts/{ => platforms}/ios/simctl.sh (90%) rename scripts/{ci => shared}/env-check.sh (100%) diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index bf8317b25..9af19a331 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -85,7 +85,7 @@ jobs: with: xcode-version: ${{ steps.defaults.outputs.runtime }} - name: Environment check - run: sh scripts/ci/env-check.sh + run: sh scripts/shared/env-check.sh - name: Xcode diagnostics run: | set -euo pipefail @@ -100,6 +100,10 @@ jobs: if [ -n "$sdk_path" ]; then ls -la "$sdk_path/usr/lib/swift" || true fi + - name: Install Xcode components + run: | + sudo xcodebuild -runFirstLaunch -checkForNewerComponents + sudo xcodebuild -downloadPlatform iOS - name: Verify Swift compatibility libs run: | set -euo pipefail @@ -118,10 +122,6 @@ jobs: echo "sdk_swift_dir=${sdk_swift_dir}" >&2 exit 1 fi - - name: Install Xcode components - run: | - sudo xcodebuild -runFirstLaunch -checkForNewerComponents - sudo xcodebuild -downloadPlatform iOS - name: devbox installer uses: jetify-com/devbox-install-action@v0.14.0 with: diff --git a/devbox.json b/devbox.json index cc0d31727..d40715834 100644 --- a/devbox.json +++ b/devbox.json @@ -24,7 +24,7 @@ "shell": { "init_hook": [ "echo 'Welcome to analytics-react-native devbox!' > /dev/null", - "INIT_ANDROID=1 INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/env.sh" + "INIT_ANDROID=1 INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/bootstrap/env.sh" ], "scripts": { "clean": [ diff --git a/scripts/env.sh b/scripts/bootstrap/env.sh similarity index 91% rename from scripts/env.sh rename to scripts/bootstrap/env.sh index ce5388a8b..14a087e04 100644 --- a/scripts/env.sh +++ b/scripts/bootstrap/env.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/env.sh must be sourced." >&2 + echo "scripts/bootstrap/env.sh must be sourced." >&2 exit 1 fi @@ -52,12 +52,12 @@ fi if [ "${INIT_ANDROID:-}" = "1" ]; then # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/env.sh" + . "$SCRIPTS_DIR/platforms/android/env.sh" fi if [ "${INIT_IOS:-}" = "1" ] && [ "$(uname -s)" = "Darwin" ]; then # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/env.sh" + . "$SCRIPTS_DIR/platforms/ios/env.sh" fi SHARED_LOADED=1 diff --git a/scripts/bootstrap/init.sh b/scripts/bootstrap/init.sh new file mode 100644 index 000000000..c2d14aaec --- /dev/null +++ b/scripts/bootstrap/init.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env sh + +if ! (return 0 2>/dev/null); then + echo "scripts/bootstrap/init.sh must be sourced." >&2 + exit 1 +fi + +load_env() { + script_dir="$1" + init_path="$script_dir/bootstrap/env.sh" + if [ ! -f "$init_path" ]; then + repo_root="" + if command -v git >/dev/null 2>&1; then + repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" + fi + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/bootstrap/env.sh" ]; then + init_path="$repo_root/scripts/bootstrap/env.sh" + fi + fi + # shellcheck disable=SC1090 + . "$init_path" +} diff --git a/scripts/android/actions.sh b/scripts/platforms/android/actions.sh similarity index 75% rename from scripts/android/actions.sh rename to scripts/platforms/android/actions.sh index e85a011e0..d6d6a5510 100644 --- a/scripts/android/actions.sh +++ b/scripts/platforms/android/actions.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/android/actions.sh must be sourced." >&2 + echo "scripts/platforms/android/actions.sh must be sourced." >&2 exit 1 fi @@ -10,12 +10,12 @@ android_run() { shift 1 || true # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/env.sh" + . "$SCRIPTS_DIR/platforms/android/env.sh" case "$action" in test) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/avd.sh" + . "$SCRIPTS_DIR/platforms/android/avd.sh" android_setup yarn install --immutable yarn e2e install @@ -25,12 +25,12 @@ android_run() { ;; setup) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/avd.sh" + . "$SCRIPTS_DIR/platforms/android/avd.sh" android_setup "$@" ;; start | stop | reset) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/android/avd.sh" + . "$SCRIPTS_DIR/platforms/android/avd.sh" case "$action" in start) android_start "$@" ;; stop) android_stop "$@" ;; diff --git a/scripts/android/avd.sh b/scripts/platforms/android/avd.sh similarity index 94% rename from scripts/android/avd.sh rename to scripts/platforms/android/avd.sh index 788eb5dd4..2468f2fb8 100644 --- a/scripts/android/avd.sh +++ b/scripts/platforms/android/avd.sh @@ -2,18 +2,18 @@ set -eu if ! (return 0 2>/dev/null); then - echo "scripts/android/avd.sh must be sourced via scripts/run.sh." >&2 + echo "scripts/platforms/android/avd.sh must be sourced via scripts/run.sh." >&2 exit 1 fi scripts_root="${SCRIPTS_DIR:-$(cd "$(dirname "$0")" && pwd)}" -android_dir="$scripts_root/android" +android_dir="$scripts_root/platforms/android" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then # shellcheck disable=SC1090 - . "$scripts_root/lib/bootstrap.sh" + . "$scripts_root/bootstrap/init.sh" load_env "$scripts_root" fi -debug_log_script "scripts/android/avd.sh" +debug_log_script "scripts/platforms/android/avd.sh" # shellcheck disable=SC1090 . "$android_dir/lib.sh" @@ -191,6 +191,7 @@ TARGET_EOF fi target_dir="$ANDROID_SDK_ROOT/system-images/android-${target_api}/${target_tag}" + require_dir_contains "$ANDROID_SDK_ROOT" "system-images/android-${target_api}/${target_tag}" "Missing system image directory for API ${target_api} (${target_tag}) under ${ANDROID_SDK_ROOT}. Re-enter the devbox shell or rebuild Devbox to fetch images." if [ -d "$target_dir" ]; then add_target "${target_api}|${target_tag}|${target_device}|${target_preferred_abi}|${AVD_NAME:-}" else @@ -224,6 +225,9 @@ TARGET_EOF api_image="$(pick_image "$api" "$tag" "$preferred_abi" 2>/dev/null || true)" fi if [ -z "$api_image" ]; then + if [ -n "$preferred_abi" ]; then + require_dir_contains "$ANDROID_SDK_ROOT" "system-images/android-${api}/${tag}/${preferred_abi}" "Missing preferred ABI ${preferred_abi} for API ${api} (${tag}) under ${ANDROID_SDK_ROOT}." + fi base_dir="${ANDROID_SDK_ROOT}/system-images/android-${api}/${tag}" if [ -d "$base_dir" ]; then available_abis="$(ls -1 "$base_dir" 2>/dev/null | tr '\n' ' ' | sed 's/[[:space:]]*$//')" diff --git a/scripts/android/env.sh b/scripts/platforms/android/env.sh similarity index 97% rename from scripts/android/env.sh rename to scripts/platforms/android/env.sh index a0a91d8d0..e2dd6f586 100755 --- a/scripts/android/env.sh +++ b/scripts/platforms/android/env.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/android/env.sh must be sourced via scripts/run.sh or scripts/env.sh." >&2 + echo "scripts/platforms/android/env.sh must be sourced via scripts/run.sh or scripts/bootstrap/env.sh." >&2 exit 1 fi project_root="${PROJECT_ROOT:-}" @@ -11,12 +11,12 @@ fi if [ -z "$project_root" ]; then project_root="$(cd "$(dirname "$0")/../.." && pwd)" fi -script_dir="$project_root/scripts/android" +script_dir="$project_root/scripts/platforms/android" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then # shellcheck disable=SC1090 - . "$project_root/scripts/env.sh" + . "$project_root/scripts/bootstrap/env.sh" fi -debug_log_script "scripts/android/env.sh" +debug_log_script "scripts/platforms/android/env.sh" diff --git a/scripts/android/lib.sh b/scripts/platforms/android/lib.sh similarity index 96% rename from scripts/android/lib.sh rename to scripts/platforms/android/lib.sh index cf86fcc51..f19f32292 100644 --- a/scripts/android/lib.sh +++ b/scripts/platforms/android/lib.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/android/lib.sh must be sourced." >&2 + echo "scripts/platforms/android/lib.sh must be sourced." >&2 exit 1 fi diff --git a/scripts/ios/actions.sh b/scripts/platforms/ios/actions.sh similarity index 96% rename from scripts/ios/actions.sh rename to scripts/platforms/ios/actions.sh index 46394c79d..0dfe91ade 100644 --- a/scripts/ios/actions.sh +++ b/scripts/platforms/ios/actions.sh @@ -1,7 +1,7 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/ios/actions.sh must be sourced." >&2 + echo "scripts/platforms/ios/actions.sh must be sourced." >&2 exit 1 fi @@ -11,13 +11,13 @@ ios_run() { if [ "$(uname -s)" = "Darwin" ]; then # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/env.sh" + . "$SCRIPTS_DIR/platforms/ios/env.sh" fi case "$action" in test) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/simctl.sh" + . "$SCRIPTS_DIR/platforms/ios/simctl.sh" target_sdk="${TARGET_SDK:-max}" runtime_version="" device_name="" @@ -74,12 +74,12 @@ ios_run() { ;; setup) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/simctl.sh" + . "$SCRIPTS_DIR/platforms/ios/simctl.sh" ios_setup "$@" ;; start | stop | reset) # shellcheck disable=SC1090 - . "$SCRIPTS_DIR/ios/simctl.sh" + . "$SCRIPTS_DIR/platforms/ios/simctl.sh" case "$action" in start) ensure_developer_dir diff --git a/scripts/ios/env.sh b/scripts/platforms/ios/env.sh similarity index 94% rename from scripts/ios/env.sh rename to scripts/platforms/ios/env.sh index 5e26c2e65..0adcd4ae2 100755 --- a/scripts/ios/env.sh +++ b/scripts/platforms/ios/env.sh @@ -1,27 +1,27 @@ #!/usr/bin/env sh if ! (return 0 2>/dev/null); then - echo "scripts/ios/env.sh must be sourced via scripts/run.sh or scripts/env.sh." >&2 + echo "scripts/platforms/ios/env.sh must be sourced via scripts/run.sh or scripts/bootstrap/env.sh." >&2 exit 1 fi set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then - init_path="$script_dir/../env.sh" + init_path="$script_dir/../../bootstrap/env.sh" if [ ! -f "$init_path" ]; then repo_root="" if command -v git >/dev/null 2>&1; then repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" fi - if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then - init_path="$repo_root/scripts/env.sh" + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/bootstrap/env.sh" ]; then + init_path="$repo_root/scripts/bootstrap/env.sh" fi fi # shellcheck disable=SC1090 . "$init_path" fi -debug_log_script "scripts/ios/env.sh" +debug_log_script "scripts/platforms/ios/env.sh" devbox_omit_nix_env() { if [ "${DEVBOX_OMIT_NIX_ENV_APPLIED:-}" = "1" ]; then diff --git a/scripts/ios/simctl.sh b/scripts/platforms/ios/simctl.sh similarity index 90% rename from scripts/ios/simctl.sh rename to scripts/platforms/ios/simctl.sh index ecb444d4b..6dddcd631 100644 --- a/scripts/ios/simctl.sh +++ b/scripts/platforms/ios/simctl.sh @@ -2,26 +2,26 @@ set -eu if ! (return 0 2>/dev/null); then - echo "scripts/ios/simctl.sh must be sourced via scripts/run.sh." >&2 + echo "scripts/platforms/ios/simctl.sh must be sourced via scripts/run.sh." >&2 exit 1 fi script_dir="$(cd "$(dirname "$0")" && pwd)" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then - init_path="$script_dir/../env.sh" + init_path="$script_dir/../../bootstrap/env.sh" if [ ! -f "$init_path" ]; then repo_root="" if command -v git >/dev/null 2>&1; then repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" fi - if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/env.sh" ]; then - init_path="$repo_root/scripts/env.sh" + if [ -n "$repo_root" ] && [ -f "$repo_root/scripts/bootstrap/env.sh" ]; then + init_path="$repo_root/scripts/bootstrap/env.sh" fi fi # shellcheck disable=SC1090 . "$init_path" fi -debug_log_script "scripts/ios/simctl.sh" +debug_log_script "scripts/platforms/ios/simctl.sh" ensure_core_sim_service() { status=0 @@ -203,15 +203,14 @@ ensure_developer_dir() { fi fi - if [ -n "$desired" ] && [ -d "$desired" ]; then - DEVELOPER_DIR="$desired" - PATH="$DEVELOPER_DIR/usr/bin:$PATH" - export DEVELOPER_DIR PATH - return 0 - fi + require_dir "$desired" "Xcode developer directory not found. Install Xcode/CLI tools or set IOS_DEVELOPER_DIR to an Xcode path (e.g., /Applications/Xcode.app/Contents/Developer)." + require_dir_contains "$desired" "Toolchains/XcodeDefault.xctoolchain" "Xcode toolchain missing under ${desired}." + require_dir_contains "$desired" "Platforms/iPhoneSimulator.platform" "iPhoneSimulator platform missing under ${desired}." - echo "Xcode developer directory not found. Install Xcode/CLI tools or set IOS_DEVELOPER_DIR to an Xcode path (e.g., /Applications/Xcode.app/Contents/Developer)." >&2 - exit 1 + DEVELOPER_DIR="$desired" + PATH="$DEVELOPER_DIR/usr/bin:$PATH" + export DEVELOPER_DIR PATH + return 0 } ensure_simctl() { diff --git a/scripts/run.sh b/scripts/run.sh index 96afbefc1..77f8665c8 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -2,7 +2,7 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" -lib_dir="$script_dir/lib" +bootstrap_dir="$script_dir/bootstrap" if [ "${RUN_SH_ACTIVE:-}" = "1" ]; then echo "scripts/run.sh is already running." >&2 @@ -12,7 +12,7 @@ RUN_SH_ACTIVE=1 export RUN_SH_ACTIVE # shellcheck disable=SC1090 -. "$lib_dir/bootstrap.sh" +. "$bootstrap_dir/init.sh" load_env "$script_dir" debug_log_script "scripts/run.sh" @@ -32,12 +32,12 @@ run_build() { case "$platform" in android) # shellcheck disable=SC1090 - . "$scripts_root/android/actions.sh" + . "$scripts_root/platforms/android/actions.sh" android_run "$action" "$@" ;; ios) # shellcheck disable=SC1090 - . "$scripts_root/ios/actions.sh" + . "$scripts_root/platforms/ios/actions.sh" ios_run "$action" "$@" ;; build) diff --git a/scripts/ci/env-check.sh b/scripts/shared/env-check.sh similarity index 100% rename from scripts/ci/env-check.sh rename to scripts/shared/env-check.sh diff --git a/scripts/shared/tools.sh b/scripts/shared/tools.sh index e79308d64..56c0eae78 100644 --- a/scripts/shared/tools.sh +++ b/scripts/shared/tools.sh @@ -19,3 +19,41 @@ require_tool() { exit 1 fi } + +require_file() { + path="$1" + message="${2:-Missing required file: $path.}" + if [ ! -f "$path" ]; then + echo "$message" >&2 + exit 1 + fi +} + +require_dir() { + path="$1" + message="${2:-Missing required directory: $path.}" + if [ ! -d "$path" ]; then + echo "$message" >&2 + exit 1 + fi +} + +require_dir_contains() { + base="$1" + subpath="$2" + message="${3:-Missing required path: $base/$subpath.}" + if [ ! -e "$base/$subpath" ]; then + echo "$message" >&2 + exit 1 + fi +} + +require_var() { + var_name="$1" + message="${2:-Missing required environment variable: $var_name.}" + value="$(eval "printf '%s' \"\${$var_name-}\"")" + if [ -z "$value" ]; then + echo "$message" >&2 + exit 1 + fi +} diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index 33ee2a444..44db84ca6 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -11,7 +11,7 @@ "init_hook": [ "export TARGET_SDK=max", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-max", - "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" + "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh" ], "scripts": { "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index bdff41f98..1c40ecbdf 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -11,7 +11,7 @@ "init_hook": [ "export TARGET_SDK=min", "export ANDROID_SDK_FLAKE_OUTPUT=android-sdk-min", - "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" + "INIT_ANDROID=1 . $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh" ], "scripts": { "setup-android": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh android setup"], diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index eea48488c..19d2984ff 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -10,7 +10,7 @@ }, "shell": { "init_hook": [ - "INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/env.sh" + "INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh" ], "scripts": { "setup-ios": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh ios setup"], diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index c4b975083..afcd90fff 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -8,7 +8,7 @@ "shfmt": "latest" }, "shell": { - "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/env.sh"], + "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh"], "scripts": { "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh build"], "release": [ diff --git a/wiki/devbox.md b/wiki/devbox.md index 4901fa929..2801a8bda 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -13,16 +13,16 @@ Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT ## Android -By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/android/env.sh`. To use a local SDK instead, launch with `ANDROID_LOCAL_SDK=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_LOCAL_SDK` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/android/avd.sh`). Version sources are documented in `wiki/nix.md`. +By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/platforms/android/env.sh`. To use a local SDK instead, launch with `ANDROID_LOCAL_SDK=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_LOCAL_SDK` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/platforms/android/avd.sh`). Version sources are documented in `wiki/nix.md`. Example custom targets (root `devbox.json` sets these via `shell.env` for testing): `ANDROID_CUSTOM_API=29` `ANDROID_CUSTOM_DEVICE=pixel_6` `IOS_CUSTOM_DEVICE="iPhone 15"` ### Emulator/AVD scripts -- `devbox run start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/android/avd.sh`. -- `devbox run start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/android/avd.sh` if it does not exist. -- `scripts/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. +- `devbox run start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/platforms/android/avd.sh`. +- `devbox run start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/platforms/android/avd.sh` if it does not exist. +- `scripts/platforms/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. - `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. - `EMU_HEADLESS=1 devbox run start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. - `EMU_PORT=5554 devbox run start-android*` to set the emulator port/serial (defaults to 5554) and avoid adb conflicts. @@ -46,11 +46,11 @@ Example custom targets (root `devbox.json` sets these via `shell.env` for testin iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `devbox run setup-ios` to provision simulators and validate Xcode tooling. Full Xcode is required for `simctl` (Command Line Tools alone are not enough). Make sure Xcode command line tools are selected (`xcode-select --print-path` or `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`) and that you have agreed to the license if prompted. -> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/run.sh` re-applies it before running iOS E2E. +> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/platforms/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/run.sh` re-applies it before running iOS E2E. ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/ios/simctl.sh`. +- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/platforms/ios/simctl.sh`. - `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `TARGET_SDK=min` to target the min sim (per `nix/defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. - `devbox run reset-ios` shuts down/erases and removes all local simulator devices. - `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). diff --git a/wiki/nix.md b/wiki/nix.md index 9984992fd..2b1334598 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -14,7 +14,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc - Single source of truth for Android/iOS min and max targets. - Contains Android build tools + cmdline tools versions. -- `scripts/env.sh` +- `scripts/bootstrap/env.sh` - Establishes `PROJECT_ROOT` and `SCRIPTS_DIR` for scripts and CI. ## How versions flow @@ -22,7 +22,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc 1. `nix/defaults.json` is updated. 2. `nix/flake.nix` reads those values when building the Android SDK output. 3. `scripts/shared/defaults.sh` loads defaults (via `jq`) and establishes script root context for: - - scripts under `scripts/android/` and `scripts/ios/` + - scripts under `scripts/platforms/android/` and `scripts/platforms/ios/` - CI workflows that set min/max targets ## Updating versions diff --git a/wiki/scripts.md b/wiki/scripts.md index 24284d40c..66d2e2c9a 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -1,17 +1,18 @@ # Scripts Overview -This repo uses `scripts/` as the entry point for devbox commands and CI helpers. Scripts are organized by platform with a small shared helper layer. +This repo uses `scripts/` as the entry point for devbox commands and tasks. Scripts are organized by platform with a small shared helper layer. ## Layout -- `scripts/run.sh`: entrypoint for devbox/CI tasks (build/test/act). -- `scripts/env.sh`: establishes `PROJECT_ROOT`/`SCRIPTS_DIR`, loads `scripts/shared/*`, and optionally initializes platforms when `INIT_ANDROID`/`INIT_IOS` are set. +- `scripts/run.sh`: entrypoint for tasks (build/test). +- `scripts/bootstrap/env.sh`: establishes `PROJECT_ROOT`/`SCRIPTS_DIR`, loads `scripts/shared/*`, and optionally initializes platforms when `INIT_ANDROID`/`INIT_IOS` are set. +- `scripts/bootstrap/init.sh`: bootstraps `scripts/bootstrap/env.sh` when invoked from `scripts/run.sh`. - `scripts/shared/project.sh`: project root + scripts path helpers. - `scripts/shared/tools.sh`: shared tool checks. - `scripts/shared/defaults.sh`: loads `nix/defaults.json` via `jq`. -- `scripts/android/`: Android SDK, AVD, and E2E helpers. -- `scripts/ios/`: iOS simulator setup, toolchain fixups, and E2E helpers. -- `scripts/android/actions.sh` + `scripts/ios/actions.sh`: platform task dispatchers called by `scripts/run.sh`. +- `scripts/platforms/android/`: Android SDK, AVD, and E2E helpers. +- `scripts/platforms/ios/`: iOS simulator setup, toolchain fixups, and E2E helpers. +- `scripts/platforms/android/actions.sh` + `scripts/platforms/ios/actions.sh`: platform task dispatchers called by `scripts/run.sh`. ## Shared helpers @@ -20,19 +21,23 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. - `SCRIPTS_DIR`: defaults to `$PROJECT_ROOT/scripts` when unset. - `scripts/shared/tools.sh` - `require_tool`: asserts a tool exists (with an optional custom message). + - `require_file`: asserts a file exists (with an optional custom message). + - `require_dir`: asserts a directory exists (with an optional custom message). + - `require_dir_contains`: asserts a directory contains a specific subpath (with an optional custom message). + - `require_var`: asserts an env var is set (with an optional custom message). - `scripts/shared/defaults.sh` - Loads `nix/defaults.json` (via `jq`) to export default env vars when available. ## Android scripts -- `scripts/android/env.sh` +- `scripts/platforms/android/env.sh` - Sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH for the Nix SDK (prefers `android-sdk-max` when available). - Set `ANDROID_LOCAL_SDK=1` to keep a pre-set local SDK instead. - Loads platform defaults via `scripts/shared/defaults.sh` (from `nix/defaults.json`). - Used by devbox init hooks in `devbox.json` and `shells/android-min/devbox.json` + `shells/android-max/devbox.json`. -- `scripts/android/avd.sh` +- `scripts/platforms/android/avd.sh` - Creates/ensures AVDs for the target API level, then starts/stops/resets emulators. - Depends on `sdkmanager`, `avdmanager`, `emulator` in PATH (Devbox shell). @@ -41,13 +46,13 @@ This repo uses `scripts/` as the entry point for devbox commands and CI helpers. ## iOS scripts -- `scripts/ios/env.sh` +- `scripts/platforms/ios/env.sh` - Workaround for Devbox macOS toolchain injection. - Removes Nix toolchain variables and re-selects system clang/Xcode. - Sourced by devbox init hooks and re-applied in `scripts/run.sh` for iOS tasks. -- `scripts/ios/simctl.sh` +- `scripts/platforms/ios/simctl.sh` - Helpers for runtime selection and simulator management. - Ensures Xcode tools are selected and simulators exist. @@ -97,9 +102,8 @@ Root devbox (`devbox.json`) exposes: - `test-ios` -> `scripts/run.sh ios test` - `setup-android` -> `scripts/run.sh android setup` - `setup-ios` -> `scripts/run.sh ios setup` -- `start-android*` -> `scripts/run.sh android start` (uses `scripts/android/avd.sh`) +- `start-android*` -> `scripts/run.sh android start` (uses `scripts/platforms/android/avd.sh`) - `start-ios` -> `scripts/run.sh ios start` -- `act` -> `scripts/run.sh act ` Slim CI shells: From 3f305c3dab626ec3900bfc5c9d11f89e9fc14689 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 11:43:08 -0600 Subject: [PATCH 29/32] fix min matrix and compile target --- .github/workflows/ci-e2e-full.yml | 3 +++ .github/workflows/publish.yml | 3 +++ nix/flake.nix | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-e2e-full.yml b/.github/workflows/ci-e2e-full.yml index 32cb8aa96..17cef47e5 100644 --- a/.github/workflows/ci-e2e-full.yml +++ b/.github/workflows/ci-e2e-full.yml @@ -17,11 +17,14 @@ jobs: include: - name: ios-min target: min + runs_on: macos-14 - name: ios-latest target: max + runs_on: macos-26 uses: ./.github/workflows/ios-e2e.yml with: target: ${{ matrix.target }} + runs_on: ${{ matrix.runs_on }} secrets: inherit run-e2e-android: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3088a6068..74787f41c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -29,11 +29,14 @@ jobs: include: - name: ios-min target: min + runs_on: macos-14 - name: ios-latest target: max + runs_on: macos-26 uses: ./.github/workflows/ios-e2e.yml with: target: ${{ matrix.target }} + runs_on: ${{ matrix.runs_on }} secrets: inherit e2e-android: diff --git a/nix/flake.nix b/nix/flake.nix index 0802c8823..33ef1d7e1 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -37,7 +37,10 @@ systemImageTypes = [ (getVar "ANDROID_SYSTEM_IMAGE_TAG") ]; }; androidSdkConfigMin = androidSdkConfig // { - platformVersions = [ (getVar "ANDROID_MIN_API") ]; + platformVersions = unique [ + (getVar "ANDROID_MIN_API") + (getVar "ANDROID_MAX_API") + ]; }; androidSdkConfigMax = androidSdkConfig // { platformVersions = [ (getVar "ANDROID_MAX_API") ]; From f9d38b2ce9303f752899e5e424aa63345dcda870 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 11:47:14 -0600 Subject: [PATCH 30/32] change xcode to 15.4 --- nix/defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/defaults.json b/nix/defaults.json index dee7ead7f..b67112e15 100644 --- a/nix/defaults.json +++ b/nix/defaults.json @@ -11,7 +11,7 @@ "ANDROID_MAX_DEVICE": "medium_phone", "ANALYTICS_CI_DEBUG": "0", "DEBUG": "0", - "IOS_RUNTIME_MIN": "15.5", + "IOS_RUNTIME_MIN": "15.4", "IOS_RUNTIME_MAX": "26.2", "IOS_MIN_DEVICE": "iPhone 13", "IOS_MAX_DEVICE": "iPhone 17" From 7d30278dc668a62c045ccc6ae75424c9655ba6a9 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 12:01:33 -0600 Subject: [PATCH 31/32] fix invalid flag on older xcode --- .github/workflows/ios-e2e.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index 9af19a331..9d2567d75 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -102,7 +102,11 @@ jobs: fi - name: Install Xcode components run: | - sudo xcodebuild -runFirstLaunch -checkForNewerComponents + if xcodebuild -help 2>&1 | grep -q "checkForNewerComponents"; then + sudo xcodebuild -runFirstLaunch -checkForNewerComponents + else + sudo xcodebuild -runFirstLaunch + fi sudo xcodebuild -downloadPlatform iOS - name: Verify Swift compatibility libs run: | From f9aa6d1e2b1b48c6c7dae988438f8a536dd07b08 Mon Sep 17 00:00:00 2001 From: Andrea Bueide Date: Thu, 29 Jan 2026 13:09:41 -0600 Subject: [PATCH 32/32] enforce purity --- .github/workflows/android-e2e.yml | 2 +- .github/workflows/ci-fast.yml | 2 +- .github/workflows/ios-e2e.yml | 2 +- .github/workflows/publish.yml | 6 +- .github/workflows/release-dry-run.yml | 2 +- devbox.json | 12 + devbox.lock | 561 ++++++++++++++++++++++++++ nix/applesimutils.nix | 34 ++ nix/flake.nix | 3 + scripts/bootstrap/env.sh | 6 +- scripts/bootstrap/init.sh | 5 + scripts/platforms/android/env.sh | 16 + scripts/platforms/ios/actions.sh | 3 + scripts/platforms/ios/env.sh | 6 + scripts/platforms/ios/simctl.sh | 7 + shells/android-max/devbox.json | 7 + shells/android-min/devbox.json | 7 + shells/ios/devbox.json | 12 + shells/minimal/devbox.json | 11 +- wiki/devbox.md | 50 +-- wiki/nix.md | 2 +- wiki/release.md | 4 +- wiki/scripts.md | 2 +- 23 files changed, 724 insertions(+), 38 deletions(-) create mode 100644 nix/applesimutils.nix diff --git a/.github/workflows/android-e2e.yml b/.github/workflows/android-e2e.yml index 2373a2f12..deca04cc5 100644 --- a/.github/workflows/android-e2e.yml +++ b/.github/workflows/android-e2e.yml @@ -55,4 +55,4 @@ jobs: project-path: ${{ env.DEVBOX_CONFIG }} enable-cache: 'false' - name: Android E2E Tests - run: devbox run --config=${{ env.DEVBOX_CONFIG }} test-android + run: devbox run --pure --config=${{ env.DEVBOX_CONFIG }} test-android diff --git a/.github/workflows/ci-fast.yml b/.github/workflows/ci-fast.yml index 5534f4006..a84dea6ce 100644 --- a/.github/workflows/ci-fast.yml +++ b/.github/workflows/ci-fast.yml @@ -21,4 +21,4 @@ jobs: project-path: shells/minimal/devbox.json enable-cache: 'false' - name: build - run: devbox run --config=shells/minimal/devbox.json build + run: devbox run --pure --config=shells/minimal/devbox.json build diff --git a/.github/workflows/ios-e2e.yml b/.github/workflows/ios-e2e.yml index 9d2567d75..92c69b32e 100644 --- a/.github/workflows/ios-e2e.yml +++ b/.github/workflows/ios-e2e.yml @@ -132,7 +132,7 @@ jobs: project-path: ${{ inputs.devbox_config }} enable-cache: 'false' - name: iOS E2E Tests - run: devbox run --config=${{ inputs.devbox_config }} test-ios + run: devbox run --pure --config=${{ inputs.devbox_config }} test-ios env: TARGET_SDK: ${{ inputs.target }} IOS_RUNTIME_MIN: ${{ steps.defaults.outputs.runtime_min }} diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 74787f41c..3255079bc 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,7 +20,7 @@ jobs: project-path: shells/minimal/devbox.json enable-cache: 'false' - name: build - run: devbox run --config=shells/minimal/devbox.json build + run: devbox run --pure --config=shells/minimal/devbox.json build e2e-ios: name: E2E iOS (min/max) @@ -75,7 +75,7 @@ jobs: enable-cache: 'false' - name: Config, Build, Release - run: devbox run --config=shells/minimal/devbox.json release + run: devbox run --pure --config=shells/minimal/devbox.json release env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }} @@ -83,4 +83,4 @@ jobs: - name: Update Apps run: | - devbox run update-apps + devbox run --pure update-apps diff --git a/.github/workflows/release-dry-run.yml b/.github/workflows/release-dry-run.yml index b6a918335..0cc1aa6ac 100644 --- a/.github/workflows/release-dry-run.yml +++ b/.github/workflows/release-dry-run.yml @@ -20,6 +20,6 @@ jobs: project-path: shells/minimal/devbox.json enable-cache: 'false' - name: Release Dry Run - run: devbox run --config=shells/minimal/devbox.json release-dry-run + run: devbox run --pure --config=shells/minimal/devbox.json release-dry-run env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/devbox.json b/devbox.json index d40715834..6f4d41516 100644 --- a/devbox.json +++ b/devbox.json @@ -6,6 +6,17 @@ "platforms": ["x86_64-darwin", "aarch64-darwin"] }, "yarn-berry": "latest", + "git": "latest", + "bash": "latest", + "nodejs": "latest", + "coreutils": "latest", + "gnused": "latest", + "gnugrep": "latest", + "gawk": "latest", + "path:./nix#applesimutils": { + "version": "", + "platforms": ["aarch64-darwin", "x86_64-darwin"] + }, "treefmt": "latest", "nixfmt": "latest", "shfmt": "latest", @@ -24,6 +35,7 @@ "shell": { "init_hook": [ "echo 'Welcome to analytics-react-native devbox!' > /dev/null", + "export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8", "INIT_ANDROID=1 INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/scripts/bootstrap/env.sh" ], "scripts": { diff --git a/devbox.lock b/devbox.lock index 07fb8283c..aa64719ac 100644 --- a/devbox.lock +++ b/devbox.lock @@ -49,6 +49,130 @@ } } }, + "bash@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#bash", + "source": "devbox-search", + "version": "5.3p9", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ngqf98amj0hv0jhzhz540p03wxjj0chj-bash-interactive-5.3p9", + "default": true + }, + { + "name": "man", + "path": "/nix/store/k23hpm86ymd7l92c7cg0a2wsjadr8mx6-bash-interactive-5.3p9-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/vhhwpi6h16bxbrvx1sdg5ag973dln1r9-bash-interactive-5.3p9-dev" + }, + { + "name": "doc", + "path": "/nix/store/dahmvcafcvsp553w8lhkqy2ppv7gd6m5-bash-interactive-5.3p9-doc" + }, + { + "name": "info", + "path": "/nix/store/lqd7rdyads0i42dhxj8zwzj0d01hbgqf-bash-interactive-5.3p9-info" + } + ], + "store_path": "/nix/store/ngqf98amj0hv0jhzhz540p03wxjj0chj-bash-interactive-5.3p9" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/62p6g8nz491c6z224wc6ci1m699y2jhn-bash-interactive-5.3p9", + "default": true + }, + { + "name": "man", + "path": "/nix/store/1ma79ibx4dn0hdbflsxyxccrxzjqqwr3-bash-interactive-5.3p9-man", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/3a9xbr58hfgbj42rmsd9x2fwnir2aasy-bash-interactive-5.3p9-doc" + }, + { + "name": "info", + "path": "/nix/store/h87j74dh8b6lrj11720bda5qq1zfzac0-bash-interactive-5.3p9-info" + }, + { + "name": "debug", + "path": "/nix/store/j1i5n2snbiim8s63x9d41yiqv1anmsvi-bash-interactive-5.3p9-debug" + }, + { + "name": "dev", + "path": "/nix/store/n2i7ipwdbxiypxfballikvp8gx4jkivz-bash-interactive-5.3p9-dev" + } + ], + "store_path": "/nix/store/62p6g8nz491c6z224wc6ci1m699y2jhn-bash-interactive-5.3p9" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/n129ikd89z3didy0p2xw8hqgfaphyv11-bash-interactive-5.3p9", + "default": true + }, + { + "name": "man", + "path": "/nix/store/2m52h1lgaahqz6fag0aqw1499fjzq473-bash-interactive-5.3p9-man", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/7px2mpd1qj0106g64qp411p2y5cwlzbz-bash-interactive-5.3p9-dev" + }, + { + "name": "doc", + "path": "/nix/store/s9wwkzamvd36hwz94661rzg0s8bs86bc-bash-interactive-5.3p9-doc" + }, + { + "name": "info", + "path": "/nix/store/z9v40pvapyx3qd6liy9q4v6iwncwapl5-bash-interactive-5.3p9-info" + } + ], + "store_path": "/nix/store/n129ikd89z3didy0p2xw8hqgfaphyv11-bash-interactive-5.3p9" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/x12lw455sq6qy2wcya85d7rb88ybc3df-bash-interactive-5.3p9", + "default": true + }, + { + "name": "man", + "path": "/nix/store/1yg24id0csjk4nq1a3apimwf8dqisr9d-bash-interactive-5.3p9-man", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/sihl8njk3077kr0bh1fnagdxy83hbyfb-bash-interactive-5.3p9-debug" + }, + { + "name": "dev", + "path": "/nix/store/a1phwny3n394ij9j7csxa51lvb7nf45d-bash-interactive-5.3p9-dev" + }, + { + "name": "doc", + "path": "/nix/store/64qrsa2hiz1ayjv0m655cqwzx54hib9w-bash-interactive-5.3p9-doc" + }, + { + "name": "info", + "path": "/nix/store/by59bhs57xx4i2nh01bsjm3gdprgrby1-bash-interactive-5.3p9-info" + } + ], + "store_path": "/nix/store/x12lw455sq6qy2wcya85d7rb88ybc3df-bash-interactive-5.3p9" + } + } + }, "cocoapods@latest": { "last_modified": "2026-01-23T17:20:52Z", "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#cocoapods", @@ -77,10 +201,366 @@ } } }, + "coreutils@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#coreutils", + "source": "devbox-search", + "version": "9.9", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/hf6y9njhfwvigr25kzrwmsvmv6jpni5n-coreutils-9.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/6bf622yq75zzhq5mdn187sk70sxs6fkh-coreutils-9.9-info" + } + ], + "store_path": "/nix/store/hf6y9njhfwvigr25kzrwmsvmv6jpni5n-coreutils-9.9" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/5pwllqskykz2by85b87kp1a8af587vcn-coreutils-9.9", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/q3bqmaf9gi315ghy600wsyamzmnahkhk-coreutils-9.9-debug" + }, + { + "name": "info", + "path": "/nix/store/fxvw68h1qhpydph2l8j9p4hhs48va1fc-coreutils-9.9-info" + } + ], + "store_path": "/nix/store/5pwllqskykz2by85b87kp1a8af587vcn-coreutils-9.9" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/qgdq763j9ddmj7aq45x3s5108qvq4z7q-coreutils-9.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/fvsrfwspi4w7kkn2wvmhjv0f9jrzwqja-coreutils-9.9-info" + } + ], + "store_path": "/nix/store/qgdq763j9ddmj7aq45x3s5108qvq4z7q-coreutils-9.9" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/7c3i7919ys6jk8qkccspz3bkc1lv82d9-coreutils-9.9-info" + }, + { + "name": "debug", + "path": "/nix/store/fzcbb02abzvmyrvpa360abfbspnz9l1j-coreutils-9.9-debug" + } + ], + "store_path": "/nix/store/i2vmgx46q9hd3z6rigaiman3wl3i2gc4-coreutils-9.9" + } + } + }, + "gawk@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#gawk", + "source": "devbox-search", + "version": "5.3.2", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/78jn4adsl7zf2padciq7bfq15qykn5wf-gawk-5.3.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/1gj15nimzw33ik7l2cqs2ry52yxgiq2h-gawk-5.3.2-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/0a3x2fkdzkbkkqz4myjsr6r19n3mgiz4-gawk-5.3.2-info" + } + ], + "store_path": "/nix/store/78jn4adsl7zf2padciq7bfq15qykn5wf-gawk-5.3.2" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/p1ff2bvyyb0vzskfkls91nvpf8g7zwcc-gawk-5.3.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/9aqrvrdpz4viqmdw1fy6f8855ixhvfaq-gawk-5.3.2-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/sxpvs7nxblvg5fis84w67rz80ygvrcgw-gawk-5.3.2-info" + } + ], + "store_path": "/nix/store/p1ff2bvyyb0vzskfkls91nvpf8g7zwcc-gawk-5.3.2" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/mknqzwppq332dqs43fgcgmgar24dgayq-gawk-5.3.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/45llzyqcsqrx45rjz1dghs891s3xbny6-gawk-5.3.2-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/nhjsr3i830m044qglqalkbkqh9g7bwaq-gawk-5.3.2-info" + } + ], + "store_path": "/nix/store/mknqzwppq332dqs43fgcgmgar24dgayq-gawk-5.3.2" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2", + "default": true + }, + { + "name": "man", + "path": "/nix/store/44gbnv9kk7cy5grvpwnjjapq3fxgsh4y-gawk-5.3.2-man", + "default": true + }, + { + "name": "info", + "path": "/nix/store/miv2z2631wsjpp2vhism5bc4ipch490r-gawk-5.3.2-info" + } + ], + "store_path": "/nix/store/2xq9rayckw8zq26k274xxlikn77jn60j-gawk-5.3.2" + } + } + }, + "git@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#git", + "source": "devbox-search", + "version": "2.52.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/vnhprisb777byfjpp5mdd0mxwkpvhbc0-git-2.52.0", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/p0dx3053175fpr3kjf0fqgs9x6gm3dri-git-2.52.0-doc" + } + ], + "store_path": "/nix/store/vnhprisb777byfjpp5mdd0mxwkpvhbc0-git-2.52.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/sd4bjblxfljbm13mpl50x8g336gw2dri-git-2.52.0", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/cx033x4nmr12d9dcn8hxjfrajc3983f0-git-2.52.0-debug" + }, + { + "name": "doc", + "path": "/nix/store/ylsmgdrnp78p8hn7n9lxpada78dka41v-git-2.52.0-doc" + } + ], + "store_path": "/nix/store/sd4bjblxfljbm13mpl50x8g336gw2dri-git-2.52.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/sr42bfqa0pc2ysba678mrm49g78jdynp-git-2.52.0", + "default": true + }, + { + "name": "doc", + "path": "/nix/store/fky0ci2bhwgyh9klg5682pmqswqg7wk4-git-2.52.0-doc" + } + ], + "store_path": "/nix/store/sr42bfqa0pc2ysba678mrm49g78jdynp-git-2.52.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ipwndaag56mm8g8gn8j98z0jvn8x4mk1-git-2.52.0", + "default": true + }, + { + "name": "debug", + "path": "/nix/store/zd8di23fmzjwrhb5ij1bjnlfqkx9j7d6-git-2.52.0-debug" + }, + { + "name": "doc", + "path": "/nix/store/d8kc4kqzcrbcj92msxrpdsdjglh2q5gp-git-2.52.0-doc" + } + ], + "store_path": "/nix/store/ipwndaag56mm8g8gn8j98z0jvn8x4mk1-git-2.52.0" + } + } + }, "github:NixOS/nixpkgs/nixpkgs-unstable": { "last_modified": "2026-01-27T15:18:14Z", "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" }, + "gnugrep@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#gnugrep", + "source": "devbox-search", + "version": "3.12", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/vh7z511kn1g6c4j4rrj2fgxnjsbny5mw-gnugrep-3.12", + "default": true + }, + { + "name": "info", + "path": "/nix/store/i484zygrqw554k0ddswv6k7lkn7i3za1-gnugrep-3.12-info" + } + ], + "store_path": "/nix/store/vh7z511kn1g6c4j4rrj2fgxnjsbny5mw-gnugrep-3.12" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/r21ffchrdgccar73w3skkah0aj15mj2b-gnugrep-3.12", + "default": true + }, + { + "name": "info", + "path": "/nix/store/2lj0xvg84lzn5bvap89grjzvrgx43kz9-gnugrep-3.12-info" + } + ], + "store_path": "/nix/store/r21ffchrdgccar73w3skkah0aj15mj2b-gnugrep-3.12" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/jblpqghdm8kbsk6lm2szsfz6qqy3ldfd-gnugrep-3.12", + "default": true + }, + { + "name": "info", + "path": "/nix/store/zvgc176fjzpnyhlp6y0f7pd1jl6zvv91-gnugrep-3.12-info" + } + ], + "store_path": "/nix/store/jblpqghdm8kbsk6lm2szsfz6qqy3ldfd-gnugrep-3.12" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12", + "default": true + }, + { + "name": "info", + "path": "/nix/store/cgk1j37lw5vw7lxdlzhdhji3fii5b5id-gnugrep-3.12-info" + } + ], + "store_path": "/nix/store/02vv0r262agf9j5n2y1gmbjvdf12zkl0-gnugrep-3.12" + } + } + }, + "gnused@latest": { + "last_modified": "2026-01-23T17:20:52Z", + "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#gnused", + "source": "devbox-search", + "version": "4.9", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/bdhywjmavg1hw3515cxsh8vxx8p42ixw-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/2q7ry9sap952dh21xda36g2gx44m9jvl-gnused-4.9-info" + } + ], + "store_path": "/nix/store/bdhywjmavg1hw3515cxsh8vxx8p42ixw-gnused-4.9" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/wl7cvwbv3p0ag201jry906ydpij3a9ij-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/srvxijm4zzcqp6krhxk8qhfcr52mh39a-gnused-4.9-info" + } + ], + "store_path": "/nix/store/wl7cvwbv3p0ag201jry906ydpij3a9ij-gnused-4.9" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/b882ldrvxjjkc130pqy53948y09hci8m-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/12wwcnqr14xnbjs9mf6l5igpqc167y61-gnused-4.9-info" + } + ], + "store_path": "/nix/store/b882ldrvxjjkc130pqy53948y09hci8m-gnused-4.9" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9", + "default": true + }, + { + "name": "info", + "path": "/nix/store/rr44gnjkn0j0h67blxaf7c69w6y5xv03-gnused-4.9-info" + } + ], + "store_path": "/nix/store/ryz8kcrm2bxpccllfqlb7qldsfnqp5c2-gnused-4.9" + } + } + }, "gradle@8.0.1": { "last_modified": "2023-07-24T21:56:31Z", "plugin_version": "0.0.1", @@ -442,6 +922,87 @@ } } }, + "nodejs@latest": { + "last_modified": "2026-01-26T13:12:53Z", + "plugin_version": "0.0.2", + "resolved": "github:NixOS/nixpkgs/13b0f9e6ac78abbbb736c635d87845c4f4bee51b#nodejs_25", + "source": "devbox-search", + "version": "25.4.0", + "systems": { + "aarch64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/m5qq262d56ar77iggvla6d5swn8yw9y6-nodejs-25.4.0", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/3pkkak278knyi93bpv7f67r8ymaa75kl-nodejs-25.4.0-libv8" + }, + { + "name": "dev", + "path": "/nix/store/v63af7yli7i3caybdgv16fxgl2y5iz3k-nodejs-25.4.0-dev" + } + ], + "store_path": "/nix/store/m5qq262d56ar77iggvla6d5swn8yw9y6-nodejs-25.4.0" + }, + "aarch64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/16jjxswcd6kr8391f7pa2vg0vhvwd74g-nodejs-25.4.0", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/nqxds9wybn5npisxpbhsyhbxmbhpayws-nodejs-25.4.0-dev" + }, + { + "name": "libv8", + "path": "/nix/store/rbdpra61acpg4aqs28wl1i4pvxybifsk-nodejs-25.4.0-libv8" + } + ], + "store_path": "/nix/store/16jjxswcd6kr8391f7pa2vg0vhvwd74g-nodejs-25.4.0" + }, + "x86_64-darwin": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/pig8ld1dg0pk15w38h1dy60j0fd909qm-nodejs-25.4.0", + "default": true + }, + { + "name": "dev", + "path": "/nix/store/hqc95i644v03m54kra36jk1i962n1cyv-nodejs-25.4.0-dev" + }, + { + "name": "libv8", + "path": "/nix/store/qi6pchsq09am76hy7wb0sb15575gzmra-nodejs-25.4.0-libv8" + } + ], + "store_path": "/nix/store/pig8ld1dg0pk15w38h1dy60j0fd909qm-nodejs-25.4.0" + }, + "x86_64-linux": { + "outputs": [ + { + "name": "out", + "path": "/nix/store/pgcjcir9hkx39zfiya8hmrm7wxzb3sn5-nodejs-25.4.0", + "default": true + }, + { + "name": "libv8", + "path": "/nix/store/xc40d8b44b12ibi7ihczllczdymdvi7w-nodejs-25.4.0-libv8" + }, + { + "name": "dev", + "path": "/nix/store/s431j6qb3xhh1ws5hrc2c0lzjq0lh1k5-nodejs-25.4.0-dev" + } + ], + "store_path": "/nix/store/pgcjcir9hkx39zfiya8hmrm7wxzb3sn5-nodejs-25.4.0" + } + } + }, "shfmt@latest": { "last_modified": "2026-01-23T17:20:52Z", "resolved": "github:NixOS/nixpkgs/a1bab9e494f5f4939442a57a58d0449a109593fe#shfmt", diff --git a/nix/applesimutils.nix b/nix/applesimutils.nix new file mode 100644 index 000000000..4af2945be --- /dev/null +++ b/nix/applesimutils.nix @@ -0,0 +1,34 @@ +{ lib +, stdenv +, fetchurl +}: + +stdenv.mkDerivation rec { + pname = "applesimutils"; + version = "0.9.12"; + + src = fetchurl { + url = + if stdenv.hostPlatform.system == "aarch64-darwin" then + "https://github.com/wix/AppleSimulatorUtils/releases/download/${version}/applesimutils-${version}.arm64_big_sur.bottle.tar.gz" + else + "https://github.com/wix/AppleSimulatorUtils/releases/download/${version}/applesimutils-${version}.big_sur.bottle.tar.gz"; + sha256 = "0cy1w8zcifdns0r95jf74qqkzmmmn079c8habf37f7h5lrgdhwrk"; + }; + + dontBuild = true; + + installPhase = '' + runHook preInstall + mkdir -p $out/bin + cp -v "0.9.12/bin/applesimutils" $out/bin/ + runHook postInstall + ''; + + meta = with lib; { + description = "Apple Simulator Utils (applesimutils) command line tool"; + homepage = "https://github.com/wix/AppleSimulatorUtils"; + license = licenses.mit; + platforms = platforms.darwin; + }; +} diff --git a/nix/flake.nix b/nix/flake.nix index 33ef1d7e1..95a02a329 100644 --- a/nix/flake.nix +++ b/nix/flake.nix @@ -70,6 +70,8 @@ }; }; + applesimutils = pkgs.callPackage ./applesimutils.nix { }; + abiVersions = if builtins.match "aarch64-.*" system != null then [ "arm64-v8a" ] else [ "x86_64" ]; androidPkgs = @@ -87,6 +89,7 @@ }; in { + applesimutils = applesimutils; android-sdk = (androidPkgs androidSdkConfig).androidsdk; android-sdk-min = (androidPkgs androidSdkConfigMin).androidsdk; android-sdk-max = (androidPkgs androidSdkConfigMax).androidsdk; diff --git a/scripts/bootstrap/env.sh b/scripts/bootstrap/env.sh index 14a087e04..ef5295e01 100644 --- a/scripts/bootstrap/env.sh +++ b/scripts/bootstrap/env.sh @@ -13,7 +13,11 @@ ENV_SH_LOADED_PID="$$" script_dir="$(cd "$(dirname "$0")" && pwd)" repo_root="" -if command -v git >/dev/null 2>&1; then +if [ -n "${DEVBOX_PROJECT_ROOT:-}" ] && [ -d "$DEVBOX_PROJECT_ROOT" ]; then + repo_root="$DEVBOX_PROJECT_ROOT" +elif [ -n "${DEVBOX_PROJECT_DIR:-}" ] && [ -d "$DEVBOX_PROJECT_DIR" ]; then + repo_root="$DEVBOX_PROJECT_DIR" +elif command -v git >/dev/null 2>&1; then repo_root="$(git -C "$script_dir" rev-parse --show-toplevel 2>/dev/null || git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)" fi if [ -z "$repo_root" ]; then diff --git a/scripts/bootstrap/init.sh b/scripts/bootstrap/init.sh index c2d14aaec..b8911cd92 100644 --- a/scripts/bootstrap/init.sh +++ b/scripts/bootstrap/init.sh @@ -8,6 +8,11 @@ fi load_env() { script_dir="$1" init_path="$script_dir/bootstrap/env.sh" + if [ -n "${DEVBOX_PROJECT_ROOT:-}" ] && [ -f "${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" + elif [ -n "${DEVBOX_PROJECT_DIR:-}" ] && [ -f "${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" + fi if [ ! -f "$init_path" ]; then repo_root="" if command -v git >/dev/null 2>&1; then diff --git a/scripts/platforms/android/env.sh b/scripts/platforms/android/env.sh index e2dd6f586..2ac1aeaeb 100755 --- a/scripts/platforms/android/env.sh +++ b/scripts/platforms/android/env.sh @@ -132,6 +132,22 @@ fi export ANDROID_SDK_ROOT ANDROID_HOME export ANDROID_BUILD_TOOLS_VERSION + +if [ -n "${HOME:-}" ]; then + if [ -z "${ANDROID_SDK_HOME:-}" ]; then + ANDROID_SDK_HOME="$HOME/.android" + export ANDROID_SDK_HOME + fi + if [ -z "${ANDROID_USER_HOME:-}" ]; then + ANDROID_USER_HOME="$ANDROID_SDK_HOME" + export ANDROID_USER_HOME + fi + if [ -z "${ANDROID_AVD_HOME:-}" ]; then + ANDROID_AVD_HOME="$ANDROID_SDK_HOME/avd" + export ANDROID_AVD_HOME + fi + mkdir -p "$ANDROID_SDK_HOME" "$ANDROID_AVD_HOME" 2>/dev/null || true +fi ANDROID_ENV_LOADED=1 ANDROID_ENV_LOADED_PID="$$" diff --git a/scripts/platforms/ios/actions.sh b/scripts/platforms/ios/actions.sh index 0dfe91ade..05efe2167 100644 --- a/scripts/platforms/ios/actions.sh +++ b/scripts/platforms/ios/actions.sh @@ -61,6 +61,9 @@ ios_run() { DETOX_IOS_DEVICE="${DETOX_IOS_DEVICE:-$device_name}" export IOS_RUNTIME IOS_DEVICE_NAMES DETOX_IOS_DEVICE + ensure_developer_dir + require_tool jq + ensure_simctl if ! resolve_runtime_name_strict "$runtime_version"; then exit 1 fi diff --git a/scripts/platforms/ios/env.sh b/scripts/platforms/ios/env.sh index 0adcd4ae2..dd79cba18 100755 --- a/scripts/platforms/ios/env.sh +++ b/scripts/platforms/ios/env.sh @@ -9,6 +9,11 @@ set -eu script_dir="$(cd "$(dirname "$0")" && pwd)" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then init_path="$script_dir/../../bootstrap/env.sh" + if [ -n "${DEVBOX_PROJECT_ROOT:-}" ] && [ -f "${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" + elif [ -n "${DEVBOX_PROJECT_DIR:-}" ] && [ -f "${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" + fi if [ ! -f "$init_path" ]; then repo_root="" if command -v git >/dev/null 2>&1; then @@ -29,6 +34,7 @@ devbox_omit_nix_env() { fi export DEVBOX_OMIT_NIX_ENV_APPLIED=1 + require_tool devbox "devbox is required to configure the macOS toolchain. Run this script inside a devbox shell." dump_env() { if [ -n "${CI:-}" ] || [ -n "${GITHUB_ACTIONS:-}" ]; then diff --git a/scripts/platforms/ios/simctl.sh b/scripts/platforms/ios/simctl.sh index 6dddcd631..5c524009d 100644 --- a/scripts/platforms/ios/simctl.sh +++ b/scripts/platforms/ios/simctl.sh @@ -9,6 +9,11 @@ fi script_dir="$(cd "$(dirname "$0")" && pwd)" if [ "${SHARED_LOADED:-}" != "1" ] || [ "${SHARED_LOADED_PID:-}" != "$$" ]; then init_path="$script_dir/../../bootstrap/env.sh" + if [ -n "${DEVBOX_PROJECT_ROOT:-}" ] && [ -f "${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_ROOT}/scripts/bootstrap/env.sh" + elif [ -n "${DEVBOX_PROJECT_DIR:-}" ] && [ -f "${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" ]; then + init_path="${DEVBOX_PROJECT_DIR}/scripts/bootstrap/env.sh" + fi if [ ! -f "$init_path" ]; then repo_root="" if command -v git >/dev/null 2>&1; then @@ -195,6 +200,8 @@ ensure_device() { ensure_developer_dir() { desired="${IOS_DEVELOPER_DIR:-}" + PATH="/usr/bin:/bin:/usr/sbin:/sbin:${PATH}" + export PATH if [ -z "$desired" ]; then if xcode-select -p >/dev/null 2>&1; then desired="$(xcode-select -p)" diff --git a/shells/android-max/devbox.json b/shells/android-max/devbox.json index 44db84ca6..ceeae43e6 100644 --- a/shells/android-max/devbox.json +++ b/shells/android-max/devbox.json @@ -2,6 +2,13 @@ "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json", "packages": { "yarn-berry": "latest", + "git": "latest", + "bash": "latest", + "nodejs": "latest", + "coreutils": "latest", + "gnused": "latest", + "gnugrep": "latest", + "gawk": "latest", "jdk17": "latest", "gradle": "8.0.1", "jq": "latest", diff --git a/shells/android-min/devbox.json b/shells/android-min/devbox.json index 1c40ecbdf..7ef9735c2 100644 --- a/shells/android-min/devbox.json +++ b/shells/android-min/devbox.json @@ -2,6 +2,13 @@ "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json", "packages": { "yarn-berry": "latest", + "git": "latest", + "bash": "latest", + "nodejs": "latest", + "coreutils": "latest", + "gnused": "latest", + "gnugrep": "latest", + "gawk": "latest", "jdk17": "latest", "gradle": "8.0.1", "jq": "latest", diff --git a/shells/ios/devbox.json b/shells/ios/devbox.json index 19d2984ff..681ca8886 100644 --- a/shells/ios/devbox.json +++ b/shells/ios/devbox.json @@ -6,10 +6,22 @@ "platforms": ["x86_64-darwin", "aarch64-darwin"] }, "yarn-berry": "latest", + "git": "latest", + "bash": "latest", + "nodejs": "latest", + "path:../../nix#applesimutils": { + "version": "", + "platforms": ["aarch64-darwin", "x86_64-darwin"] + }, + "coreutils": "latest", + "gnused": "latest", + "gnugrep": "latest", + "gawk": "latest", "jq": "latest" }, "shell": { "init_hook": [ + "export LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8", "INIT_IOS=1 . $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh" ], "scripts": { diff --git a/shells/minimal/devbox.json b/shells/minimal/devbox.json index afcd90fff..c072ef165 100644 --- a/shells/minimal/devbox.json +++ b/shells/minimal/devbox.json @@ -2,13 +2,22 @@ "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.14.2/.schema/devbox.schema.json", "packages": { "yarn-berry": "latest", + "git": "latest", + "bash": "latest", + "nodejs": "latest", + "coreutils": "latest", + "gnused": "latest", + "gnugrep": "latest", + "gawk": "latest", "jq": "latest", "treefmt": "latest", "nixfmt": "latest", "shfmt": "latest" }, "shell": { - "init_hook": [". $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh"], + "init_hook": [ + ". $DEVBOX_PROJECT_ROOT/../../scripts/bootstrap/env.sh" + ], "scripts": { "build": ["sh $DEVBOX_PROJECT_ROOT/../../scripts/run.sh build"], "release": [ diff --git a/wiki/devbox.md b/wiki/devbox.md index 2801a8bda..e70120610 100644 --- a/wiki/devbox.md +++ b/wiki/devbox.md @@ -2,31 +2,31 @@ This repo ships a Devbox environment that preinstalls the Android SDK and common build tools like Gradle and Yarn. Devbox uses Nix under the hood to pin versions so everyone has the same setup. You don’t need to know Nix to use it. -Enter the environment with `devbox shell`. The init hook wires `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH. Common scripts run via `devbox run`, for example `devbox run build`. For Devbox basics, see the official docs: https://www.jetify.com/devbox/docs/. For script layout, see `wiki/scripts.md`; for Nix/SDK versions, see `wiki/nix.md`. +Enter the environment with `devbox shell --pure`. The init hook wires `ANDROID_SDK_ROOT`/`ANDROID_HOME` and PATH. Common scripts run via `devbox run --pure`, for example `devbox run --pure build`. For Devbox basics, see the official docs: https://www.jetify.com/devbox/docs/. For script layout, see `wiki/scripts.md`; for Nix/SDK versions, see `wiki/nix.md`. ## Getting started - Install Devbox (https://www.jetify.com/devbox/docs/install/). - From the repo root: `devbox install`. -- Enter the shell: `devbox shell`. -- Build/test: `devbox run build`, `devbox run test-android`, `devbox run test-ios`. +- Enter the shell: `devbox shell --pure`. +- Build/test: `devbox run --pure build`, `devbox run --pure test-android`, `devbox run --pure test-ios`. ## Android -By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/platforms/android/env.sh`. To use a local SDK instead, launch with `ANDROID_LOCAL_SDK=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_LOCAL_SDK` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run start-android*` (uses `scripts/platforms/android/avd.sh`). Version sources are documented in `wiki/nix.md`. +By default, Devbox uses the flake-pinned SDKs and prefers the latest (`android-sdk-max`) when available. It sets `ANDROID_SDK_ROOT`/`ANDROID_HOME` and adds emulator/platform-tools/cmdline-tools to `PATH` via `scripts/platforms/android/env.sh`. To use a local SDK instead, launch with `ANDROID_LOCAL_SDK=1 ANDROID_HOME="$HOME/Library/Android/sdk" devbox shell --pure` (or set `ANDROID_SDK_ROOT`). Unset `ANDROID_LOCAL_SDK` (and `ANDROID_HOME`/`ANDROID_SDK_ROOT` if you set them) to return to the Nix SDK. Inspect the active SDK with `echo "$ANDROID_SDK_ROOT"` and `which sdkmanager` inside the shell. Create/boot AVDs via `devbox run --pure start-android*` (uses `scripts/platforms/android/avd.sh`). Version sources are documented in `wiki/nix.md`. Example custom targets (root `devbox.json` sets these via `shell.env` for testing): `ANDROID_CUSTOM_API=29` `ANDROID_CUSTOM_DEVICE=pixel_6` `IOS_CUSTOM_DEVICE="iPhone 15"` ### Emulator/AVD scripts -- `devbox run start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/platforms/android/avd.sh`. -- `devbox run start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/platforms/android/avd.sh` if it does not exist. +- `devbox run --pure start-android` launches the default “max” AVD (from `nix/defaults.json`). Override with `TARGET_SDK=min` to launch the min AVD instead. You can also set `DETOX_AVD` or `AVD_NAME` to pick an exact AVD name. Internally uses `scripts/platforms/android/avd.sh`. +- `devbox run --pure start-android-max` / `start-android-min` explicitly launch the max (API 33) or min (API 21) AVDs. Both will create the AVD first via `scripts/platforms/android/avd.sh` if it does not exist. - `scripts/platforms/android/avd.sh` accepts env overrides: `AVD_API`, `AVD_DEVICE`, `AVD_TAG`, `AVD_ABI`, `AVD_NAME`, `ANDROID_TARGET_API`. Defaults target the latest API (`ANDROID_MAX_API`) when available. The script auto-selects the best ABI for the host (arm64-v8a on arm, x86_64 on Intel) if `AVD_ABI` is unset. -- `devbox run reset-android` removes local AVDs/adb keys if you need a clean slate. -- `EMU_HEADLESS=1 devbox run start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. -- `EMU_PORT=5554 devbox run start-android*` to set the emulator port/serial (defaults to 5554) and avoid adb conflicts. -- `devbox run test-android` runs `setup-android` first to ensure AVDs exist, then delegates startup to Detox. It will not boot an emulator itself; use `start-android*` if you want it running beforehand. +- `devbox run --pure reset-android` removes local AVDs/adb keys if you need a clean slate. +- `EMU_HEADLESS=1 devbox run --pure start-android*` to run the emulator headless (CI sets this); omit for a visible emulator locally. +- `EMU_PORT=5554 devbox run --pure start-android*` to set the emulator port/serial (defaults to 5554) and avoid adb conflicts. +- `devbox run --pure test-android` runs `setup-android` first to ensure AVDs exist, then delegates startup to Detox. It will not boot an emulator itself; use `start-android*` if you want it running beforehand. ### Detox defaults @@ -35,7 +35,7 @@ Example custom targets (root `devbox.json` sets these via `shell.env` for testin ### Updating Android min/latest versions -- Bump pinned SDK versions in `nix/defaults.json`. Refresh your devshell by running the `refresh` command while inside a devbox shell. +- Bump pinned SDK versions in `nix/defaults.json`. Refresh your devshell by running the `refresh` command while inside a devbox shell (`devbox shell --pure`). - Update AVD defaults/names if you change API levels: - `devbox.json` (`start-android-*` scripts) for default AVD names. - `examples/E2E/.detoxrc.js` for the default `DETOX_AVD`. @@ -44,18 +44,18 @@ Example custom targets (root `devbox.json` sets these via `shell.env` for testin ## iOS -iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `devbox run setup-ios` to provision simulators and validate Xcode tooling. Full Xcode is required for `simctl` (Command Line Tools alone are not enough). Make sure Xcode command line tools are selected (`xcode-select --print-path` or `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`) and that you have agreed to the license if prompted. +iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `devbox run --pure setup-ios` to provision simulators and validate Xcode tooling. Full Xcode is required for `simctl` (Command Line Tools alone are not enough). Make sure Xcode command line tools are selected (`xcode-select --print-path` or `sudo xcode-select -s /Applications/Xcode.app/Contents/Developer`) and that you have agreed to the license if prompted. -> Important: `devbox shell` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/platforms/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/run.sh` re-applies it before running iOS E2E. +> Important: `devbox shell --pure` injects Nix toolchain variables on macOS, which can break Xcode builds. The init hooks source `scripts/platforms/ios/env.sh` to undo that and re-select the system toolchain, and `scripts/run.sh` re-applies it before running iOS E2E. ### Simulators and Detox -- `devbox run setup-ios` provisions simulators. Defaults are driven by `nix/defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/platforms/ios/simctl.sh`. -- `devbox run start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `TARGET_SDK=min` to target the min sim (per `nix/defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. -- `devbox run reset-ios` shuts down/erases and removes all local simulator devices. -- `devbox run stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). +- `devbox run --pure setup-ios` provisions simulators. Defaults are driven by `nix/defaults.json` (min/max device and iOS version). Override via env vars to target a specific device/runtime. Set `IOS_DOWNLOAD_RUNTIME=0` to skip attempting `xcodebuild -downloadPlatform iOS` when the preferred runtime is missing. Set `IOS_DEVELOPER_DIR` (e.g., `/Applications/Xcode.app/Contents/Developer`) to point at a specific Xcode; otherwise it uses `xcode-select -p` or the default Xcode.app if found. Internally uses `scripts/platforms/ios/simctl.sh`. +- `devbox run --pure start-ios` provisions simulators (via `setup-ios`), then boots the chosen device (`DETOX_IOS_DEVICE` or default `iPhone 17`) and opens Simulator. Set `TARGET_SDK=min` to target the min sim (per `nix/defaults.json`) or leave default for latest. Internally uses `scripts/run.sh ios start`. +- `devbox run --pure reset-ios` shuts down/erases and removes all local simulator devices. +- `devbox run --pure stop-android` / `stop-ios` / `stop` to shut down running emulators/simulators (handy for headless runs). - Detox defaults to `iPhone 17` for local runs; override with `DETOX_IOS_DEVICE`. CI runs a matrix: min sim (from `nix/defaults.json`) and latest (iPhone 17). -- `devbox run test-ios` runs `setup-ios` first to ensure simulators exist; Detox handles booting. Use `start-ios` if you want to pre-boot. +- `devbox run --pure test-ios` runs `setup-ios` first to ensure simulators exist; Detox handles booting. Use `start-ios` if you want to pre-boot. ### Common env knobs @@ -64,7 +64,7 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev ### Releases -- `devbox run release` runs npm auth, yarn install/build, and `yarn release`. Requires `NPM_TOKEN` (and `GH_TOKEN`/`YARN_NPM_AUTH_TOKEN` for publishing). Used by the publish workflow. +- `devbox run --pure release` runs npm auth, yarn install/build, and `yarn release`. Requires `NPM_TOKEN` (and `GH_TOKEN`/`YARN_NPM_AUTH_TOKEN` for publishing). Used by the publish workflow. ### Updating iOS min/latest versions @@ -77,17 +77,17 @@ iOS uses the host Xcode toolchain. There is no Nix-provisioned iOS SDK. Run `dev The root `devbox.json` is a full local dev environment. CI uses slim Devbox configs under `shells/` to avoid pulling unnecessary SDKs: - `shells/minimal/devbox.json`: build + lint only. -- `shells/android-min/devbox.json`: Android SDK (min API) + JDK/Gradle for Android E2E. +- `shells/android-min/devbox.json`: Android SDK (min + max platforms) + JDK/Gradle for Android E2E. - `shells/android-max/devbox.json`: Android SDK (max API) + JDK/Gradle for Android E2E. - `shells/ios/devbox.json`: CocoaPods + Yarn for iOS E2E (Xcode still required on macOS). Run them locally with: ```sh -devbox run --config=shells/minimal/devbox.json build -devbox run --config=shells/android-min/devbox.json test-android -devbox run --config=shells/android-max/devbox.json test-android -devbox run --config=shells/ios/devbox.json test-ios +devbox run --pure --config=shells/minimal/devbox.json build +devbox run --pure --config=shells/android-min/devbox.json test-android +devbox run --pure --config=shells/android-max/devbox.json test-android +devbox run --pure --config=shells/ios/devbox.json test-ios ``` -Note: when you use `devbox run --config=shells//devbox.json`, Devbox treats `shells//` as the config root. The init hooks set `SCRIPTS_DIR` to point back at the repo-level `scripts/` folder. +Note: when you use `devbox run --pure --config=shells//devbox.json`, Devbox treats `shells//` as the config root. The init hooks set `SCRIPTS_DIR` to point back at the repo-level `scripts/` folder. diff --git a/wiki/nix.md b/wiki/nix.md index 2b1334598..321a95149 100644 --- a/wiki/nix.md +++ b/wiki/nix.md @@ -28,7 +28,7 @@ This repo uses a Nix flake for the Android SDK, and a JSON file for single-sourc ## Updating versions 1. Edit `nix/defaults.json`. -2. In a devbox shell, run `refresh` to rebuild the SDK. +2. In a devbox shell (`devbox shell --pure`), run `refresh` to rebuild the SDK. 3. If iOS min/max versions change, re-run the iOS E2E workflow to confirm the runtime/device exists on the runner. 4. `nix/defaults.json` exports concrete defaults via the `defaults` section. diff --git a/wiki/release.md b/wiki/release.md index edc5d9f80..62365b5e8 100644 --- a/wiki/release.md +++ b/wiki/release.md @@ -17,13 +17,13 @@ This repo uses semantic-release with multi-semantic-release to version and publi ### CI/CD path (recommended) 1. Ensure `master`/`beta` are green. Merges must use conventional commits. -2. Trigger `Publish` workflow in Actions. Inputs are tokens only; workflow fetches full history, installs Devbox, then runs `devbox run release`. +2. Trigger `Publish` workflow in Actions. Inputs are tokens only; workflow fetches full history, installs Devbox, then runs `devbox run --pure release`. 3. Outputs: package tags (`${name}-vX.Y.Z`), npm publishes, GitHub releases, and updated changelog commits pushed back via the workflow token. ### Local dry run 1. `GH_TOKEN= NPM_TOKEN= YARN_NPM_AUTH_TOKEN=` (GH token needs `contents` write; npm token can be automation/classic publish). -2. `devbox run release -- --dry-run` to see what would publish. Omit `--dry-run` to actually publish (only do this if you intend to release from your machine). +2. `devbox run --pure release -- --dry-run` to see what would publish. Omit `--dry-run` to actually publish (only do this if you intend to release from your machine). ### Tips and gotchas diff --git a/wiki/scripts.md b/wiki/scripts.md index 66d2e2c9a..1c831dbd7 100644 --- a/wiki/scripts.md +++ b/wiki/scripts.md @@ -1,6 +1,6 @@ # Scripts Overview -This repo uses `scripts/` as the entry point for devbox commands and tasks. Scripts are organized by platform with a small shared helper layer. +This repo uses `scripts/` as the entry point for devbox commands and tasks. Scripts are organized by platform with a small shared helper layer. Devbox runs are expected to use `--pure` for reproducible environments. ## Layout