diff --git a/packages/app/.eas/workflows/release-mobile.yml b/packages/app/.eas/workflows/release-mobile.yml index 33f1c2ea6..13968b8b5 100644 --- a/packages/app/.eas/workflows/release-mobile.yml +++ b/packages/app/.eas/workflows/release-mobile.yml @@ -41,7 +41,7 @@ jobs: submit_ios_for_review: name: Submit iOS for App Store review - needs: [submit_ios] + needs: [build_ios, submit_ios] environment: production runs_on: macos-medium steps: @@ -49,4 +49,7 @@ jobs: - name: Install fastlane run: bundle install - name: Submit for review - run: bundle exec fastlane ios submit_review + run: | + export APP_VERSION="${{ needs.build_ios.outputs.app_version }}" + export APP_BUILD_VERSION="${{ needs.build_ios.outputs.app_build_version }}" + bundle exec fastlane ios submit_review diff --git a/packages/app/.eas/workflows/resubmit-ios-review.yml b/packages/app/.eas/workflows/resubmit-ios-review.yml index 0b203de2c..906f8b124 100644 --- a/packages/app/.eas/workflows/resubmit-ios-review.yml +++ b/packages/app/.eas/workflows/resubmit-ios-review.yml @@ -6,7 +6,16 @@ name: Resubmit iOS for App Store review # TestFlight build, without rebuilding or re-uploading. on: - workflow_dispatch: {} + workflow_dispatch: + inputs: + app_version: + type: string + required: false + description: "Marketing version to resubmit, e.g. 0.1.76. Leave empty to target the most recently uploaded iOS build." + app_build_version: + type: string + required: false + description: "CFBundleVersion to resubmit, e.g. 2. Only used when app_version is set." jobs: submit_ios_for_review: @@ -18,4 +27,7 @@ jobs: - name: Install fastlane run: bundle install - name: Submit for review - run: bundle exec fastlane ios submit_review + run: | + export APP_VERSION="${{ inputs.app_version }}" + export APP_BUILD_VERSION="${{ inputs.app_build_version }}" + bundle exec fastlane ios submit_review diff --git a/packages/app/Gemfile b/packages/app/Gemfile index 7a118b49b..102550f22 100644 --- a/packages/app/Gemfile +++ b/packages/app/Gemfile @@ -1,3 +1,3 @@ source "https://rubygems.org" -gem "fastlane" +gem "fastlane", "~> 2.234" diff --git a/packages/app/fastlane/Fastfile b/packages/app/fastlane/Fastfile index 2af230c85..e8d28503d 100644 --- a/packages/app/fastlane/Fastfile +++ b/packages/app/fastlane/Fastfile @@ -11,11 +11,6 @@ platform :ios do key_filepath: ENV.fetch("ASC_KEY_P8"), ) - build_number = latest_testflight_build_number( - api_key: api_key, - app_identifier: APP_IDENTIFIER, - ) - require "spaceship" Spaceship::ConnectAPI.token = Spaceship::ConnectAPI::Token.create( key_id: ENV.fetch("ASC_KEY_ID"), @@ -25,30 +20,58 @@ platform :ios do app = Spaceship::ConnectAPI::App.find(APP_IDENTIFIER) UI.user_error!("Could not find app #{APP_IDENTIFIER} on App Store Connect") if app.nil? + # The release workflow forwards the marketing version and CFBundleVersion of + # the binary it just built. Use them to identify the exact build, since + # CFBundleVersion is not unique across marketing versions in this project + # (the production profile resets it per app_version). The resubmit workflow + # leaves these unset and falls back to "most recently uploaded iOS build". + target_version = ENV["APP_VERSION"].to_s.strip + target_build = ENV["APP_BUILD_VERSION"].to_s.strip + target_version = nil if target_version.empty? + target_build = nil if target_build.empty? + + if target_version + UI.message("Targeting App Store version #{target_version}#{target_build ? " build #{target_build}" : ""} from workflow input") + else + UI.message("No APP_VERSION provided; selecting the most recently uploaded iOS build") + end + valid_build = nil deadline = Time.now + (30 * 60) loop do builds = Spaceship::ConnectAPI::Build.all( app_id: app.id, - build_number: build_number.to_s, - ) - build = builds.find { |b| b.pre_release_version&.platform == "IOS" } - state = build&.processing_state - UI.message("Build #{build_number} processing state: #{state || 'unknown'}") + sort: "-uploadedDate", + limit: 100, + ).select { |b| b.pre_release_version&.platform == "IOS" } + builds = builds.select { |b| b.pre_release_version&.version == target_version } if target_version + builds = builds.select { |b| b.version == target_build } if target_build + + build = builds.first + if build.nil? + UI.user_error!("Timed out waiting for build to appear on App Store Connect.") if Time.now > deadline + UI.message("No matching iOS build visible on App Store Connect yet; waiting...") + sleep(30) + next + end + + state = build.processing_state + UI.message("Build #{build.pre_release_version.version} (#{build.version}) processing state: #{state || 'unknown'}") if state == "VALID" valid_build = build break end if state == "INVALID" || state == "FAILED" - UI.user_error!("Build #{build_number} failed App Store processing (state: #{state}).") + UI.user_error!("Build #{build.version} failed App Store processing (state: #{state}).") end if Time.now > deadline - UI.user_error!("Timed out waiting for build #{build_number} to finish processing on App Store Connect.") + UI.user_error!("Timed out waiting for build #{build.version} to finish processing on App Store Connect.") end sleep(30) end app_version = valid_build.pre_release_version.version + build_number = valid_build.version UI.message("Submitting build #{build_number} as App Store version #{app_version} for review") # Ensure an editable App Store version exists for this marketing version.