From 73d46956a4c8cda975e0074cdaf067c2494f7c16 Mon Sep 17 00:00:00 2001 From: Kieran Osgood Date: Wed, 12 Aug 2026 18:19:37 +0100 Subject: [PATCH] Port the remaining three macOS jobs to the Bitrise ci-ios pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Part of the macOS CI speed-up. Tracked on shop/issues-checkout-kit#1207, under shop/issues-checkout-kit#1202. Completes the port started in the previous PR. `ci-ios` now covers all four slow macOS jobs. ## Change `e2e/config/ios_ci.yml` gains `swift-samples`, `react-native-build-ios` and `react-native-test-ios`. The set-equality invariants from the previous PR then force `e2e/bitrise.yml` to match, which it does: three `ci-ios-*` workflows, three `run_if` blocks, three `share-pipeline-variable@1` entries, and three more names in `ci-ios-report.depends_on`. All three reuse the existing step bundles verbatim — `install-node-modules`, `install-ruby-gems`, `install-cocoapods`, `bootstrap-mint`, `create-ios-simulator`. Both `check_published_podfile_lock` guards are kept, each in its own step **before** `pod install`, so a local-path lockfile is named rather than surfacing as an opaque `--deployment` diff. ## Baselines to beat | Job | n | median | p90 | slowest step | share | | --- | --- | --- | --- | --- | --- | | `React Native / Run iOS Tests` | 11 | 13m19s | 13m53s | `Run iOS tests` 11m44s | 88% | | `React Native / Build iOS Sample` | 11 | 11m59s | 13m54s | `Build iOS sample` 10m27s | 87% | | `Swift / build-and-test-samples` | 11 | 6m38s | 8m10s | `Run Tests` 6m04s | 91% | React Native pair total: 25m18s. Whole-PR CI wall clock: 15m18s. 🟡 Variance is wide across all four jobs. Only the median over n ≥ 10 is worth comparing. ## Selection, verified | Change | Jobs selected | | --- | --- | | `platforms/swift/**` | `swift-package-tests`, `swift-samples` | | `platforms/react-native/**` | `react-native-build-ios`, `react-native-test-ios` | | `Package.swift` | all four | | `README.md` | none — `CI_IOS_HAS_JOBS=false` | `Package.swift` selecting all four mirrors `ci.yml:63-64` and `ci.yml:90-91`. ## Verification - `shadowenv exec -- ./scripts/test_ruby` — 293 runs, 0 failures. - `shadowenv exec -- bitrise validate --config=e2e/bitrise.yml` — valid. - Negative control: removing one flag and one `run_if` block fails all three set-equality invariants. ## Decisions made without you - **`swift-samples` secrets**: the samples only need a well-formed storefront configuration to compile, so the job exports placeholder values and calls `scripts/setup_storefront_env --skip-optional-prompts` directly. It does not call `e2e_configure_storefront`, which asserts the real secrets. Staying off them is what lets the job run on fork pull requests. - **`react-native-test-ios` pods**: not the `install-cocoapods` bundle — that one owns the sample app's Pods tree, and `test_ios` runs `pod install` for the integration app itself. An inline `restore-cache` / `save-cache` pair carries `test/rct-integration-app/Pods` instead. The plan called for a step bundle; inline is used because a bundle cannot wrap a step that lives in the workflow, and the paired-cache invariant added in the next PR would flag a split pair. - **`bootstrap-mint` in `react-native-test-ios`**: `test_ios` calls `generate_xcode_projects`, which needs xcodegen. --- e2e/bitrise.yml | 127 ++++++++++++++++++++++++++++++++++++++++++ e2e/config/ios_ci.yml | 26 +++++++++ 2 files changed, 153 insertions(+) diff --git a/e2e/bitrise.yml b/e2e/bitrise.yml index 64dfb72f0..eff063f35 100644 --- a/e2e/bitrise.yml +++ b/e2e/bitrise.yml @@ -110,11 +110,29 @@ pipelines: expression: '{{ enveq "CI_IOS_SWIFT_PACKAGE_TESTS" "true" }}' depends_on: - ci-ios-plan + ci-ios-swift-samples: + run_if: + expression: '{{ enveq "CI_IOS_SWIFT_SAMPLES" "true" }}' + depends_on: + - ci-ios-plan + ci-ios-react-native-build-ios: + run_if: + expression: '{{ enveq "CI_IOS_REACT_NATIVE_BUILD_IOS" "true" }}' + depends_on: + - ci-ios-plan + ci-ios-react-native-test-ios: + run_if: + expression: '{{ enveq "CI_IOS_REACT_NATIVE_TEST_IOS" "true" }}' + depends_on: + - ci-ios-plan # No run_if: this workflow is the required check, so it posts on every build, # including one where ci-ios-plan selected nothing and every job was skipped. ci-ios-report: depends_on: - ci-ios-swift-package-tests + - ci-ios-swift-samples + - ci-ios-react-native-build-ios + - ci-ios-react-native-test-ios should_always_run: workflow # Deliberately absent from trigger_map: a scheduled build in the Bitrise UI is @@ -280,6 +298,9 @@ workflows: CI_IOS_HAS_JOBS CI_IOS_SELECTED_JOBS CI_IOS_SWIFT_PACKAGE_TESTS + CI_IOS_SWIFT_SAMPLES + CI_IOS_REACT_NATIVE_BUILD_IOS + CI_IOS_REACT_NATIVE_TEST_IOS ci-ios-swift-package-tests: meta: @@ -302,6 +323,112 @@ workflows: cd platforms/swift ./Scripts/xcode_run test ShopifyCheckoutKit-Package + ci-ios-swift-samples: + meta: + bitrise.io: + stack: *macos_stack + machine_type_id: g2.mac.4large + steps: + - git-clone@8: {} + - bundle::create-ios-simulator: {} + - bundle::bootstrap-mint: + inputs: + - mintfile_dir: platforms/swift + - script@1: + title: Build and test the Swift sample apps + timeout: 5400 + no_output_timeout: 1800 + inputs: + - content: |- + set -euo pipefail + # The samples only need a well-formed storefront configuration to compile, + # so this job runs on placeholders rather than e2e_configure_storefront, + # which asserts the real secrets. Keeping it off them is what lets the job + # run on fork pull requests, where Bitrise withholds secrets. + export STOREFRONT_DOMAIN="${STOREFRONT_DOMAIN:-example.myshopify.com}" + export STOREFRONT_ACCESS_TOKEN="${STOREFRONT_ACCESS_TOKEN:-test-token}" + ./scripts/setup_storefront_env --skip-optional-prompts + cd platforms/swift + ./Scripts/build_and_test_samples + + ci-ios-react-native-build-ios: + meta: + bitrise.io: + stack: *macos_stack + machine_type_id: g2.mac.4large + steps: + - git-clone@8: {} + - bundle::create-ios-simulator: {} + - script@1: + title: Verify the sample lockfile resolves the published native SDK + timeout: 300 + no_output_timeout: 150 + inputs: + - content: |- + set -euo pipefail + # Runs before pod install: --deployment would also catch a local-path + # lockfile, but only as an opaque diff. This names the problem. + cd platforms/react-native + scripts/check_published_podfile_lock sample/ios/Podfile.lock + - bundle::install-node-modules: {} + - bundle::install-ruby-gems: {} + - bundle::install-cocoapods: {} + - script@1: + title: Build the React Native iOS sample + timeout: 5400 + no_output_timeout: 1800 + inputs: + - content: |- + set -euo pipefail + cd platforms/react-native + pnpm module build + pnpm sample build:ios + + ci-ios-react-native-test-ios: + meta: + bitrise.io: + stack: *macos_stack + machine_type_id: g2.mac.4large + steps: + - git-clone@8: {} + - bundle::create-ios-simulator: {} + - script@1: + title: Verify the integration app lockfile resolves the published native SDK + timeout: 300 + no_output_timeout: 150 + inputs: + - content: |- + set -euo pipefail + cd platforms/react-native + scripts/check_published_podfile_lock test/rct-integration-app/Podfile.lock + - bundle::install-node-modules: {} + - bundle::install-ruby-gems: {} + # xcodegen generates the integration app's project from project.yml. + - bundle::bootstrap-mint: + inputs: + - mintfile_dir: platforms/swift + # Not the install-cocoapods bundle: that one owns the sample app's Pods tree. + # test_ios runs `pod install` for the integration app itself, so this pair only + # carries the resulting Pods directory across builds. + - restore-cache@3: + inputs: + - key: &rct_integration_cocoapods_cache_key |- + rct-integration-cocoapods-{{ .OS }}-{{ .Arch }}-{{ checksum "platforms/react-native/test/rct-integration-app/Podfile.lock" }} + - script@1: + title: Run the React Native iOS tests + timeout: 5400 + no_output_timeout: 1800 + inputs: + - content: |- + set -euo pipefail + cd platforms/react-native + pnpm module build + pnpm sample test:ios + - save-cache@1: + inputs: + - key: *rct_integration_cocoapods_cache_key + - paths: platforms/react-native/test/rct-integration-app/Pods + ci-ios-report: steps: - git-clone@8: {} diff --git a/e2e/config/ios_ci.yml b/e2e/config/ios_ci.yml index de7a8495a..30649ddc6 100644 --- a/e2e/config/ios_ci.yml +++ b/e2e/config/ios_ci.yml @@ -16,3 +16,29 @@ jobs: - packageSwift - ciFilters - iosCiConfig + - id: swift-samples + changed_files_filters: + - swift + - protocolSwift + - protocolShared + - packageSwift + - ciFilters + - iosCiConfig + # packageSwift mirrors the reactNativeIos infra filter in ci.yml: the sample app + # resolves the Swift package, so a manifest change rebuilds the React Native apps too. + - id: react-native-build-ios + changed_files_filters: + - reactNative + - protocolTypescript + - protocolShared + - packageSwift + - ciFilters + - iosCiConfig + - id: react-native-test-ios + changed_files_filters: + - reactNative + - protocolTypescript + - protocolShared + - packageSwift + - ciFilters + - iosCiConfig