Skip to content

Add release-pipeline automation scripts#2140

Open
jagerman wants to merge 3 commits into
session-foundation:devfrom
jagerman:release-tooling
Open

Add release-pipeline automation scripts#2140
jagerman wants to merge 3 commits into
session-foundation:devfrom
jagerman:release-tooling

Conversation

@jagerman

Copy link
Copy Markdown
Member

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.

jagerman and others added 3 commits July 9, 2026 21:50
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant