Skip to content
Open
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
49328a4
Add Release Playbook wiki page stub
Sandesh282 Aug 9, 2026
3cdcc76
Complete Release Playbook wiki page with coordinator checklists
Sandesh282 Aug 13, 2026
68b2103
minor fix
Sandesh282 Aug 13, 2026
12edde9
Address review: workflow display names, QA clarifications, rollout % …
Sandesh282 Aug 27, 2026
cbc391c
Add build_and_sign.yml dispatch screenshot to §3 Build & sign
Sandesh282 Aug 27, 2026
89b972f
Add deploy_to_play_console.yml dispatch screenshot to §1 alpha release
Sandesh282 Aug 27, 2026
8b786f9
Add deploy_to_play_console.yml dispatch screenshot to §3 production D…
Sandesh282 Aug 27, 2026
c0e699a
Address review: clarify rollout_fraction unit, version.bzl trigger, a…
Sandesh282 Aug 28, 2026
f968360
minor edit
Sandesh282 Aug 28, 2026
4468d64
Make pre-release steps unambiguously RC-owned actions
Sandesh282 Aug 28, 2026
3368526
Address review: link Generate Changelogs references in §3 to §2
Sandesh282 Aug 31, 2026
40c0bb0
Refactor rollout_fraction to rollout_permille
Sandesh282 Sep 11, 2026
eed7dc6
Merge remote-tracking branch 'upstream/develop' into pr2.7
Sandesh282 Sep 11, 2026
a4a987c
Complete rollout_permille rename: local vars, test names, and wiki
Sandesh282 Sep 11, 2026
28dfbe5
Fix remaining 'rollout fraction' prose in comments, KDoc, and wiki
Sandesh282 Sep 11, 2026
36cee80
minor edits
Sandesh282 Sep 11, 2026
22255cb
Update wiki/app-and-feature-release-process.md
Sandesh282 Sep 11, 2026
b22dfee
Update wiki/app-and-feature-release-process.md
Sandesh282 Sep 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions wiki/Release-Playbook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Release Playbook

This page is the step-by-step coordinator guide for Oppia Android releases using the automated
release pipeline. For conceptual background on any step, see the
[App and Feature Release Process](app-and-feature-release-process.md) wiki page. For manual
fallback procedures when automation fails, see the
[In-Depth Release Reference](In-Depth-Release-Reference.md).

---

## Table of Contents

