Add release-pipeline automation scripts#2140
Open
jagerman wants to merge 3 commits into
Open
Conversation
README linked to BUILDING.md, which does not exist. The build instructions live in RELEASE.md; point the link there. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Capture the toolchain, flavors/build types, the play build + emulator install commands, and the Crowdin "strings.xml is generated, don't hand-edit" gotcha (pointing at ARCHITECTURE.md), so future sessions can pick it up. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Automate the mechanical, error-prone parts of cutting a Session Android
release, and move all signing/publishing credentials off disk into the OS
keyring. The scripts are plain Python 3 (no uv/venv bootstrap) and shell out to
git, gh, gradlew, and fdroid.
## Credentials (OS keyring)
Signing keys and the Play API key no longer sit in plaintext files. They are
stored once in the OS keyring -- cross-platform via the `keyring` library
(macOS Keychain, Linux Secret Service, ...) -- and read at run time:
- release-creds the signing-keystore TOML (play / huawei / fdroid)
- play-service-account the Play Developer API service-account JSON key
_keyring.py is the shared helper, with a set/get/del CLI:
python3 scripts/_keyring.py set release-creds < release-creds.toml
## The tools
- prepare-release.py X.Y.Z [--from BRANCH]
Forks release/X.Y.Z from master (or --from), bumps canonicalVersionCode and
canonicalVersionName in app/build.gradle.kts, commits, pushes, and opens a
GitHub draft release with placeholder notes -- then stops so you drive the
merges yourself. --dry-run previews; --yes skips the prompt.
- update-release-notes.py X.Y.Z
(Re)generates the draft's changelog using GitHub's own release-notes
generator for the finalized branch and overwrites the draft body. Run it
after the merges and before signing (it replaces the whole body).
- build-and-release.py [--build-only]
Builds every flavor -- play (AAB + split APKs), fdroid (APKs), huawei
(universal APK) -- signed with the keyring creds; opens the automated F-Droid
PR against session-fdroid; and uploads the play/huawei artifacts to the
GitHub draft. --build-only skips the F-Droid PR and the GitHub upload, for a
local build/signing check.
- play-store.py {status | upload | rollout}
Play Developer API tool:
status list each track's releases (version code,
status, rollout %)
upload [AAB] --track T [...] upload the AAB as a draft (default), a
full rollout (--submit), or a staged
rollout (--rollout 0.1). Only the AAB is
sent; Play derives the device splits.
rollout {FRACTION|complete|halt} change a live staged rollout without
re-uploading -- bump the %, go to 100%,
or pause it.
## A release, end to end
# land the change on dev via its PR first, then:
scripts/prepare-release.py 1.33.5 # branch + version bump + draft
git switch release/1.33.5 && git merge origin/dev && git push
scripts/update-release-notes.py 1.33.5 # changelog onto the draft
scripts/build-and-release.py # build all flavors, F-Droid PR, upload to draft
<your PGP signing script> # sign files + append signature block
scripts/play-store.py upload --track production --submit # AAB -> Play
# human go-live steps:
gh release edit 1.33.5 --draft=false # publish the GitHub release (creates the tag)
scripts/play-store.py rollout ... # ramp the Play rollout if staged
# + click Publish in the Play Console, merge the F-Droid PR,
# + merge release/1.33.5 into master
## Play API gaps worth knowing
- With managed publishing on, a submitted Play release is reviewed but held for
a manual Publish in the console; there is no API for that final publish, nor
for querying review status (status shows rollout state only).
- Play has no native timed rollout ramp -- `rollout` is the primitive to script
one (e.g. a daily cron that bumps the fraction).
- Huawei has no store automation: its APK is attached to the GitHub release
only; any AppGallery upload is manual.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automate the mechanical, error-prone parts of cutting a Session Android
release, and move all signing/publishing credentials off disk into the OS
keyring. The scripts are plain Python 3 (no uv/venv bootstrap) and shell out to
git, gh, gradlew, and fdroid.
Credentials (OS keyring)
Signing keys and the Play API key no longer sit in plaintext files. They are
stored once in the OS keyring -- cross-platform via the
keyringlibrary(macOS Keychain, Linux Secret Service, ...) -- and read at run time:
_keyring.py is the shared helper, with a set/get/del CLI:
The tools
prepare-release.py X.Y.Z [--from BRANCH]
Forks release/X.Y.Z from master (or --from), bumps canonicalVersionCode and
canonicalVersionName in app/build.gradle.kts, commits, pushes, and opens a
GitHub draft release with placeholder notes -- then stops so you drive the
merges yourself. --dry-run previews; --yes skips the prompt.
update-release-notes.py X.Y.Z
(Re)generates the draft's changelog using GitHub's own release-notes
generator for the finalized branch and overwrites the draft body. Run it
after the merges and before signing (it replaces the whole body).
build-and-release.py [--build-only]
Builds every flavor -- play (AAB + split APKs), fdroid (APKs), huawei
(universal APK) -- signed with the keyring creds; opens the automated F-Droid
PR against session-fdroid; and uploads the play/huawei artifacts to the
GitHub draft. --build-only skips the F-Droid PR and the GitHub upload, for a
local build/signing check.
play-store.py {status | upload | rollout}
Play Developer API tool:
status list each track's releases (version code,
status, rollout %)
upload [AAB] --track T [...] upload the AAB as a draft (default), a
full rollout (--submit), or a staged
rollout (--rollout 0.1). Only the AAB is
sent; Play derives the device splits.
rollout {FRACTION|complete|halt} change a live staged rollout without
re-uploading -- bump the %, go to 100%,
or pause it.
A release, end to end
Play API gaps worth knowing
a manual Publish in the console; there is no API for that final publish, nor
for querying review status (status shows rollout state only).
rolloutis the primitive to scriptone (e.g. a daily cron that bumps the fraction).
only; any AppGallery upload is manual.