diff --git a/.github/workflows/devbox-update.yml b/.github/workflows/devbox-update.yml new file mode 100644 index 000000000..002190e76 --- /dev/null +++ b/.github/workflows/devbox-update.yml @@ -0,0 +1,31 @@ +name: Devbox Update + +on: + # Weekly schedule - Monday 10am UTC + schedule: + - cron: '0 10 * * 1' + + # Manual trigger + workflow_dispatch: + +concurrency: + group: devbox-update-${{ github.ref }} + cancel-in-progress: true + +jobs: + update: + name: Update Devbox Dependencies + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@v4 + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.14.0 + + - name: Update devbox packages + uses: xiaolutech/devbox-update-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/e2e-mobile-tests.yml b/.github/workflows/e2e-mobile-tests.yml new file mode 100644 index 000000000..60f582711 --- /dev/null +++ b/.github/workflows/e2e-mobile-tests.yml @@ -0,0 +1,200 @@ +name: E2E Mobile Tests + +on: + # Weekly schedule - Monday 9am UTC + schedule: + - cron: '0 9 * * 1' + + # TODO: Remove before merging - for testing only + push: + branches: + - feat/mobile-devtools-e2e-integration + + # Manual trigger + workflow_dispatch: + inputs: + test_matrix: + description: 'Test matrix to run' + required: false + type: choice + options: + - all + - android + - ios + - compat + - latest + default: 'all' + + # Callable by other workflows (e.g., release) + workflow_call: + +concurrency: + group: e2e-mobile-${{ github.ref }} + cancel-in-progress: true + +jobs: + e2e-android-compat: + name: E2E Android (RN 0.72) + runs-on: ubuntu-24.04 + timeout-minutes: 30 + if: | + inputs.test_matrix == 'all' || + inputs.test_matrix == 'android' || + inputs.test_matrix == 'compat' || + github.event_name != 'workflow_dispatch' + steps: + - uses: actions/checkout@v6 + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.15.0 + with: + project-path: examples/E2E-compat + + - name: Run Android E2E Tests + working-directory: examples/E2E-compat + run: devbox run --pure test:e2e:android + env: + DETOX_AVD: medium_phone_API33_x86_64 + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: e2e-android-compat-results + path: examples/E2E-compat/reports/ + if-no-files-found: ignore + + e2e-ios-compat: + name: E2E iOS (RN 0.72) + runs-on: macos-14 + timeout-minutes: 30 + if: | + inputs.test_matrix == 'all' || + inputs.test_matrix == 'ios' || + inputs.test_matrix == 'compat' || + github.event_name != 'workflow_dispatch' + steps: + - uses: actions/checkout@v6 + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.15.0 + with: + project-path: examples/E2E-compat + + - name: Run iOS E2E Tests + working-directory: examples/E2E-compat + run: devbox run --pure test:e2e:ios + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: e2e-ios-compat-results + path: examples/E2E-compat/reports/ + if-no-files-found: ignore + + e2e-android-latest: + name: E2E Android (RN 0.84) + runs-on: ubuntu-24.04 + timeout-minutes: 30 + continue-on-error: true # TODO: Remove when RN 0.84 support is complete + if: | + inputs.test_matrix == 'all' || + inputs.test_matrix == 'android' || + inputs.test_matrix == 'latest' || + github.event_name != 'workflow_dispatch' + steps: + - uses: actions/checkout@v6 + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.15.0 + with: + project-path: examples/E2E-latest + + - name: Run Android E2E Tests + working-directory: examples/E2E-latest + run: devbox run --pure test:e2e:android + env: + DETOX_AVD: medium_phone_API35_x86_64 + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: e2e-android-latest-results + path: examples/E2E-latest/reports/ + if-no-files-found: ignore + + e2e-ios-latest: + name: E2E iOS (RN 0.84) + runs-on: macos-14 + timeout-minutes: 30 + continue-on-error: true # TODO: Remove when RN 0.84 support is complete + if: | + inputs.test_matrix == 'all' || + inputs.test_matrix == 'ios' || + inputs.test_matrix == 'latest' || + github.event_name != 'workflow_dispatch' + steps: + - uses: actions/checkout@v6 + + - name: Install devbox + uses: jetify-com/devbox-install-action@v0.15.0 + with: + project-path: examples/E2E-latest + + - name: Run iOS E2E Tests + working-directory: examples/E2E-latest + run: devbox run --pure test:e2e:ios + + - name: Upload test results + if: always() + uses: actions/upload-artifact@v7 + with: + name: e2e-ios-latest-results + path: examples/E2E-latest/reports/ + if-no-files-found: ignore + + e2e-summary: + name: E2E Test Summary + runs-on: ubuntu-latest + needs: + [e2e-android-compat, e2e-ios-compat, e2e-android-latest, e2e-ios-latest] + if: always() + steps: + - name: Check results + run: | + echo "📊 E2E Test Results:" + echo " Android (RN 0.72): ${{ needs.e2e-android-compat.result }}" + echo " iOS (RN 0.72): ${{ needs.e2e-ios-compat.result }}" + echo " Android (RN 0.84): ${{ needs.e2e-android-latest.result }}" + echo " iOS (RN 0.84): ${{ needs.e2e-ios-latest.result }}" + echo "" + + # Check for failures, treating continue-on-error jobs as non-blocking + if [[ "${{ needs.e2e-android-compat.result }}" != "success" && "${{ needs.e2e-android-compat.result }}" != "skipped" ]] || \ + [[ "${{ needs.e2e-ios-compat.result }}" != "success" && "${{ needs.e2e-ios-compat.result }}" != "skipped" ]]; then + echo "::error::One or more E2E test suites failed" + echo "::error::Check the individual job logs for details" + exit 1 + fi + + # Note: android-latest and ios-latest have continue-on-error, so we don't fail on them + if [[ "${{ needs.e2e-android-latest.result }}" == "failure" ]] || \ + [[ "${{ needs.e2e-ios-latest.result }}" == "failure" ]]; then + echo "::warning::RN 0.84 tests failed but are allowed to fail (continue-on-error)" + fi + + echo "::notice::✅ E2E tests passed successfully!" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4dc77483f..d39a94de0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,6 +37,12 @@ jobs: - name: Test run: devbox run test + e2e-tests: + name: E2E Mobile Tests + needs: [ci] + if: inputs.type == 'beta' || inputs.type == 'production' + uses: ./.github/workflows/e2e-mobile-tests.yml + release-dryrun: name: Release (dry-run) if: inputs.type == 'dry-run' @@ -64,7 +70,7 @@ jobs: release-beta: name: Release (beta) if: inputs.type == 'beta' - needs: [ci] + needs: [ci, e2e-tests] runs-on: ubuntu-latest environment: Publish-Beta permissions: @@ -91,7 +97,7 @@ jobs: release-production: name: Release (production) if: inputs.type == 'production' - needs: [ci] + needs: [ci, e2e-tests] runs-on: ubuntu-latest environment: Publish permissions: diff --git a/.gitignore b/.gitignore index 3dad8cc4e..1276fd748 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,7 @@ AGENTS.md # Notes and research (not for commit) notes/ + +# Devbox runtime data +.devbox/ +**/.devbox/ diff --git a/devbox.lock b/devbox.lock index 63e5a592d..9dad91196 100644 --- a/devbox.lock +++ b/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-03-21T07:29:51Z", + "resolved": "github:NixOS/nixpkgs/09061f748ee21f68a089cd5d91ec1859cd93d0be#cocoapods", "source": "devbox-search", "version": "1.16.2", "systems": { @@ -11,31 +11,31 @@ "outputs": [ { "name": "out", - "path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2", + "path": "/nix/store/i35dcb5pq1a03ns5qh2d3jsrmfn610qc-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/av5g6hfp0yiir3iavg72js70ian8hxyf-cocoapods-1.16.2" + "store_path": "/nix/store/i35dcb5pq1a03ns5qh2d3jsrmfn610qc-cocoapods-1.16.2" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2", + "path": "/nix/store/9f32j7nxb1n3hdx3g4jl7ha45krrs55d-cocoapods-1.16.2", "default": true } ], - "store_path": "/nix/store/har71589bwmh6h6skisd20b3c6lrwmz7-cocoapods-1.16.2" + "store_path": "/nix/store/9f32j7nxb1n3hdx3g4jl7ha45krrs55d-cocoapods-1.16.2" } } }, "github:NixOS/nixpkgs/nixpkgs-unstable": { - "last_modified": "2026-01-27T15:18:14Z", - "resolved": "github:NixOS/nixpkgs/afce96367b2e37fc29afb5543573cd49db3357b7?lastModified=1769527094" + "last_modified": "2026-04-16T08:46:55Z", + "resolved": "github:NixOS/nixpkgs/b86751bc4085f48661017fa226dee99fab6c651b?lastModified=1776329215" }, "jq@latest": { - "last_modified": "2026-01-12T00:44:08Z", - "resolved": "github:NixOS/nixpkgs/3fbab70c6e69c87ea2b6e48aa6629da2aa6a23b0#jq", + "last_modified": "2026-04-10T03:55:24Z", + "resolved": "github:NixOS/nixpkgs/9d29d5f667d7467f98efc31881e824fa586c927e#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/bb450vb2gl547zwba8sihcyilsg2rqfa-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/cv999saj62xhq7xv5i7q6944vljykfmw-jq-1.8.1-man", + "path": "/nix/store/vs96fwfhd5gjycxs5yc58wkrizscww92-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/5camppj4hz2mgkdbxs0kr6nvh6qa65wf-jq-1.8.1-dev" + "path": "/nix/store/irxgyhi0rq34f2y721a26ii09nynq2ha-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/lak094rhhxlaj1qycadmxyfphgjadj5r-jq-1.8.1-doc" + "path": "/nix/store/rnkk37licxmcicz44sm368bk2fsrk52j-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/g371yvjasdr552v98p5kav7n35s1dfib-jq-1.8.1" + "path": "/nix/store/y4gq3lbz2nq75cl3v28ixrqrr90pk4lf-jq-1.8.1" } ], - "store_path": "/nix/store/9rm6fm3zq1jq8rgsx528cw8wkmfya2gf-jq-1.8.1-bin" + "store_path": "/nix/store/bb450vb2gl547zwba8sihcyilsg2rqfa-jq-1.8.1-bin" }, "aarch64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin", + "path": "/nix/store/h68aklwk28xbrg7pqaw078w1hvvvf419-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/9x2457g76jikfy7xq4mjqwzl8iz3zvxj-jq-1.8.1-man", + "path": "/nix/store/l4npc0sgk51lz2d6jqnl4r18hmn6qckr-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/5ykn83b3hhvnnq0p5vqgcrzihrl9wpsl-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/5jf55qkwrnd769ri9wxiy7z9kp5zb4ca-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/37ypy1595g6rj3cymh1mpk2b25fx40g7-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/kzsszlf69lndqilpgysw1j9b4hrfwjfx-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/16lg603jzppwjanlakcak1ais69mkd03-jq-1.8.1" + "name": "doc", + "path": "/nix/store/rr0a4brsd47393640zn9zgw844rbkrsl-jq-1.8.1-doc" } ], - "store_path": "/nix/store/m8qv4g54q3jmjb8i33v9lljcwhydx2vd-jq-1.8.1-bin" + "store_path": "/nix/store/h68aklwk28xbrg7pqaw078w1hvvvf419-jq-1.8.1-bin" }, "x86_64-darwin": { "outputs": [ { "name": "bin", - "path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin", + "path": "/nix/store/y699jyfkqhj7lm51zdxm1df28izg6zgj-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/iwr61wi83kflqvz8j5nf7ridaqq6nh2w-jq-1.8.1-man", + "path": "/nix/store/0h261wdn6mlrn564adwhyw52a2dfnbg5-jq-1.8.1-man", "default": true }, { - "name": "dev", - "path": "/nix/store/lypnqs272644l8ff6wfji9rg5jw10v7h-jq-1.8.1-dev" + "name": "out", + "path": "/nix/store/44i56yshwqwgw912idz0m9zx30d1xg8z-jq-1.8.1" }, { - "name": "doc", - "path": "/nix/store/nyw97c4pywfcqqap5hyk9xjghczlbshl-jq-1.8.1-doc" + "name": "dev", + "path": "/nix/store/681w0vijzacwyhcwylkvbppd4kps33fw-jq-1.8.1-dev" }, { - "name": "out", - "path": "/nix/store/ri930a557685c64bdh88a5031i7hx3vy-jq-1.8.1" + "name": "doc", + "path": "/nix/store/2bvvha8apma6crzhsnpjrghnjbjj6hpm-jq-1.8.1-doc" } ], - "store_path": "/nix/store/kkb17whpkdrmn9g3gk7y6l69vipxsw0i-jq-1.8.1-bin" + "store_path": "/nix/store/y699jyfkqhj7lm51zdxm1df28izg6zgj-jq-1.8.1-bin" }, "x86_64-linux": { "outputs": [ { "name": "bin", - "path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin", + "path": "/nix/store/fc13hvlj7541i1xmwdka7f61qicdzr5a-jq-1.8.1-bin", "default": true }, { "name": "man", - "path": "/nix/store/7d4pv1iymyqk2lykwj1ydml3rjhc6gl3-jq-1.8.1-man", + "path": "/nix/store/crwv17pim6csnfr4jmsd7kf60sp3c5dh-jq-1.8.1-man", "default": true }, { "name": "dev", - "path": "/nix/store/rmxxm5jnxq93kvkhbr2b3hzj6v3ldp8z-jq-1.8.1-dev" + "path": "/nix/store/plinh1rzkh83n4gfpkxl748zgaydpxll-jq-1.8.1-dev" }, { "name": "doc", - "path": "/nix/store/mkhfvc69grlky3iblibkw9wcc12jcdqq-jq-1.8.1-doc" + "path": "/nix/store/ihgrvb9w91mwbhxx3fi3gcwwx3qlsdfv-jq-1.8.1-doc" }, { "name": "out", - "path": "/nix/store/807g765zgpmp1c8fm5y40rw2gbr1k6dk-jq-1.8.1" + "path": "/nix/store/s4w1j16dj8wyriv1ljfypr9s1r39yjwp-jq-1.8.1" } ], - "store_path": "/nix/store/zssasryipb2x4gk2ahzacl4mvvcmk48j-jq-1.8.1-bin" + "store_path": "/nix/store/fc13hvlj7541i1xmwdka7f61qicdzr5a-jq-1.8.1-bin" } } }, "nixfmt@latest": { - "last_modified": "2026-01-09T13:41:53Z", - "resolved": "github:NixOS/nixpkgs/5f02c91314c8ba4afe83b256b023756412218535#nixfmt", + "last_modified": "2026-03-21T07:29:51Z", + "resolved": "github:NixOS/nixpkgs/09061f748ee21f68a089cd5d91ec1859cd93d0be#nixfmt", "source": "devbox-search", "version": "1.2.0", "systems": { @@ -159,41 +159,41 @@ "outputs": [ { "name": "out", - "path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0", + "path": "/nix/store/js6wdady9nz3whaf99flkszzdx9642yc-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/4jzq73b6bax62245z5a5ag8xdazfw4fg-nixfmt-1.2.0" + "store_path": "/nix/store/js6wdady9nz3whaf99flkszzdx9642yc-nixfmt-1.2.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0", + "path": "/nix/store/gsd7qz0fn2ll0sgnnrbjq0yc0cgrcnw7-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/as7f2yrlqgv130vdiw2xi7rhlgd1yk8v-nixfmt-1.2.0" + "store_path": "/nix/store/gsd7qz0fn2ll0sgnnrbjq0yc0cgrcnw7-nixfmt-1.2.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0", + "path": "/nix/store/qzg1pr3by70s6x0w2636n7z91y5c3f66-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/qmas80hmzqbm7n5h9is2im9gjzxsl04a-nixfmt-1.2.0" + "store_path": "/nix/store/qzg1pr3by70s6x0w2636n7z91y5c3f66-nixfmt-1.2.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0", + "path": "/nix/store/m8r6kk7rancjxh4p3hrqwdh0g19yk3hl-nixfmt-1.2.0", "default": true } ], - "store_path": "/nix/store/yx338k689yp9hpnl6h5y22f7vbmi5pky-nixfmt-1.2.0" + "store_path": "/nix/store/m8r6kk7rancjxh4p3hrqwdh0g19yk3hl-nixfmt-1.2.0" } } }, @@ -247,146 +247,146 @@ } }, "shfmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#shfmt", + "last_modified": "2026-04-07T08:05:10Z", + "resolved": "github:NixOS/nixpkgs/a3db02183b5da6fbf728203492a5d1b9d109b7f9#shfmt", "source": "devbox-search", - "version": "3.12.0", + "version": "3.13.1", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0", + "path": "/nix/store/mrwyxsjjd4b25g7h3w5sxh1w9slv9qvr-shfmt-3.13.1", "default": true } ], - "store_path": "/nix/store/dwz5z2wp95pkv6gsmz74w01qrihvhl1h-shfmt-3.12.0" + "store_path": "/nix/store/mrwyxsjjd4b25g7h3w5sxh1w9slv9qvr-shfmt-3.13.1" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0", + "path": "/nix/store/5r4388803b93ampjnm5j4c047d7ra3vd-shfmt-3.13.1", "default": true } ], - "store_path": "/nix/store/6gqqharpvjfzm1wzny6a0zgf1v0aj53a-shfmt-3.12.0" + "store_path": "/nix/store/5r4388803b93ampjnm5j4c047d7ra3vd-shfmt-3.13.1" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0", + "path": "/nix/store/rczypri1abwhzys5piy9zqbzhgad7jlq-shfmt-3.13.1", "default": true } ], - "store_path": "/nix/store/98fwma9rxd04pxj9jrsgvf9xs76f9hlf-shfmt-3.12.0" + "store_path": "/nix/store/rczypri1abwhzys5piy9zqbzhgad7jlq-shfmt-3.13.1" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0", + "path": "/nix/store/3fqbb9m25zbkg1cs19bl9w6yi0yjvd7q-shfmt-3.13.1", "default": true } ], - "store_path": "/nix/store/c3bgrcwq2735ybl5zw68n9nqgwaa0yrj-shfmt-3.12.0" + "store_path": "/nix/store/3fqbb9m25zbkg1cs19bl9w6yi0yjvd7q-shfmt-3.13.1" } } }, "treefmt@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#treefmt", + "last_modified": "2026-04-08T00:40:38Z", + "resolved": "github:NixOS/nixpkgs/9a01fad67a57e44e1b3e1d905c6881bcfb209e8a#treefmt", "source": "devbox-search", - "version": "2.4.0", + "version": "2.5.0", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0", + "path": "/nix/store/1z84g4b0y6xbgp2x17bhvcqb1flid4ls-treefmt-2.5.0", "default": true } ], - "store_path": "/nix/store/48r10kj61pjhz8alfscs8vgrdmlfnqx9-treefmt-2.4.0" + "store_path": "/nix/store/1z84g4b0y6xbgp2x17bhvcqb1flid4ls-treefmt-2.5.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0", + "path": "/nix/store/m4h9rk5khvl7mz3hi1dj508xpak4kd27-treefmt-2.5.0", "default": true } ], - "store_path": "/nix/store/d46fscf82k9ay6s8a3qxk3682ycqalds-treefmt-2.4.0" + "store_path": "/nix/store/m4h9rk5khvl7mz3hi1dj508xpak4kd27-treefmt-2.5.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0", + "path": "/nix/store/bmqxxypl5hsg4dak9ckw819lld87imnp-treefmt-2.5.0", "default": true } ], - "store_path": "/nix/store/yllw5b2js10ia8v0z8x3crbakhal0cs7-treefmt-2.4.0" + "store_path": "/nix/store/bmqxxypl5hsg4dak9ckw819lld87imnp-treefmt-2.5.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0", + "path": "/nix/store/z60np9r7vgajzk4jrbccqafk41vgg63h-treefmt-2.5.0", "default": true } ], - "store_path": "/nix/store/1pdwlp9d1rrm3xp4s5rhhk7mkmx9cmv2-treefmt-2.4.0" + "store_path": "/nix/store/z60np9r7vgajzk4jrbccqafk41vgg63h-treefmt-2.5.0" } } }, "yarn-berry@latest": { - "last_modified": "2025-12-31T03:27:36Z", - "resolved": "github:NixOS/nixpkgs/f665af0cdb70ed27e1bd8f9fdfecaf451260fc55#yarn-berry", + "last_modified": "2026-03-21T07:29:51Z", + "resolved": "github:NixOS/nixpkgs/09061f748ee21f68a089cd5d91ec1859cd93d0be#yarn-berry", "source": "devbox-search", - "version": "4.12.0", + "version": "4.13.0", "systems": { "aarch64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0", + "path": "/nix/store/b1md6hp71c5lcgj7nn2iqm69qryry1nn-yarn-berry-4.13.0", "default": true } ], - "store_path": "/nix/store/2l7sbyyqardvrzr35zkrw67gbng5gb8y-yarn-berry-4.12.0" + "store_path": "/nix/store/b1md6hp71c5lcgj7nn2iqm69qryry1nn-yarn-berry-4.13.0" }, "aarch64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0", + "path": "/nix/store/p64sf0mkrr5zp6ikaa5lq05554n4960s-yarn-berry-4.13.0", "default": true } ], - "store_path": "/nix/store/klx9ndw1djgx0zhhyrkcn9an094rmmwv-yarn-berry-4.12.0" + "store_path": "/nix/store/p64sf0mkrr5zp6ikaa5lq05554n4960s-yarn-berry-4.13.0" }, "x86_64-darwin": { "outputs": [ { "name": "out", - "path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0", + "path": "/nix/store/gd4bawwhkrvwxms96vq1z0vpy8j51fra-yarn-berry-4.13.0", "default": true } ], - "store_path": "/nix/store/m6cwiya6hrbwnlprh2cbnmz6c7mkylrf-yarn-berry-4.12.0" + "store_path": "/nix/store/gd4bawwhkrvwxms96vq1z0vpy8j51fra-yarn-berry-4.13.0" }, "x86_64-linux": { "outputs": [ { "name": "out", - "path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0", + "path": "/nix/store/gr19h6hyx64amxbh334csgsqgjhljwyx-yarn-berry-4.13.0", "default": true } ], - "store_path": "/nix/store/q1gys3zgijcciiafbh9nfawkx5wj8179-yarn-berry-4.12.0" + "store_path": "/nix/store/gr19h6hyx64amxbh334csgsqgjhljwyx-yarn-berry-4.13.0" } } } diff --git a/examples/E2E-compat/README.md b/examples/E2E-compat/README.md index 8bd066df0..0bbc4be87 100644 --- a/examples/E2E-compat/README.md +++ b/examples/E2E-compat/README.md @@ -1,8 +1,56 @@ This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). -# Getting Started +# E2E Test App - React Native 0.72 (Compat) -> **Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. +This example app tests SDK compatibility with React Native 0.72.9 + React 18.3.1. + +## Developer Setup (Devbox) + +### Prerequisites + +```bash +# Install devbox +curl -fsSL https://get.jetify.com/devbox | bash +``` + +### Quick Start + +```bash +cd examples/E2E-compat + +# Enter devbox shell (downloads SDKs on first run) +devbox shell + +# Install dependencies +devbox run install + +# Start Android emulator +devbox run start:emu + +# Run E2E tests +devbox run test:e2e:android +``` + +### Available Commands + +- `devbox run install` - Install Node dependencies +- `devbox run install:pods` - Install iOS CocoaPods +- `devbox run build:android` - Build Android app +- `devbox run build:ios` - Build iOS app +- `devbox run test:e2e:android` - Run Android E2E tests +- `devbox run test:e2e:ios` - Run iOS E2E tests +- `devbox run start:emu` - Start Android emulator +- `devbox run start:sim` - Start iOS simulator +- `devbox run stop:emu` - Stop Android emulator +- `devbox run stop:sim` - Stop iOS simulator + +See [mobile-devtools](https://github.com/segment-integrations/mobile-devtools) for more details. + +--- + +# Getting Started (Manual Setup) + +> **Note**: The devbox setup above is recommended. For manual setup, follow the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. ## Step 1: Start the Metro Server diff --git a/examples/E2E-compat/android/build.gradle b/examples/E2E-compat/android/build.gradle index c83bf5b8a..bcdfc2d9f 100644 --- a/examples/E2E-compat/android/build.gradle +++ b/examples/E2E-compat/android/build.gradle @@ -2,16 +2,18 @@ buildscript { ext { - // Default to the build-tools pinned in devbox; allow override via ANDROID_BUILD_TOOLS_VERSION. - // Keep in sync with nix/flake.nix when ANDROID_BUILD_TOOLS_VERSION is unset. - buildToolsVersion = System.getenv("ANDROID_BUILD_TOOLS_VERSION") ?: "30.0.3" + def compileSdkEnv = System.getenv("ANDROID_COMPILE_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "33" + def targetSdkEnv = System.getenv("ANDROID_TARGET_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "33" + buildToolsVersion = System.getenv("ANDROID_BUILD_TOOLS_VERSION") ?: "35.0.0" minSdkVersion = 21 - compileSdkVersion = 33 - targetSdkVersion = 33 + compileSdkVersion = compileSdkEnv.toInteger() + targetSdkVersion = targetSdkEnv.toInteger() kotlinVersion="1.7.20" - // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" + def ndkVersionEnv = System.getenv("ANDROID_NDK_VERSION") + if (ndkVersionEnv) { + ndkVersion = ndkVersionEnv + } } repositories { google() diff --git a/examples/E2E-compat/devbox.d/android/hash-overrides.json b/examples/E2E-compat/devbox.d/android/hash-overrides.json new file mode 100644 index 000000000..2f029a14c --- /dev/null +++ b/examples/E2E-compat/devbox.d/android/hash-overrides.json @@ -0,0 +1,3 @@ +{ + "https://dl.google.com/android/repository/platform-tools_r37.0.0-darwin.zip": "094a1395683c509fd4d48667da0d8b5ef4d42b2abfcd29f2e8149e2f989357c7" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/devices.lock b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/devices.lock new file mode 100644 index 000000000..4386fa6f3 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/devices.lock @@ -0,0 +1,17 @@ +{ + "devices": [ + { + "name": "medium_phone_api36", + "api": 36, + "device": "medium_phone", + "tag": "google_apis" + }, + { + "name": "pixel_api24", + "api": 24, + "device": "pixel", + "tag": "google_apis" + } + ], + "checksum": "9c9adf202cb494e4d6554d790fab9455481658cf70e7d0a0abcdb0ae9824ddc0" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/max.json b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/max.json new file mode 100644 index 000000000..7ed1bd7d2 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/max.json @@ -0,0 +1,6 @@ +{ + "name": "medium_phone_api36", + "api": 36, + "device": "medium_phone", + "tag": "google_apis" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/min.json b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/min.json new file mode 100644 index 000000000..64984b872 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.android/devices/min.json @@ -0,0 +1,6 @@ +{ + "name": "pixel_api24", + "api": 24, + "device": "pixel", + "tag": "google_apis" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/devices.lock b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/devices.lock new file mode 100644 index 000000000..ed4e6c1f2 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/devices.lock @@ -0,0 +1,13 @@ +{ + "devices": [ + { + "name": "iPhone 17", + "runtime": "26.2" + }, + { + "name": "iPhone 13", + "runtime": "15.4" + } + ], + "checksum": "4d5276f203d7ad62860bfc067f76194df53be449d4aa8a3b2d069855ec1f3232" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/max.json b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/max.json new file mode 100644 index 000000000..0e76d6983 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/max.json @@ -0,0 +1,4 @@ +{ + "name": "iPhone 17", + "runtime": "26.2" +} diff --git a/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/min.json b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/min.json new file mode 100644 index 000000000..fba99bb50 --- /dev/null +++ b/examples/E2E-compat/devbox.d/segment-integrations.mobile-devtools.ios/devices/min.json @@ -0,0 +1,4 @@ +{ + "name": "iPhone 13", + "runtime": "15.4" +} diff --git a/examples/E2E-compat/devbox.json b/examples/E2E-compat/devbox.json new file mode 100644 index 000000000..dbb4ea12e --- /dev/null +++ b/examples/E2E-compat/devbox.json @@ -0,0 +1,58 @@ +{ + "include": [ + "github:segment-integrations/mobile-devtools/feat/move-flake-to-devbox-d?dir=plugins/react-native" + ], + "packages": [ + "nodejs@20", + "yarn-berry@latest", + "watchman@latest", + "jdk17@latest", + "gradle@latest" + ], + "env": { + "IOS_APP_SCHEME": "AnalyticsReactNativeE2E", + "IOS_APP_BUNDLE_ID": "com.analyticsreactnativeexample", + "ANDROID_APP_ID": "com.analyticsreactnativeexample", + "ANDROID_APP_APK": "android/app/build/outputs/apk/release/app-release.apk", + "ANDROID_MAX_API": "35", + "ANDROID_SDK_REQUIRED": "0", + "ANDROID_BUILD_TOOLS_VERSION": "30.0.3", + "ANDROID_INCLUDE_NDK": "false", + "ANDROID_INCLUDE_CMAKE": "false", + "GRADLE_OPTS": "-Dorg.gradle.project.android.aapt2FromMavenOverride=$ANDROID_SDK_ROOT/build-tools/30.0.3/aapt2" + }, + "shell": { + "scripts": { + "install": ["yarn install"], + "install:pods": ["(cd ios && pod install)"], + "build:android": [ + "yarn install", + "(cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release)" + ], + "build:ios": [ + "yarn install", + "(cd ios && pod install)", + "ios.sh xcodebuild -workspace ios/AnalyticsReactNativeE2E.xcworkspace -scheme AnalyticsReactNativeE2E -configuration Release -sdk iphonesimulator -derivedDataPath ios/build" + ], + "test:e2e:android": [ + "yarn install", + "(cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release)", + "yarn detox test --configuration android.emu.release" + ], + "test:e2e:ios": [ + "yarn install", + "(cd ios && pod install)", + "ios.sh xcodebuild -workspace ios/AnalyticsReactNativeE2E.xcworkspace -scheme AnalyticsReactNativeE2E -configuration Release -sdk iphonesimulator -derivedDataPath ios/build", + "yarn detox test --configuration ios.sim.release" + ], + "start:metro": ["metro.sh start ${1:-default}"], + "stop:metro": ["metro.sh stop ${1:-default}"], + "start:sim": ["ios.sh simulator start ${1:-${IOS_DEFAULT_DEVICE:-max}}"], + "stop:sim": ["ios.sh simulator stop"], + "start:emu": [ + "android.sh emulator start ${1:-${ANDROID_DEFAULT_DEVICE:-max}}" + ], + "stop:emu": ["android.sh emulator stop"] + } + } +} diff --git a/examples/E2E-latest/README.md b/examples/E2E-latest/README.md index 8bd066df0..6c16ffbfe 100644 --- a/examples/E2E-latest/README.md +++ b/examples/E2E-latest/README.md @@ -1,8 +1,56 @@ This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). -# Getting Started +# E2E Test App - React Native 0.84 (Latest) -> **Note**: Make sure you have completed the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. +This example app tests SDK compatibility with React Native 0.84.1 + React 19.2.3. + +## Developer Setup (Devbox) + +### Prerequisites + +```bash +# Install devbox +curl -fsSL https://get.jetify.com/devbox | bash +``` + +### Quick Start + +```bash +cd examples/E2E-latest + +# Enter devbox shell (downloads SDKs on first run) +devbox shell + +# Install dependencies +devbox run install + +# Start Android emulator +devbox run start:emu + +# Run E2E tests +devbox run test:e2e:android +``` + +### Available Commands + +- `devbox run install` - Install Node dependencies +- `devbox run install:pods` - Install iOS CocoaPods +- `devbox run build:android` - Build Android app +- `devbox run build:ios` - Build iOS app +- `devbox run test:e2e:android` - Run Android E2E tests +- `devbox run test:e2e:ios` - Run iOS E2E tests +- `devbox run start:emu` - Start Android emulator +- `devbox run start:sim` - Start iOS simulator +- `devbox run stop:emu` - Stop Android emulator +- `devbox run stop:sim` - Stop iOS simulator + +See [mobile-devtools](https://github.com/segment-integrations/mobile-devtools) for more details. + +--- + +# Getting Started (Manual Setup) + +> **Note**: The devbox setup above is recommended. For manual setup, follow the [React Native - Environment Setup](https://reactnative.dev/docs/environment-setup) instructions till "Creating a new application" step, before proceeding. ## Step 1: Start the Metro Server diff --git a/examples/E2E-latest/android/build.gradle b/examples/E2E-latest/android/build.gradle index c83bf5b8a..ae7670564 100644 --- a/examples/E2E-latest/android/build.gradle +++ b/examples/E2E-latest/android/build.gradle @@ -2,16 +2,18 @@ buildscript { ext { - // Default to the build-tools pinned in devbox; allow override via ANDROID_BUILD_TOOLS_VERSION. - // Keep in sync with nix/flake.nix when ANDROID_BUILD_TOOLS_VERSION is unset. - buildToolsVersion = System.getenv("ANDROID_BUILD_TOOLS_VERSION") ?: "30.0.3" + def compileSdkEnv = System.getenv("ANDROID_COMPILE_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "35" + def targetSdkEnv = System.getenv("ANDROID_TARGET_SDK") ?: System.getenv("ANDROID_MAX_API") ?: "35" + buildToolsVersion = System.getenv("ANDROID_BUILD_TOOLS_VERSION") ?: "35.0.0" minSdkVersion = 21 - compileSdkVersion = 33 - targetSdkVersion = 33 + compileSdkVersion = compileSdkEnv.toInteger() + targetSdkVersion = targetSdkEnv.toInteger() kotlinVersion="1.7.20" - // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" + def ndkVersionEnv = System.getenv("ANDROID_NDK_VERSION") + if (ndkVersionEnv) { + ndkVersion = ndkVersionEnv + } } repositories { google() diff --git a/examples/E2E-latest/devbox.json b/examples/E2E-latest/devbox.json new file mode 100644 index 000000000..d811523da --- /dev/null +++ b/examples/E2E-latest/devbox.json @@ -0,0 +1,57 @@ +{ + "include": [ + "github:segment-integrations/mobile-devtools/feat/move-flake-to-devbox-d?dir=plugins/react-native" + ], + "packages": [ + "nodejs@20", + "yarn-berry@latest", + "watchman@latest", + "jdk17@latest", + "gradle@latest" + ], + "env": { + "IOS_APP_SCHEME": "AnalyticsReactNativeE2E", + "IOS_APP_BUNDLE_ID": "com.analyticsreactnativeexample", + "ANDROID_APP_ID": "com.analyticsreactnativeexample", + "ANDROID_APP_APK": "android/app/build/outputs/apk/release/app-release.apk", + "ANDROID_MAX_API": "35", + "ANDROID_SDK_REQUIRED": "0", + "ANDROID_INCLUDE_NDK": "false", + "ANDROID_INCLUDE_CMAKE": "false", + "GRADLE_OPTS": "-Dorg.gradle.project.android.aapt2FromMavenOverride=$ANDROID_SDK_ROOT/build-tools/36.1.0/aapt2" + }, + "shell": { + "scripts": { + "install": ["yarn install"], + "install:pods": ["(cd ios && pod install)"], + "build:android": [ + "yarn install", + "(cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release)" + ], + "build:ios": [ + "yarn install", + "(cd ios && pod install)", + "ios.sh xcodebuild -workspace ios/AnalyticsReactNativeE2E.xcworkspace -scheme AnalyticsReactNativeE2E -configuration Release -sdk iphonesimulator -derivedDataPath ios/build" + ], + "test:e2e:android": [ + "yarn install", + "(cd android && ./gradlew assembleRelease assembleAndroidTest -DtestBuildType=release)", + "yarn detox test --configuration android.emu.release" + ], + "test:e2e:ios": [ + "yarn install", + "(cd ios && pod install)", + "ios.sh xcodebuild -workspace ios/AnalyticsReactNativeE2E.xcworkspace -scheme AnalyticsReactNativeE2E -configuration Release -sdk iphonesimulator -derivedDataPath ios/build", + "yarn detox test --configuration ios.sim.release" + ], + "start:metro": ["metro.sh start ${1:-default}"], + "stop:metro": ["metro.sh stop ${1:-default}"], + "start:sim": ["ios.sh simulator start ${1:-${IOS_DEFAULT_DEVICE:-max}}"], + "stop:sim": ["ios.sh simulator stop"], + "start:emu": [ + "android.sh emulator start ${1:-${ANDROID_DEFAULT_DEVICE:-max}}" + ], + "stop:emu": ["android.sh emulator stop"] + } + } +}