1. [Weekly alpha release](#1-weekly-alpha-release)
2. [Changelog review](#2-changelog-review)
3. [Production release](#3-production-release)
4. [Staged rollout](#4-staged-rollout)
5. [Weekly coordinator checklist](#5-weekly-coordinator-checklist)

---

## 1. Weekly Alpha Release

The **Auto Release Alpha** workflow, defined by
[`auto_release_alpha.yml`](../.github/workflows/auto_release_alpha.yml), fires automatically every
**Tuesday at 03:30 UTC**. It finds the latest passing commit on `develop`, tags it as
`latest-alpha`, and dispatches **Build and Sign**. The coordinator's job starts at the approval
gate.

### Steps

- [ ] **Approve the build** — Navigate to Actions → **Build and Sign** run → approve in the
`oppia-android-release-env` gate.
- [ ] **Copy the GCS path** — After the build completes, copy the signed AAB path from the job
Comment thread
adhiamboperes marked this conversation as resolved.
summary (format: `gs://oppia-android-alpha-releases/…/*.aab`), which will be used for the
deployment steps.
- [ ] **Distribute to QA** — Trigger **Deploy to Firebase** (`deploy_to_firebase.yml`) with the
GCS path above and approve the run in the `oppia-android-release-env` gate.
- [ ] **Await QA sign-off** — Notify the alpha tester group and wait for their confirmation that
the alpha build is stable and ready for Play Store deployment.
- [ ] **Deploy to Play Console** — After QA sign-off, trigger **Deploy to Play Console**
(`deploy_to_play_console.yml`) with `track=alpha` and `rollout_fraction=1000` (100% of the
alpha track). The Firebase and Play Console deployments are sequential: QA on Firebase is
completed first, then the approved build is pushed to the alpha track:

![Deploy to Play Console dispatch dialog](https://github.com/user-attachments/assets/76b3dbbd-eede-4a1c-a359-8751d08b304e)

> If **Auto Release Alpha** exits with an error or finds no passing commit, see the
> [In-Depth Release Reference](In-Depth-Release-Reference.md) for manual fallback steps.

---

## 2. Changelog Review

The **Generate Changelogs** workflow

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this is supposed to trigger when version.bzl is updated, but when does that latter event happen? Can you explain?

Also, is the release coordinator ever supposed to run this manually? If so, in what circumstances? Please explain.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

version.bzl is bumped by the RC at the start of each release cycle as part of the pre-release step in §3 that push triggers Generate Changelogs automatically. The manual workflow_dispatch option exists for cases where the auto-trigger didn't fire or the changelog needs to be regenerated after corrections. Updated the §2 intro to explain both triggers.

([`generate_changelog.yml`](../.github/workflows/generate_changelog.yml)) opens a PR to
`develop` automatically when `version.bzl` is updated with a new `MINOR_VERSION`. This update
happens at the start of each release cycle when the RC bumps `MINOR_VERSION` as part of the
pre-release step in §3. The workflow can also be triggered manually via `workflow_dispatch` if
the auto-trigger did not fire (e.g. the version bump happened without triggering CI) or if the
changelog needs to be regenerated after corrections.

### Steps

- [ ] Review the AI-generated release notes in `config/changelogs/{version}.md` (and any
flavor-specific overrides such as `{version}_alpha.md` or `{version}_beta.md`).
- [ ] Edit the release notes if the AI summary needs adjustment before merging.
- [ ] Merge the changelog PR into `develop`. Merging automatically triggers **Deploy Updated
Changelog** (`deploy_updated_changelog.yml`), which uploads the release notes to Play Console.

---

## 3. Production Release

Follow this checklist for a full beta or production (GA) release.

### Pre-release

- [ ] Bump `MINOR_VERSION` in `version.bzl`. This push triggers **Generate Changelogs**

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link "Generate Changelogs" to the section above. Ditto below.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

automatically.
- [ ] Review and merge the changelog PR opened by **Generate Changelogs** (§2). **Do not cut
the release branch until this PR is merged** — the release branch must include the correct
version number and changelog.
- [ ] Cut the release branch from `develop` HEAD:
```
git checkout -b release-0.X upstream/develop
git push upstream release-0.X
```

### Build & sign

- [ ] Trigger **Build and Sign** (`build_and_sign.yml`) with `flavor=beta` or `flavor=ga` and
`source_ref=release-0.X`:

![Build and Sign dispatch dialog](https://github.com/user-attachments/assets/c9119df5-5d3a-459e-bb31-ba3b7683b98b)

- [ ] Approve the run in the `oppia-android-release-env` gate.
- [ ] Copy the signed AAB GCS path from the job summary.

### QA

- [ ] Trigger **Deploy to Firebase** (`deploy_to_firebase.yml`) with the GCS path and approve
the run in the `oppia-android-release-env` gate.
- [ ] Notify QA testers and await sign-off.
- [ ] If critical issues are found during QA: land the fix on `develop`, cherry-pick to
`release-0.X`, then rebuild from Build & sign above.

### Deploy

- [ ] Trigger **Deploy to Play Console** (`deploy_to_play_console.yml`) with `track=beta` or
`track=production` and `rollout_fraction=100` (10% initial rollout — see §4):

![Deploy to Play Console dispatch dialog](https://github.com/user-attachments/assets/a8c27c48-7fe6-48c1-aea6-3c5393b6db9d)

---

## 4. Staged Rollout

After the initial deployment, progressively increase the rollout using `update_rollout.yml`.
Monitor Firebase Crashlytics between each step; halt and investigate if crash rates spike.

| Day | `rollout_fraction` | Actual rollout | Action |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These look like integers rather than "fractions"?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are in permille (thousandths out of 1000), so 100 = 10%, 1000 = 100%. Added a note below the table to clarify the unit.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then shouldn't the name be something like "rollout_permille", not "rollout_fraction"? The integer here is still not a fraction.

@Sandesh282 Sandesh282 Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rollout_fraction is already the established parameter name in update_rollout.yml (the workflow input, job name, and Bazel target are all named accordingly). Keeping the same name in the playbook table makes it easy for release coordinators to directly map the doc to the actual workflow input when triggering a run.

PS: The note directly below the table already clarifies the permille semantics: "rollout_fraction is specified in permille (thousandths out of 1000) as required by the Play Console API — 100 means 10%, 1000 means 100%."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I am actually suggesting that that name is misleading throughout and should be changed, not just here, but in the workflows. This should probably have been caught during earlier review.

If a variable does not actually represent a fraction, it should not be called a fraction.

Could you please look into this? Is there an external constraint that forces us to keep the incorrect naming?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2026-09-02 at 15 54 01

I understand. I had already added a sentence with an example explaining what the number represents. I think this makes values like 1000 or 100 less ambiguous, since readers can refer to the example to understand what the value means.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sandesh282 We are talking about two different things here. The message for the users of the feature is good, but the problem I am discussing is the name of the variable in the code, which I still think should be fixed to reflect the type of value that it stores.

@adhiamboperes adhiamboperes Sep 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sandesh282, after further consideration, rollout_fraction is misleading for the value this code stores. Sean’s distinction is correct. Documenting the conversion helps coordinators, but the variable name should also communicate its unit.

val fraction = rolloutFraction / 1000.0
val status = if (rolloutFraction >= 1000) "completed" else "inProgress"
divides rolloutFraction by 1000.0 before assigning the result to userFraction.

I recommend:

  • rollout_permille for workflow inputs.
  • rolloutPermille for Kotlin integer parameters and properties.
  • Keep userFraction for the API models, where it correctly represents a decimal fraction.

This is mostly a mechanical refactor. My search found 20 files containing the affected naming:
Workflows
.github/workflows/deploy_to_play_console.yml
.github/workflows/update_rollout.yml

Implementation
PlayConsoleClient.kt
GooglePlayConsoleClient.kt
FakePlayConsoleClient.kt
PendingReleaseChecker.kt
UpdateRolloutFraction.kt - rename to UpdateRolloutPermille.kt
UploadBinaryToPlayConsole.kt
UploadChangelogToPlayConsole.kt
FrozenReleaseConfig.kt - documentation reference only

Tests
FakePlayConsoleClientTest.kt
GooglePlayConsoleClientTest.kt
PendingReleaseCheckerTest.kt
UpdateRolloutFractionTest.kt - rename to UpdateRolloutPermilleTest.kt
UploadBinaryToPlayConsoleTest.kt
UploadChangelogToPlayConsoleTest.kt

Build definitions
scripts/BUILD.bazel
scripts/release/BUILD.bazel
javatests/scripts/release/BUILD.bazel

Documentation
wiki/Release-Playbook.md ln128: permille is our implementation choice, not an API requirement. It provides 0.1-percentage-point increments using integers; it does not represent every possible API decimal.

This is about 20 files total. You can change those in this PR.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc/ @seanlip.

|---|---|---|---|
| 0 | `100` | 10% | Initial deploy via **Deploy to Play Console** |
| 1 | `250` | 25% | Trigger **Update Rollout** after monitoring |
| 3 | `500` | 50% | Trigger **Update Rollout** |
| 7+ | `1000` | 100% | Trigger **Update Rollout** for full rollout |

> `rollout_fraction` is specified in **permille** (thousandths out of 1000) as required by the
> Play Console API — `100` means 10%, `1000` means 100%.

**Inputs for `update_rollout.yml`:**

| Input | Value |
|---|---|
| `track` | `beta` or `production` |
| `version` | e.g. `0.18` |
| `rollout_fraction` | New fraction from the table above |

---

## 5. Weekly Coordinator Checklist

Run through this checklist each week:

- [ ] Check whether **Auto Release Alpha** completed successfully on Tuesday. If not,
consult the [In-Depth Release Reference](In-Depth-Release-Reference.md).
- [ ] Check whether **Pull Latest Lesson Versions** opened a PR on Monday. If so, review
and merge the lesson-versions PR.
- [ ] Check for any pending changelog PRs opened by **Generate Changelogs** and merge them.
- [ ] Review crash rates in Firebase Crashlytics and advance the rollout fraction if stable
(see §4).

---
Loading