mirror of
https://github.com/stablyai/orca.git
synced 2026-10-16 16:03:26 +00:00
fix(mobile): auto-bump iOS version when App Store train is closed
The iOS release lane auto-increments the TestFlight build number but never the marketing version. Once a version is submitted/approved/released its train closes, so any further build upload is rejected by Apple (~20 min in) with altool 90186 / 90062 — with no signal until then and no guard beyond a manual 'bump patch' checkbox the dispatcher had to remember to tick. prepare_release_version now checks the App Store version state via Spaceship::ConnectAPI before building. If the resolved version's train is closed it auto-bumps the patch (advancing past any further closed versions), preserving normal multi-build beta iteration on an open version. An explicit release_version override that's already closed fails fast with a clear message instead of being silently overridden. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -10,7 +10,7 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
bump_patch_version:
|
||||
description: 'Bump the iOS marketing version patch number before release'
|
||||
description: 'Force a marketing version patch bump. Usually unnecessary: a released version auto-bumps. Use this to start a new version while the current one is still open (beta iteration).'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
@@ -30,6 +30,23 @@ BUNDLE_ID = "com.stably.orca.mobile"
|
||||
TESTFLIGHT_GROUPS = ["peeps"].freeze
|
||||
DEFAULT_TESTFLIGHT_CHANGELOG = "Latest Orca Mobile updates and fixes.".freeze
|
||||
|
||||
# App Store version states in which the version "train" no longer accepts new
|
||||
# TestFlight build uploads (altool rejects with 90186 "train ... is closed").
|
||||
# Once a version has been submitted/approved/released, builds must go under a
|
||||
# higher marketing version. PROCESSING_FOR_APP_STORE / IN_REVIEW are included
|
||||
# conservatively: a build is already committed to that train.
|
||||
CLOSED_APP_STORE_STATES = %w[
|
||||
READY_FOR_SALE
|
||||
PENDING_DEVELOPER_RELEASE
|
||||
PENDING_APPLE_RELEASE
|
||||
PROCESSING_FOR_APP_STORE
|
||||
IN_REVIEW
|
||||
WAITING_FOR_REVIEW
|
||||
REPLACED_WITH_NEW_VERSION
|
||||
REMOVED_FROM_SALE
|
||||
DEVELOPER_REMOVED_FROM_SALE
|
||||
].freeze
|
||||
|
||||
def app_store_connect_api_key_from_env
|
||||
app_store_connect_api_key(
|
||||
key_id: ENV.fetch("ASC_KEY_ID"),
|
||||
@@ -71,6 +88,18 @@ def resolve_requested_version(options, config)
|
||||
truthy_option?(options[:bump_patch]) ? bump_patch_version(current_version) : current_version
|
||||
end
|
||||
|
||||
# Returns true when `version`'s App Store train is closed to new build uploads.
|
||||
# app_store_connect_api_key (set_spaceship_token: true, the default) has already
|
||||
# authenticated Spaceship::ConnectAPI globally, so no extra auth is needed here.
|
||||
def version_train_closed?(version)
|
||||
app = Spaceship::ConnectAPI::App.find(BUNDLE_ID)
|
||||
return false unless app
|
||||
|
||||
app
|
||||
.get_app_store_versions(filter: { versionString: version })
|
||||
.any? { |app_store_version| CLOSED_APP_STORE_STATES.include?(app_store_version.app_store_state) }
|
||||
end
|
||||
|
||||
def testflight_changelog
|
||||
changelog = ENV.fetch("TESTFLIGHT_CHANGELOG", "").strip
|
||||
changelog.empty? ? DEFAULT_TESTFLIGHT_CHANGELOG : changelog
|
||||
@@ -82,6 +111,29 @@ platform :ios do
|
||||
api_key = app_store_connect_api_key_from_env
|
||||
config = load_mobile_app_config
|
||||
version = resolve_requested_version(options, config)
|
||||
explicit_version = !options[:version].to_s.strip.empty?
|
||||
|
||||
# A closed train (version already submitted/approved/released) cannot accept
|
||||
# more builds, so Apple would reject the upload (~20 min later) with 90186.
|
||||
# Auto-bump the patch in the default path; if the caller pinned an exact
|
||||
# version, fail loudly rather than silently overriding their choice.
|
||||
if version_train_closed?(version)
|
||||
if explicit_version
|
||||
UI.user_error!(
|
||||
"Requested iOS version #{version} is already submitted/released on the App Store " \
|
||||
"and cannot accept new builds. Choose a higher release_version.",
|
||||
)
|
||||
end
|
||||
# Advance until we find an open train (handles the rare case where the
|
||||
# next patch was also already shipped). Bounded to avoid an infinite loop.
|
||||
original = version
|
||||
10.times do
|
||||
version = bump_patch_version(version)
|
||||
break unless version_train_closed?(version)
|
||||
end
|
||||
UI.user_error!("Could not find an open iOS version train after #{original}.") if version_train_closed?(version)
|
||||
UI.message("iOS version #{original} is closed for new builds; bumping to #{version}.")
|
||||
end
|
||||
|
||||
latest_build_number = latest_testflight_build_number(
|
||||
api_key: api_key,
|
||||
|
||||
Reference in New Issue
Block a user