Skip to content

Build: Add CI-driven release pipeline (release-prepare)#126

Merged
d4rken merged 1 commit into
mainfrom
worktree-release-pipeline
May 30, 2026
Merged

Build: Add CI-driven release pipeline (release-prepare)#126
d4rken merged 1 commit into
mainfrom
worktree-release-pipeline

Conversation

@d4rken
Copy link
Copy Markdown
Member

@d4rken d4rken commented May 30, 2026

What

Ports the CI-driven release pipeline from d4rken-org/capod so releases can be cut and versions bumped entirely from the GitHub Actions UI, replacing the local interactive release.sh.

How it works

  1. Run Release prepare (workflow_dispatch) from main. Inputs:
    • bump_kind: build / patch / minor / major (default patch)
    • version_override: explicit M.m.p-rcN (overrides bump_kind)
    • expected_current: optional safety guard (fail if current version differs)
    • dry_run: default true — computes + validates + prints the plan to the run summary, no mutation
  2. With dry_run=false, job 2 mints a GitHub App token, applies the bump via bump.sh --mode=write, commits Release: <name>, tags v<name>, and atomically pushes commit+tag to main.
  3. The tag push (made with the App token, not GITHUB_TOKEN) re-triggers release-tag.yml, which validates the tag, builds the signed FOSS APK, and publishes the GitHub release.

Changes

  • tools/release/bump.sh (new, executable): non-interactive version bumper, modes check / plan / write. Validates version.propertiesVERSION consistency, enforces 0–99 bounds + no leading zeros, monotonic versionCode, and re-verifies after writing. Mirrors the formula in buildSrc/.../ProjectConfig.kt. Runnable locally.
  • .github/workflows/release-prepare.yml (new): the two-job dispatch flow above, concurrency: release-prepare-main.
  • .github/workflows/release-tag.yml (modified): added validate-tag gate (rc-only tag format + version.properties↔tag match, skipped on branch dry-runs so build-only dry-runs still work), concurrency, fail_on_unmatched_files: true; bumped softprops/action-gh-release to v3.0.0 (Node24-compatible); removed the unreachable -beta build/prerelease steps.
  • version.properties: header comment updated to reference tools/release/bump.sh.
  • release.sh: deleted (replaced by bump.sh).

Design decisions

  • rc-only: version.properties keeps its 4 keys and ProjectConfig.kt (which hardcodes -rc) is left untouched. capod's type/beta-channel switching was intentionally dropped. Legacy -beta0/-beta1 tags in history are intentionally unsupported by the new workflow.
  • Default bump_kind=patch (not capod's build) to match this repo's actual release cadence (all prior releases are -rc0). Override per-run as needed.

⚠️ Operator setup required before first non-dry-run

  • Add repo secrets RELEASE_APP_CLIENT_ID and RELEASE_APP_PRIVATE_KEY for a GitHub App installed on this repo with contents: write (the same App used by capod can be installed here).
  • If main has branch protection, the App must be allowed to bypass it, or the atomic push will be rejected.
  • The existing foss-production environment / signing secrets (SIGNING_KEYSTORE_BASE64, STORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD) are unchanged.

Recovery path (tag pushed but build/release failed)

The model is monotonic and cheap to re-cut. If release-tag.yml fails after the tag exists:

  • Fix the cause and bump forward (run Release prepare again), or
  • Delete the bad tag/release (git push origin :refs/tags/v<name>) and revert the Release: commit on main, then re-run.

No second release is silently published: expected_current + tag-collision checks + validate-tag guard against drift.

Testing

  • bash -n tools/release/bump.sh; YAML of both workflows parses clean.
  • 21 behavior assertions pass: check on the real tree → 0.8.0-rc0/800000; plan for build/patch/minor/major + override; beta/garbage overrides rejected; expected-current match/mismatch; no-op rejected; write against a temp-copied repo root (never the real tree) producing 0.8.1-rc0 801000 + header refresh + clean re-validation; real tree confirmed unchanged.
  • Plan reviewed by Codex (gpt-5.5) and a code-reviewer agent; substantive feedback integrated.

Replace the local interactive release.sh with a GitHub Actions release flow ported from d4rken-org/capod.

- tools/release/bump.sh: non-interactive version bumper (check/plan/write modes) with validation, monotonic versionCode and post-write checks; single source of truth, runnable locally too.

- release-prepare.yml: workflow_dispatch with dry-run preview, then GitHub-App-token commit+tag+atomic-push to main, which re-triggers release-tag.yml.

- release-tag.yml: add validate-tag gate (rc-only format + version.properties<->tag match, skipped on branch dry-runs), concurrency, fail_on_unmatched_files; bump softprops to v3.0.0; drop unreachable beta steps.

rc-only by design: version.properties keeps 4 keys and ProjectConfig.kt is untouched.
@d4rken d4rken merged commit daa9602 into main May 30, 2026
9 checks passed
@d4rken d4rken deleted the worktree-release-pipeline branch May 30, 2026 15:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant