diff --git a/README.md b/README.md index bacdf58a5fb6..f15a8101b46d 100644 --- a/README.md +++ b/README.md @@ -110,10 +110,21 @@ the APK on the GitHub release. That is what keeps a version on a single commit - the `v*` tag names and F-Droid builds. Internal is the only track it uploads to. Anything wider - closed, open, production - -is a promotion in the Play Console, which moves the same bundle and version code that -was tested onto the wider track instead of uploading a second one. It is also where the -review that a production release waits on actually happens, so the workflow finishing is -not the same as the release being out. +is a promotion, which moves the same bundle and version code that was tested onto the +wider track instead of uploading a second one. A version code is spent the moment it +goes up, so there is one upload per release and every track after it is an assignment +of what is already there. + +`fastlane android openTestingPro` and `openTestingLite` promote to open testing, given +the version whose code should move: + +```sh +fastlane android openTestingLite version:v4.17.0 +``` + +Closed testing and production are still the Play Console. Play reviews a promotion like +any other release - only the internal track is immediate - so neither the workflow +finishing nor the promotion running is the same as the release being out. The listing goes up in its own job, behind the bundle: the title, both descriptions, the release notes of that version, the screenshots and the feature graphic, in all fifteen diff --git a/fastlane/Fastfile b/fastlane/Fastfile index bbda403a07b0..28204ca10a56 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -10,6 +10,10 @@ PACKAGE_NAMES = { DEFAULT_TRACK = "internal".freeze +# what the console calls open testing. Supply kept the older track names, so the +# one a promotion has to name is not the one the console shows. +OPEN_TESTING_TRACK = "beta".freeze + # absolute, because a lane and an action do not agree on what the working directory # is, and every path below is handed to something else ROOT = File.expand_path("..", __dir__).freeze @@ -174,6 +178,16 @@ platform :android do uploadListing(flavor: "Lite", track: options[:track], version: options[:version]) end + desc "Move the Pro version already on the internal track to open testing" + lane :openTestingPro do |options| + promoteBundle(flavor: "Pro", version: options[:version]) + end + + desc "Move the Lite version already on the internal track to open testing" + lane :openTestingLite do |options| + promoteBundle(flavor: "Lite", version: options[:version]) + end + lane :tests do gradle(task: "connectedAndroidTest") end @@ -252,6 +266,43 @@ platform :android do ) end + # A promotion, not a second upload: the bundle is already in the artifact library + # and a version code is spent the moment it goes up, so the wider track is handed + # the build the narrower one tested rather than one built again beside it. + # + # Play reviews this like any other release - what the lane saves is the console, + # not the wait. The source track keeps serving the release it is promoted from. + private_lane :promoteBundle do |options| + flavor = options[:flavor] + version = require_version(options[:version]) + + upload_to_play_store( + track: DEFAULT_TRACK, + track_promote_to: OPEN_TESTING_TRACK, + # spelled out rather than left to the default: a promotion that lands as a + # draft, or at a percent of the testers, is the failure that looks like success + track_promote_release_status: "completed", + package_name: PACKAGE_NAMES.fetch(flavor), + json_key: ENV["ODR_PLAY_JSON_KEY"] || + CredentialsManager::AppfileConfig.try_fetch_value(:json_key_file), + # which release moves, and there is no bundle to read it off as uploadBundle + # has. It is a filter, not a label: supply keeps the source track's release + # carrying this code and errors when none does, so a version that never + # reached internal fails the lane rather than promoting what it is serving. + version_code: version_code(version), + # nothing new goes up here - the listing and its notes are already against + # this version code, and resending them is uploadListing's job. Skipping both + # binaries is what puts supply on the promotion path at all: hand it one to + # upload and it updates the source track and never reads track_promote_to. + skip_upload_aab: true, + skip_upload_apk: true, + skip_upload_metadata: true, + skip_upload_changelogs: true, + skip_upload_images: true, + skip_upload_screenshots: true + ) + end + desc "Take the play store screenshots of one device, in every locale the listing is written in" lane :screenshots do device = screenshot_device