This project uses CalVer (YYYY.M.patch) for versioning. Releases are fully automated via a release PR model: changes land on main, a PR is kept up to date reflecting the pending release, and merging that PR triggers the actual release.
| Component | Format | Example |
|---|---|---|
| Version name | YYYY.M.patch |
2026.5.2 |
| Build number | YYYYMMDDPP (date * 100 + patch) |
2026050902 |
| pubspec.yaml | version: YYYY.M.patch+YYYYMMDDPP |
2026.5.2+2026050902 |
| Git tag | vYYYY.M.patch |
v2026.5.2 |
Patch number resets to 0 each month. Increment for each release within a month (2026.5.0, 2026.5.1, …).
Every push to main (and a daily cron at 06:00 UTC) triggers release-pr.yml, which:
- Computes the next version by inspecting existing
v*tags for the current month - Runs git-cliff to generate a changelog from unreleased commits
- Updates
pubspec.yamlwith the new version - Prepends the new section to
CHANGELOG.md - Opens or force-updates a PR from
release/next→maintitledRelease X.Y.Z
The PR is skipped if there are no releasable commits (i.e. only chore/ci/test changes since the last tag).
Note — CI on the release PR: GitHub does not trigger workflow runs on PRs created by
GITHUB_TOKEN, so the usual test/analysis checks will not run onrelease/next. This is acceptable because the shipped code is identical to what already passed CI onmain; onlypubspec.yaml(version bump) andCHANGELOG.md(generated text) differ. If you want CI to run, supply a PAT assecrets.RELEASE_TOKENand pass it viatoken:in thecreate-pull-requeststep.
Note — Android versionCode uniqueness: The
+YYYYMMDDPPbuild suffix inpubspec.yamlis computed asdate * 100 + patch, so multiple releases on the same day still get unique Play Store version codes.
Inspect the auto-generated changelog in the PR body. Add context to the body if helpful, then merge when ready to ship.
Merging the release PR triggers release.yml, which:
- Reads the version from
pubspec.yaml(source of truth) - Creates and pushes the git tag (e.g.
v2026.5.5) - Creates a GitHub Release with the changelog for that version
- Explicitly triggers the deployment workflows via
workflow_dispatch
| Workflow | Action |
|---|---|
release-web.yml |
Builds and deploys web app to cambeerfestival.app |
release-android.yml |
Builds signed APK/AAB, attaches artifacts to the GitHub Release, uploads to Google Play Internal track |
Monitor progress in the Actions tab.
Why
workflow_dispatchand notrelease: published? GitHub does not fire workflow triggers in response to events created byGITHUB_TOKEN. Usinggh workflow runsidesteps this limitation without requiring a PAT.
git-cliff reads conventional commit messages since the last tag. The following types are included:
| Type | Changelog section |
|---|---|
feat |
Features |
fix |
Bug Fixes |
perf |
Performance |
refactor |
Refactoring |
docs |
Documentation |
Types chore, ci, build, style, and test are excluded. Unconventional commits are also excluded.
Branch from the release tag rather than main:
git checkout v2026.5.2
git checkout -b hotfix/fix-description
# fix, commit using conventional commit message
git push origin hotfix/fix-description
# Open a PR targeting main, merge normallyAfter merging to main, the release PR will pick up the fix in the next run and compute the next patch version automatically.
To deploy a hotfix without waiting for the release PR flow, you can trigger the deployment workflows manually from the Actions tab — select Release Web to Cloudflare Pages or Release Android and provide the version tag.
Once the Internal track build is available:
- Open Google Play Console
- Navigate to your app → Internal testing
- Promote to Alpha / Beta / Production as appropriate
Visit cambeerfestival.app and confirm the release is live.
- CI/CD Workflows — full workflow documentation
- GitHub Secrets — secrets required for release workflows