CI/CD Pipeline
Workflow: release.yml
File: .github/workflows/release.yml
Trigger: PR merged to main or manual workflow_dispatch.
Runner: Blacksmith (4vCPU Ubuntu 2404)
Steps
- Checkout (fetch-depth: 0 for tags)
- Setup JDK 17 + Gradle
- Decode keystore from secrets (base64)
- Create keystore.properties, secrets.properties, google-services.json from secrets
- Check for existing draft release (reuse if found)
- Version bump: Read versionName from
app/build.gradle.kts, patch increment (X.Y.Z → X.Y.(Z+1)), write back, commit, tag v1.X.Y - AI release notes: Collect commits since previous tag, call OpenCode with commit history to generate notes, split into full (GitHub) and ≤500 char (Play Store) versions
- Build:
assembleGithubRelease + bundlePlaystoreRelease - Upload AAB to Play Store (alpha track, status: completed)
- Upload APK to GitHub Release (draft, reuse or create)
Secrets required
| Secret | Purpose |
KEYSTORE_FILE_BASE64 | Release keystore (base64 encoded) |
KEYSTORE_PASSWORD | Keystore password |
KEY_ALIAS | Key alias |
KEY_PASSWORD | Key password |
GOOGLE_CLIENT_ID | OAuth web client ID |
PUSH_BACKEND_URL | Cloudflare Workers push relay URL |
GOOGLE_SERVICES_JSON | Firebase google-services.json (base64) |
SERVICE_ACCOUNT_JSON | Play Console service account for upload |
GITHUB_TOKEN | Auto-provided, used for GitHub release |
Release Process
How a release happens
- A PR is merged to
main (or workflow_dispatch is triggered). - CI runs
release.yml. - Version is bumped automatically (patch increment), committed and tagged.
- APK and AAB are built.
- AAB is uploaded to Play Console alpha track.
- APK is uploaded to a draft GitHub Release.
- Release notes are generated by AI from commit messages.
Post-release manual steps
- Go to GitHub Releases.
- Find the new draft release.
- Review and edit release notes if needed.
- Publish the release.
What if a release fails mid-way?
- Fix the issue.
- Push a fix to
main. - Either merge another PR (triggers a new release) or run
workflow_dispatch. - The workflow checks for existing draft releases and reuses them if found.
Version numbering
- Format:
1.X.Y where X is feature/minor and Y is patch. - Patch is auto-incremented by CI on every release.
- Feature/minor bumps are manual edits to
versionName in app/build.gradle.kts.