Releasing¶
The step-by-step release runbook. For the why and the shape of the branch flow, see Branching & releases; this page is the exact steps.
Run pnpm run cut-release -- X.Y.Z. The rest is automatic. You can also cut a release from
GitHub Actions by running Cut Release on the develop branch with the same X.Y.Z
version.
Normal release flow¶
- Make sure the intended changes are merged to
develop. - From a clean checkout at the latest
origin/develop, run:
- Review the generated
release/X.Y.Z->mainPR. - Merge the release PR to
mainwith a merge commit. - Let the Back Merge Main to Develop workflow open or update
sync/main-to-develop. - Merge the sync PR to
developwith a merge commit.
Releases are cut from develop, never from main, so the release branch is grounded in the
same state that was tested on staging. The post-release sync must be a real merge commit so
release commits propagate back to develop and the branches do not silently diverge.
Incident context: PR #976.
GitHub Actions entry point¶
Use Actions -> Cut Release -> Run workflow on develop. Inputs:
version: semver without a build suffix, for example1.1.13.dry_run: validates and prints the planned branch, version bump and PR without pushing anything.
The workflow wraps scripts/cut-release.ts, configures the GitHub Actions bot identity, and
creates the same release PR as the local script.
Versioning¶
Release versions use semver: MAJOR.MINOR.PATCH. The version of record lives in both Flutter
app pubspecs, which the release script writes as <version>+1:
apps/perci-platform-members/pubspec.yamlapps/perci-platform-clinicians/pubspec.yaml
The +1 build number is intentionally stable for web releases. The release version must be
strictly greater than the version currently on main; the release guard rejects downgrades
and stale version bumps.
QA fixes¶
During QA, fixes land on develop first. Forward-port the same fix to the open
release/X.Y.Z branch so the release contains the reviewed change and develop stays the
source of truth.
Hotfixes¶
Use a hotfix when a fix must reach production before the next normal release. The rules for
main PRs (branch prefix, version bump) are in
Branching & releases.
For urgent production incidents:
- Branch from
mainashotfix/PPL-NNNN. - Keep the fix minimal.
- Open a PR to
main. - Merge with a merge commit after review and required checks pass.
- Let the automatic
sync/main-to-developPR carry the hotfix back todevelop.
For non-urgent hotfixes, prefer fixing develop first:
- Branch from
developand merge the fix todevelopthrough the normal PR path. - Branch from
mainashotfix/PPL-NNNN. - Cherry-pick the minimal fix commit from
developonto the hotfix branch. - Open the hotfix PR to
mainand merge it with a merge commit. - Let the automatic
sync/main-to-developPR reconcile the production merge back todevelop.
Before cherry-picking from develop, check the fix does not depend on unreleased
develop-only changes. If it does, make a smaller hotfix directly from main instead.
Required repository settings¶
main keeps its protections and requires:
- Pull requests; no direct pushes.
- Required status check: Release PR Guard.
- Merge commits allowed for
release/*,hotfix/*and sync PRs. - Squash remains the default for ordinary PRs to
develop. - PRs to
mainmust come fromrelease/*,hotfix/*orsync/main-to-develop*. The versioned enforcement lives inscripts/release-pr-guard.ts; if GitHub branch rulesets are available, mirror the same source-branch allow-list in themainruleset.
Troubleshooting¶
release must be cut from the exact origin/develop commit¶
version must be greater¶
Pick the next semver above the version currently on both app pubspecs. Do not reuse a version that has already shipped.
PR branch appears to be grounded in main¶
Close the bad release PR and re-run pnpm run cut-release -- X.Y.Z from the latest
origin/develop.
.gitignore files were added¶
Remove generated build output from the release branch. Common examples are Flutter Linux
generated files under apps/*/linux/**, .dart_tool, and build/.
mcp/*/package-lock.json¶
Remove the npm lockfile. MCP packages use pnpm, and the root pnpm-lock.yaml is the
lockfile source of truth.
Back-merge PR has conflicts¶
Check out sync/main-to-develop, merge origin/main, resolve conflicts, then push the
branch. Keep the PR as a merge commit into develop.