From ed7d9ef441c1093db23bd8b9b06efe1c3873857a Mon Sep 17 00:00:00 2001 From: joshavant <830519+joshavant@users.noreply.github.com> Date: Thu, 23 Jul 2026 21:15:33 -0500 Subject: [PATCH] fix(ios): preserve planned build during release validation --- apps/ios/fastlane/Fastfile | 17 ++--------------- test/scripts/ios-release-fastlane-gates.test.ts | 15 ++++++++++----- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/apps/ios/fastlane/Fastfile b/apps/ios/fastlane/Fastfile index c33251895799..edcfefbe0854 100644 --- a/apps/ios/fastlane/Fastfile +++ b/apps/ios/fastlane/Fastfile @@ -1433,19 +1433,6 @@ def resolve_release_build_number(api_key:, short_version:, explicit_build_number next_build.to_s end -def verify_app_store_binary!(api_key:, ipa_path:) - deliver( - api_key: api_key, - app_identifier: APP_STORE_APP_IDENTIFIER, - ipa: ipa_path, - platform: "ios", - verify_only: true, - skip_metadata: true, - skip_screenshots: true, - submit_for_review: false - ) -end - def release_build_number_needs_app_store_connect_auth?(explicit_build_number: nil) explicit = explicit_build_number.to_s.strip !env_present?(explicit) @@ -1984,9 +1971,9 @@ platform :ios do end verify_apple_release_source!(release_sha) build = build_app_store_release(context) - verify_app_store_binary!(api_key: context[:api_key], ipa_path: build[:ipa_path]) # Release operations have one active uploader by policy. This final read - # catches human state changes; it is not a cross-uploader lock. + # catches human state changes before the first App Store mutation; it is + # not a cross-uploader lock. resolve_ios_release_plan!( release_version: context[:version], app_store_revision: context[:app_store_revision], diff --git a/test/scripts/ios-release-fastlane-gates.test.ts b/test/scripts/ios-release-fastlane-gates.test.ts index 6c7517c479bb..b6c43034ae7a 100644 --- a/test/scripts/ios-release-fastlane-gates.test.ts +++ b/test/scripts/ios-release-fastlane-gates.test.ts @@ -178,15 +178,20 @@ describe("iOS Fastlane release upload gates", () => { expect(uploadCall).toBeGreaterThan(validationCall); }); - it("validates with Apple and rechecks the plan before the first remote mutation", () => { - const releaseUpload = laneBody(readFastfile(), "release_upload"); - const binaryValidation = releaseUpload.indexOf("verify_app_store_binary!"); + it("rechecks the plan after local validation and before the first App Store mutation", () => { + const fastfile = readFastfile(); + const releaseUpload = laneBody(fastfile, "release_upload"); + const build = releaseUpload.indexOf("build = build_app_store_release(context)"); const planRecheck = releaseUpload.lastIndexOf("resolve_ios_release_plan!"); const metadata = releaseUpload.indexOf("\n metadata("); + const upload = releaseUpload.indexOf("upload_to_testflight("); - expect(binaryValidation).toBeGreaterThanOrEqual(0); - expect(planRecheck).toBeGreaterThan(binaryValidation); + expect(fastfile).not.toContain("def verify_app_store_binary!"); + expect(releaseUpload).not.toContain("verify_only: true"); + expect(build).toBeGreaterThanOrEqual(0); + expect(planRecheck).toBeGreaterThan(build); expect(metadata).toBeGreaterThan(planRecheck); + expect(upload).toBeGreaterThan(planRecheck); }); it("waits for Apple build processing without submitting to TestFlight review", () => {