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 c5ee0993..54a48650 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 6dd28931..abfaf8fb 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 0ffe2437..b4f3f569 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 54a48650..014eefe4 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 7bf5a418..179de1c1 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 00000000..8b4c4a56 --- /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 a1be49c5..6afb07ff 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 ba43b7d3..9acfffe0 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 31d37f8b..c99d41ed 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 98fd45c6..65a68b30 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 6d110a05..5534f400 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 18f54d08..d2767fdd 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 abfaf8fb..bddaa055 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 06ff8738..7a515a45 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 6afb07ff..fd35c3f7 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 00000000..92847cff --- /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 00000000..3bdc87f1 --- /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 00000000..92847cff --- /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 9acfffe0..f92bea93 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 2413eb4e..3fa4f62f 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 00000000..9a97af8e --- /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 76e710ed..f6645e73 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 483d447c..65ed3959 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 65a68b30..98c8f8d1 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 00000000..b6fdff49 --- /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 bddaa055..fd626cac 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 b4f3f569..22072b49 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 014eefe4..60f60d16 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 179de1c1..835a5957 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 8b4c4a56..00000000 --- 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 fd35c3f7..e97dd935 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 3bdc87f1..ecb94fdb 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 f92bea93..5862daa3 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 3fa4f62f..606e39df 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 22072b49..5d062172 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 ffc0b7ce..a5f85ede 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 0713ce9c..024dba43 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 e97dd935..b0057ba4 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 00000000..a468eda9 --- /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 ecb94fdb..27115996 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 00000000..a468eda9 --- /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 c99d41ed..6ab7177e 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 98c8f8d1..ef7dcb7c 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 d2767fdd..3c1b30f9 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 e8c21a1c..f1cee274 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 5d062172..59ba2fd8 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 fd626cac..2ccaf0fa 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 60c7f85a..58a996cf 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 59ba2fd8..3fab642a 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 a1275adb..b1a05cb5 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 a5f85ede..7857b9c9 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 342a187a..a27edf02 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 d22efb73..9c4e841f 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 60f60d16..9812906a 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 52359735..d804339f 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 de7827ca..3a17b941 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 ddfe7bf2..5c5b50b1 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 835a5957..aa88b44c 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 2ccaf0fa..906f6122 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 3fab642a..7ddf623d 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 b1a05cb5..b06e25c9 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 7857b9c9..377f54a1 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 9812906a..4c120de8 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 d804339f..f0ca5ba4 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 b0057ba4..c87b0ec1 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 27115996..e7125620 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 5862daa3..f15d16f1 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 606e39df..57e2b910 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 6ab7177e..9443a186 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 ef7dcb7c..424133e6 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 3c1b30f9..2f165e25 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 974b8d04..ccf2855b 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 9c478de2..073a7fdb 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 0039daf4..a81ffcdf 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 7ddf623d..14b8b2fc 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 a27edf02..e889da2c 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 aa88b44c..89f4810c 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 f6645e73..19581953 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 65ed3959..5c9faaa5 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 9443a186..18419baf 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 424133e6..84f03849 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 2f165e25..235fe0f7 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 906f6122..16b3b4da 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 50666990..87c7ac9b 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 58a996cf..55a20d38 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 14b8b2fc..f93fd37c 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 b06e25c9..f9d537d7 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 377f54a1..cdbad4f0 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 e889da2c..18098ac2 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 9c4e841f..42aa2183 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 00000000..4fd673ea --- /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 4c120de8..5dc2bb9e 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 f0ca5ba4..b23c590d 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 3a17b941..4038398a 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 5c5b50b1..88121ac7 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 89f4810c..dceb7252 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 024dba43..12b44560 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 a62edbf0..98cb52bf 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 00000000..51824b9a --- /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 c87b0ec1..3f653e86 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 e7125620..c5fd85e7 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 f15d16f1..f30a96e9 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 57e2b910..ac5fad0c 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 19581953..48422e3c 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 986eff98..c0434320 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 16b3b4da..86d58545 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 87c7ac9b..149c88e7 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 cdbad4f0..3ecc1440 --- 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 f93fd37c..fe93a3ee 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 f9d537d7..00000000 --- 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 18098ac2..00000000 --- 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 42aa2183..4ddd95ac 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 00000000..5a9f92e0 --- /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 5dc2bb9e..2c31d5ca 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 b23c590d..00000000 --- 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 4038398a..00000000 --- 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 88121ac7..e9982e8b 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 dceb7252..00000000 --- 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 12b44560..b2a51cca 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 98cb52bf..2a2c188a 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 3f653e86..edc75ce8 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 c5fd85e7..e7603ac2 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 f30a96e9..af78dbea 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 ac5fad0c..b26377ab 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 48422e3c..aaa7b041 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 c0434320..a589a575 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 5c9faaa5..268e7ba9 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 86d58545..0e0731ef 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 7a515a45..0b955cf1 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 55a20d38..00000000 --- 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 3ecc1440..23c4f127 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 fe93a3ee..366cd9ac 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 00000000..cec00532 --- /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 4ddd95ac..00000000 --- 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 4fd673ea..00000000 --- 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 149c88e7..ed6738c7 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 00000000..a8ffdf36 --- /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 5a9f92e0..3ea6ede9 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 e9982e8b..b650db36 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 b2a51cca..00000000 --- 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 00000000..7e09e97d --- /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 2a2c188a..7b9c0806 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 edc75ce8..fcdb3658 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 e7603ac2..23e7c015 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 af78dbea..d0715ab8 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 b26377ab..c836ecc4 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 aaa7b041..a2ceef79 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 a589a575..2a6d0db4 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 268e7ba9..05845822 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 18419baf..ada62ca0 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 84f03849..9466d7a2 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 235fe0f7..2976b06a 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 d6232414..34981f99 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 23c4f127..0a0e641f 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 366cd9ac..cc85087e 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 cec00532..6fe526d1 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 ed6738c7..2c64b14b 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 a8ffdf36..6e482759 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 ebd3b7cf..ace8f2c3 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 3ea6ede9..7647ab1a 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 b650db36..c7975292 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 a2ceef79..0118028f 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 2a6d0db4..9fd27e71 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 05845822..221fadb4 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 221fadb4..c1f2838a 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 0e0731ef..6093f8a1 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 6fe526d1..e85a011e 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 0a0e641f..216b5576 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 cc85087e..959d108c 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 6e482759..00000000 --- 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 7647ab1a..817d3d53 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 ace8f2c3..95c14384 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 c7975292..e2eac700 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 7e09e97d..3697201c 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 7b9c0806..00000000 --- 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 51824b9a..ddd568b3 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 00000000..cfcfcff9 --- /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 00000000..64b50323 --- /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 fcdb3658..f07f05af 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 23e7c015..838b69c7 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 d0715ab8..eea48488 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 c836ecc4..e59e71d5 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 9fd27e71..a169b428 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 c1f2838a..90bdea08 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 ada62ca0..48c916e3 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 9466d7a2..1248267d 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 2976b06a..8c5d19c9 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 0b955cf1..a4ed0cad 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 817d3d53..726af90d 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 cfcfcff9..a1dae45d 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 0118028f..b181ab26 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 a169b428..9984992f 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 90bdea08..65044a43 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 00000000..4aede427 --- /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 48c916e3..06994ae0 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 1248267d..4a53194c 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 00000000..16ee3b64 --- /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 8c5d19c9..3088a606 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 6093f8a1..938f5163 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 81129d34..e1591780 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 2c64b14b..69597468 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 a4ed0cad..0802c882 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 216b5576..e43d3b80 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 959d108c..dd512a9e 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 56269050..e14dde3b 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 726af90d..42be577e 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 95c14384..d7febe02 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 e2eac700..5fc648b6 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 3697201c..7c5f6e77 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 ddd568b3..9d8bed8e 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 a1dae45d..e737fd07 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 0e0260fb..546641ad 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 64b50323..e79308d6 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 b181ab26..92849433 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 65044a43..e0b8c9bc 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 69597468..dee7ead7 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 dd512a9e..a0a91d8d 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 42be577e..9b5f73a5 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 d7febe02..5e26c2e6 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 9d8bed8e..253ed5db 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 92849433..4901fa92 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 e0b8c9bc..24284d40 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 b6fdff49..b6a91833 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 e59e71d5..c4b97508 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 16ee3b64..24b3e40f 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 e43d3b80..18c1645b 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 24b3e40f..c96b77cc 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 1a19352a..5536ce20 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 f944e52b..7544da84 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 18c1645b..299c3338 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 938f5163..cc0d3172 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 e1591780..07fb8283 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 073a7fdb..7fe7b261 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 299c3338..788eb5dd 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 00000000..cf86fcc5 --- /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 7c5f6e77..96afbefc 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 f07f05af..a9bc4bea 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 92847cff..f1529257 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 838b69c7..68b3f2c6 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 92847cff..f1529257 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 ae82190b..62575edd 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 9a97af8e..9e633587 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 4aede427..2373a2f1 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 06994ae0..32cb8aa9 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 4a53194c..3fa66bf6 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 c96b77cc..bf8317b2 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 9b5f73a5..46394c79 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 5fc648b6..dde0f790 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 a9bc4bea..33ee2a44 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 68b3f2c6..bdff41f9 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 0cab2ac6..f6ca9014 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 0cab2ac6..f6ca9014 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 0cab2ac6..f6ca9014 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 3d5782c7..00000000 --- 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 e14dde3b..ce5388a8 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 dde0f790..ecb444d4 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 bf8317b2..9af19a33 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 cc0d3172..d4071583 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 ce5388a8..14a087e0 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 00000000..c2d14aae --- /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 e85a011e..d6d6a551 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 788eb5dd..2468f2fb 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 a0a91d8d..e2dd6f58 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 cf86fcc5..f19f3229 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 46394c79..0dfe91ad 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 5e26c2e6..0adcd4ae 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 ecb444d4..6dddcd63 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 96afbefc..77f8665c 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 e79308d6..56c0eae7 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 33ee2a44..44db84ca 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 bdff41f9..1c40ecbd 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 eea48488..19d2984f 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 c4b97508..afcd90ff 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 4901fa92..2801a8bd 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 9984992f..2b133459 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 24284d40..66d2e2c9 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 32cb8aa9..17cef47e 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 3088a606..74787f41 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 0802c882..33ef1d7e 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 dee7ead7..b67112e1 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 9af19a33..9d2567d7 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 2373a2f1..deca04cc 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 5534f400..a84dea6c 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 9d2567d7..92c69b32 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 74787f41..3255079b 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 b6a91833..0cc1aa6a 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 d4071583..6f4d4151 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 07fb8283..aa64719a 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 00000000..4af2945b --- /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 33ef1d7e..95a02a32 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 14a087e0..ef5295e0 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 c2d14aae..b8911cd9 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 e2dd6f58..2ac1aeae 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 0dfe91ad..05efe216 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 0adcd4ae..dd79cba1 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 6dddcd63..5c524009 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 44db84ca..ceeae43e 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 1c40ecbd..7ef9735c 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 19d2984f..681ca888 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 afcd90ff..c072ef16 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 2801a8bd..e7012061 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 2b133459..321a9514 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 edc5d9f8..62365b5e 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 66d2e2c9..1c831dbd 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