From 88ae20cfdb70908816b8c6f7413e0a4ce341faed Mon Sep 17 00:00:00 2001 From: Oguz Kocer Date: Thu, 23 Jul 2026 17:22:35 -0400 Subject: [PATCH] Promote to production via track promotion instead of a new release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `promote_version_code_to_production` now uses `upload_to_play_store` with `track_promote_to` (the Play Console "Promote" action) instead of building a new production release via `update_track`. This extends the already-reviewed beta release to the production track — same versionCode, no new binary — so the beta release's notes and name carry over automatically. Ships as a live staged rollout (`inProgress` at 0.1%); `advance_production_rollout` grows it from there. --- fastlane/lanes/promote.rb | 56 +++++++++++++++------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/fastlane/lanes/promote.rb b/fastlane/lanes/promote.rb index a81b7fba4255..05d5d5ef822c 100644 --- a/fastlane/lanes/promote.rb +++ b/fastlane/lanes/promote.rb @@ -417,42 +417,30 @@ def distribute_to_production(version_code:) end end - # Creates a `production` release referencing an already-uploaded version code, via the Play API — - # the same approach as promote_version_code_to_beta (see there for why upload_to_play_store can't). + # Promotes the existing beta build to production — the scripted equivalent of the Play Console + # "Promote" button. `track_promote_to` extends the already-reviewed beta release to the production + # track (same versionCode, no new binary): supply reuses that beta TrackRelease, so its release + # notes and name carry over automatically, and its version codes (incl. the retained legacy code) + # come along too. def promote_version_code_to_production(package_name:, version_code:) - require 'supply' - require 'supply/options' - - Supply.config = FastlaneCore::Configuration.create( - Supply::Options.available_options, - { json_key: UPLOAD_TO_PLAY_STORE_JSON_KEY, package_name: package_name, track: PRODUCTION_TRACK } + upload_to_play_store( + package_name: package_name, + json_key: UPLOAD_TO_PLAY_STORE_JSON_KEY, + track: BETA_TRACK, + track_promote_to: PRODUCTION_TRACK, + version_code: Integer(version_code), + # Promote as a live staged rollout: a `rollout` in (0, 1) makes supply set the promoted + # release to `inProgress` at that user fraction. Starting tiny (0.1%) exercises the full + # production flow end to end; `advance_production_rollout` grows it from there. + rollout: '0.001', + # Promotion touches only the track release, never a binary — skip every upload path. + skip_upload_apk: true, + skip_upload_aab: true, + skip_upload_metadata: true, + skip_upload_changelogs: true, + skip_upload_images: true, + skip_upload_screenshots: true ) - - with_play_edit_retries("Promoting #{version_code} to production for #{package_name}") do - client = Supply::Client.make_from_config - client.begin_edit(package_name: package_name) - - committed = false - begin - release = AndroidPublisher::TrackRelease.new( - # TODO: swap `draft` for the staged rollout below once the full production flow is ready; - # until then it ships as a draft a human starts from the Play Console. - status: 'draft', - # status: 'inProgress', - # user_fraction: 0.001, - version_codes: [Integer(version_code), *PLAY_STORE_VERSION_CODES_TO_RETAIN] - ) - track = client.tracks(PRODUCTION_TRACK).first || AndroidPublisher::Track.new(track: PRODUCTION_TRACK) - track.releases = [release] - - client.update_track(PRODUCTION_TRACK, track) - client.commit_current_edit! - committed = true - ensure - # Discard the edit if we bailed before committing (a committed edit can't be aborted). - client.abort_current_edit unless committed - end - end end #################################################