Automated draft releases
A successful merged pull request to main can create a reviewable Android draft release. The pipeline separates untrusted change text, read-only note generation, and the only write-capable publication step so a release is traceable without making it automatic publication.
Version source and transitions
VERSION is the single newline-terminated source of Flutter build name and build number, in MAJOR.MINOR.PATCH+BUILD form. Release Make targets validate it and pass both parts to Flutter without changing tracked files. The version utility rejects malformed, negative, overflowing, or multi-line values before a workflow uses them.
| Path | Selection | Result |
|---|---|---|
| Automatic | Merged PR labeled release:minor | Increment MINOR and BUILD; reset PATCH to zero. |
| Automatic | Any other merged PR | Increment PATCH and BUILD. |
| Manual rebuild | workflow_dispatch | Preserve MAJOR.MINOR.PATCH; increment BUILD only. |
BUILD is a positive, globally increasing value that becomes the Android versionCode and iOS CFBundleVersion, so it is never reset. Semantic releases use immutable annotated tags named vMAJOR.MINOR.PATCH: an automatic release with build name 0.1.2 and build number 42 carries tag v0.1.2, and a rebuild increments only the build number (0.1.2+43) to replace the draft assets without moving that tag.
Automatic flow
Flutter-Analyze-Test-Buildvalidates formatting, analysis, tests, and the documentation site. On amainpush it resolves the merged pull request and builds versioned signed Android APK and AAB artifacts; a direct push validates without producing a release build.Automated Draft Releaseruns only after that workflow succeeds for amainpush. Its gate resolves the PR associated with the exact workflow-run SHA and skips direct pushes and prior release VERSION commits.- The prepare job independently calculates the expected version, downloads artifacts from that exact CI run, and verifies names, metadata, and SHA-256 digests before preserving only verified inputs.
- A separate read-only Claude job receives bounded PR metadata. It uses schema-constrained output, a single permitted file read, and
CLAUDE_CODE_OAUTH_TOKEN; it cannot commit, tag, publish, or receive publication credentials. The validator requires developer Markdown headed with the exact release version and non-empty, plain store text of at most 500 Unicode characters with no control characters. - The write-capable publish job revalidates notes and artifact provenance, commits only
VERSION, creates or verifies the annotated tag, creates or resumes a compatible draft release, and uploads exactly the verified APK and AAB.
The workflow is serialized rather than canceled mid-transaction, and queued runs are never dropped so closely spaced merges each receive a release. Release provenance records the source SHA, PR, workflow run, selected version, and artifact digests; reruns resume only compatible commits, tags, draft releases, and assets. The draft is intentionally left unpublished for a human to inspect the notes and binaries.
Manual rebuild flow
Run Automated Draft Release with workflow_dispatch only when an existing semantic tag and compatible draft release already exist. The rebuild path reads main, computes one BUILD increment, verifies the tag/release contract, creates signed Android artifacts, and records their hashes. Its publish job revalidates the complete transaction, makes (or recognizes on a rerun) the one-file VERSION commit, confirms that the semantic tag never moved, then deterministically replaces the draft's APK and AAB. It refuses published, missing, duplicated, unexpected, or provenance-mismatched assets.
Operator setup
Configure these repository secrets before expecting a main release build to succeed. Names are shown deliberately; values must never be committed, copied into workflow logs, or placed in documentation.
| Secret | Used for |
|---|---|
CLAUDE_CODE_OAUTH_TOKEN | Claude subscription authentication in the isolated read-only release-notes job. Generate locally with claude setup-token, then store the displayed token as this repository secret. |
CIVIQ_RELEASE_API_HOST | Release API-host input used to generate the untracked HTTPS runtime configuration. |
ANDROID_KEYSTORE_BASE64 | Base64-encoded Android release keystore provisioned only in the runner temporary directory. |
ANDROID_STORE_PASSWORD | Android keystore password. |
ANDROID_KEY_ALIAS | Android signing-key alias. |
ANDROID_KEY_PASSWORD | Android signing-key password. |
Install the Claude GitHub App for the repository before using the subscription token. Keep Claude's job at contents: read and pull-requests: read; only publication jobs receive contents: write. The token is generated with claude setup-token; do not use Claude bare mode for this OAuth credential.
Branch protection and token policy
The publication jobs use the ephemeral GITHUB_TOKEN and require contents: write. Repository and branch-protection settings must explicitly permit the GitHub Actions bot to create the one-file VERSION commit on main; normal required checks and review rules still apply. Tag and release creation also require that the repository policy permits the job token's write permission. The workflow never substitutes a personal access token, force-pushes, or bypasses protection.
Fail closed: missing secrets, an unavailable write permission, branch protection rejection, a changed main ref, invalid release notes, a moved tag, incompatible draft state, or an artifact/hash mismatch stops the affected job. It does not create an unsigned release, publish a draft, mutate a tag, or fall back to another credential. Correct the repository configuration or state, then rerun only after verifying the failure cause.
Failure recovery and review
| Failure | Safe operator action |
|---|---|
| Validation or Android prerequisites fail | Fix the failing validation or configure every required secret, then allow a new merged-PR run or explicitly start the appropriate rebuild. Do not treat an unconfigured build as a release. |
| VERSION commit is rejected | Authorize the GitHub Actions bot for the required one-file commit through repository policy. Do not provide an alternate bypass credential; rerun after the rule is corrected. |
| Concurrent main change or incompatible tag/draft | Inspect the recorded SHA, tag target, provenance marker, and assets. Preserve immutable tags; resolve the competing release deliberately rather than forcing an update. |
| Manual rebuild fails after staging | Verify the draft remains compatible and rerun the same workflow run where supported. Convergent checks recognize its prior one-file rebuild commit and avoid a second BUILD increment. |
Before publishing a draft, reviewers should confirm the tag target and VERSION commit, developer and ≤500-character store notes, Android APK/AAB names and checksums, and the release provenance marker. Publishing is a separate human decision.
Documentation process: the project documentation skill was unavailable while this page was added. The house documentation standard was applied directly; this constraint is recorded in the release-automation subtask metadata.