perf(ci): Parallelize screenshot generation across CI jobs#113
Merged
perf(ci): Parallelize screenshot generation across CI jobs#113
Conversation
Split screenshot generation into build-once + run-per-device jobs to eliminate fastlane snapshot's per-device-family rebuild and enable targeted retries on failure. New lanes: - build_screenshots: xcodebuild build-for-testing (single build) - run_screenshot_on_device: test-without-building on one device - collect_screenshots: gather results into fastlane/screenshots/ - generate_screenshots_parallel: local convenience lane Split release_ci into release_ci_build + release_ci_upload so the release workflow can run IPA build and screenshot generation in parallel, then combine for App Store upload.
📲 Install BuildsiOS
|
Adds a resolve-ref job that captures main's HEAD once, then feeds that SHA into every downstream job's checkout. Without this, each parallel job resolves `ref: main` independently and could diverge if main advances mid-release.
Adds a `ref` workflow_dispatch input (default: main) so the release can be tested from a feature branch before merging. The resolve-ref job resolves whichever ref was dispatched to an explicit SHA. Concurrency group is now ref-agnostic: only one release runs at a time regardless of ref, to avoid App Store Connect contention.
scan auto-discovers Flinky.xcodeproj from cwd and bails with "Multiple schemes found". Adds explicit scheme: "ScreenshotUITests" and test_without_building: true to reuse the pre-built xctestrun bundle instead of triggering a rebuild.
_commit_and_tag_version_signed overlays VERSION_BUMP_FILES onto main's tree and fast-forwards main, regardless of which ref was dispatched. When dispatched from a feature branch, the resulting tag points to a hybrid tree that does not match the IPA actually uploaded — a data integrity issue. release_ci_upload now accepts a `ref` option and skips the commit+tag step unless ref == main. The release workflow passes inputs.ref through. Normal main releases are unchanged; feature-branch test dispatches leave git history clean.
_boot_simulator ran `xcrun simctl boot` and immediately returned, but that command only kicks off the boot process — it doesn't wait for the simulator to reach the home screen. On slow CI runners, _override_status_bar would then race the boot and silently no-op, leaking the real clock into screenshots (same class of bug that PR #120 fixed in the snapshot action's path). Add `xcrun simctl bootstatus <udid> -b` after `boot` to block until the simulator is fully booted. This matches what fastlane/snapshot does in simulator_launcher_base.rb:124.
The matrix screenshot jobs use scan (run_tests) rather than snapshot (capture_screenshots), so the retries added in #119 don't apply here. iPad matrix jobs are consistently flaking at the long-press / context-menu interaction (ScreenshotUITests:66) and failing the whole release because release-upload needs the matrix. Add number_of_retries: 3 to the run_tests call so scan retries the test before giving up, matching the snapshot lane's behaviour.
upload_to_app_store rejects build_number when ipa: is set; the value is read from the IPA. Drop the duplicate arg so publish_ci_upload stops failing with "You can't use 'build_number' and 'ipa' options in one run." Rename release_beta_ci -> beta_ci, release_ci_build -> publish_ci_build, release_ci_upload -> publish_ci_upload so the local/CI lane pairs share prefixes. Drop the dead release_ci lane (superseded by the parallel build/upload split).
run_screenshot_on_device already passes number_of_retries: 3 to scan, but GHA simulator runs still failed the step when the first iteration flaked and a later iteration passed: scan's exit logic counted the retried attempt as a real failure. Switch the run_tests call to fail_build: false and decide pass/fail from the returned :number_of_failures_excluding_retries. Add output_remove_retry_attempts: true so reports stay clean. Wrap everything in a 2-attempt outer loop that hard-reboots the simulator (shutdown + boot + bootstatus -b) between attempts to recover from a wedged sim that even -retry-tests-on-failure can't unstick. Drop log: false on the simctl boot/shutdown/bootstatus/clear commands so their output is visible when CI fails — only the bulky `simctl list devices -j` JSON dump stays silenced.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parallelize App Store screenshot generation to reduce release workflow time.
Previously,
fastlane snapshotran screenshots in 2 batches (iPhones, then iPads), rebuilding the test target for each batch. With 4 devices this took ~48 minutes — most of it building, not testing (actual UI tests take <1 min per device).This PR introduces a build-once + run-per-device approach:
build_screenshotslane runsxcodebuild build-for-testingoncerun_screenshot_on_devicelane runstest-without-buildingon a single device with status bar overridecollect_screenshotsgathers PNGs intofastlane/screenshots/en-US/The release workflow is restructured into parallel jobs:
release-build— IPA build, validation, Sentry setup (runs in parallel with screenshots)build-screenshots— single test bundle buildscreenshot(matrix: 4 devices) — parallel per-device test executionrelease-upload— collects everything, uploads to App StoreBenefits:
New lanes
release_ci_buildandrelease_ci_uploadsplit the monolithicrelease_cifor the multi-job workflow. The originalrelease_cilane is preserved for single-job use.