ci: tag-driven release with native GitHub workflows#154
Conversation
Code Review: tagpr + promote-stable PRLogic Test Results ✅Tested the core flow — tag validation, pre-release detection, and promote-stable tag lookup all work correctly.
|
PR Review1. What problem does this solve?The original CI had two pain points:
2. How does it solve it?Tag-driven release flow with the core principle: what you tested is what you ship.
Zero third-party dependencies (only GitHub official actions). GitHub App permissions reduced from 8 to 3. 3. Were alternatives considered?Yes — Songmu/tagpr was implemented (visible in commits 6–10) but ultimately replaced with native GitHub workflows in the final commit by @thepagent. Reason: tagpr has only 292 stars and requires broad repo permissions, posing supply chain risk. 4. Is this the best approach? Issues & suggestionsOverall: solid design. A few things to address:
|
|
All four items addressed in 9e06b1d:
Thanks for the thorough review @chaodu-agent! |
c99ba9d to
2e627ac
Compare
- trigger: push tags v* (instead of push to main with paths filter) - version: parsed from tag (v0.7.0-beta.1 → 0.7.0-beta.1) - docker tags: sha + semver + major.minor + latest (stable only) - bump-chart: version comes directly from tag, no more GITHUB_RUN_NUMBER - workflow_dispatch: kept for manual trigger with explicit tag input
Beta (tag contains '-'): → release-chart-beta: helm package + push to OCI registry → no PR, main branch untouched Stable (tag without '-'): → bump-chart-stable: update Chart.yaml + values.yaml → PR → auto merge → release.yml picks up Chart.yaml change → publish to GitHub Pages + OCI
- Add resolve-tag job: validates tag format, parses chart_version, image_sha, is_beta — single source of truth for all downstream jobs - Fix: workflow_dispatch now uses inputs.tag instead of github.ref_name for beta/stable branching (github.ref_name is branch name, not tag) - Remove 3× duplicated 'Resolve version tag' steps - IMAGE_SHA computed once in resolve-tag, not repeated per job
- build-image + merge-manifests: only run for beta tags - promote-stable: retag existing beta image with stable tags (version, major.minor, latest) using imagetools create - verify beta image exists before promoting — fail fast if not - bump-chart-stable now depends on promote-stable This ensures "what you tested is what you ship" — the stable release uses the exact same image artifact validated during beta.
- Add tagpr.yml with GitHub App token (so tags trigger build.yml) - Simplify build.yml: remove beta/stable two-stage, all tags do full build - Add pre-release support: manual tags like v0.7.0-rc.1 won't overwrite latest - Configure .tagpr to sync Cargo.toml + Chart.yaml version/appVersion - Simplify release.yml: keep chart-releaser + install instructions - Align Cargo.toml and Chart.yaml versions to 0.6.0 - Rewrite RELEASING.md with new tag-driven flow
- Pre-release tag (v0.7.0-rc.1): full build, image tags = sha + version - Stable tag (v0.7.0): promote (re-tag) pre-release image, no rebuild - Verify pre-release image exists before promote, fail if not found - Update RELEASING.md with two-path flow diagram
… SHA - promote-stable uses git tag -l to find latest pre-release tag (e.g. v0.7.0-rc.*) - re-tags pre-release image to stable tags (no rebuild, same artifact) - removes commit SHA dependency — pre-release and stable can be on different commits - natural flow: pre-release first → test → merge Release PR → auto promote
- Remove tagpr.yml and .tagpr (third-party dependency) - Add release-pr.yml: workflow_dispatch with auto/manual version bump - Add tag-on-merge.yml: auto-tag on release PR merge - Update RELEASING.md: document new flow, simplify App permissions
- release-chart: add resolve-tag.result == 'success' to if-condition - release-pr: add rust-toolchain + cargo generate-lockfile for Cargo.lock sync - tag-on-merge: validate version format before pushing tag - build: add default placeholder for workflow_dispatch tag input
2e627ac to
fef071a
Compare
* ci: switch Build & Release to git tag driven flow - trigger: push tags v* (instead of push to main with paths filter) - version: parsed from tag (v0.7.0-beta.1 → 0.7.0-beta.1) - docker tags: sha + semver + major.minor + latest (stable only) - bump-chart: version comes directly from tag, no more GITHUB_RUN_NUMBER - workflow_dispatch: kept for manual trigger with explicit tag input * ci: mark beta chart releases as pre-release * ci: split chart release — beta pushes OCI only, stable opens PR Beta (tag contains '-'): → release-chart-beta: helm package + push to OCI registry → no PR, main branch untouched Stable (tag without '-'): → bump-chart-stable: update Chart.yaml + values.yaml → PR → auto merge → release.yml picks up Chart.yaml change → publish to GitHub Pages + OCI * ci: add resolve-tag job, fix workflow_dispatch bug, deduplicate - Add resolve-tag job: validates tag format, parses chart_version, image_sha, is_beta — single source of truth for all downstream jobs - Fix: workflow_dispatch now uses inputs.tag instead of github.ref_name for beta/stable branching (github.ref_name is branch name, not tag) - Remove 3× duplicated 'Resolve version tag' steps - IMAGE_SHA computed once in resolve-tag, not repeated per job * ci: stable release promotes beta image instead of rebuilding - build-image + merge-manifests: only run for beta tags - promote-stable: retag existing beta image with stable tags (version, major.minor, latest) using imagetools create - verify beta image exists before promoting — fail fast if not - bump-chart-stable now depends on promote-stable This ensures "what you tested is what you ship" — the stable release uses the exact same image artifact validated during beta. * ci: add tagpr workflow and config for automated release PR * ci: pin tagpr action to commit hash and bump checkout to v6 * ci: add tagpr workflow and config for automated release PR - Add tagpr.yml with GitHub App token (so tags trigger build.yml) - Simplify build.yml: remove beta/stable two-stage, all tags do full build - Add pre-release support: manual tags like v0.7.0-rc.1 won't overwrite latest - Configure .tagpr to sync Cargo.toml + Chart.yaml version/appVersion - Simplify release.yml: keep chart-releaser + install instructions - Align Cargo.toml and Chart.yaml versions to 0.6.0 - Rewrite RELEASING.md with new tag-driven flow * ci: add promote-stable to guarantee pre-release = stable image - Pre-release tag (v0.7.0-rc.1): full build, image tags = sha + version - Stable tag (v0.7.0): promote (re-tag) pre-release image, no rebuild - Verify pre-release image exists before promote, fail if not found - Update RELEASING.md with two-path flow diagram * docs: rewrite RELEASING.md with complete release flow and constraints * ci: promote-stable finds pre-release image by version tag, not commit SHA - promote-stable uses git tag -l to find latest pre-release tag (e.g. v0.7.0-rc.*) - re-tags pre-release image to stable tags (no rebuild, same artifact) - removes commit SHA dependency — pre-release and stable can be on different commits - natural flow: pre-release first → test → merge Release PR → auto promote * chore: update openab version to 0.6.0 in Cargo.lock * ci: upgrade tagpr to v1.18.1 and use vPrefix config * ci: replace deprecated app-id with client-id in create-github-app-token * ci: add CI workflow for PR validation on source and Dockerfile changes * docs: add GitHub App permissions to RELEASING.md * ci: replace tagpr with native GitHub workflows - Remove tagpr.yml and .tagpr (third-party dependency) - Add release-pr.yml: workflow_dispatch with auto/manual version bump - Add tag-on-merge.yml: auto-tag on release PR merge - Update RELEASING.md: document new flow, simplify App permissions * ci: address review feedback - release-chart: add resolve-tag.result == 'success' to if-condition - release-pr: add rust-toolchain + cargo generate-lockfile for Cargo.lock sync - tag-on-merge: validate version format before pushing tag - build: add default placeholder for workflow_dispatch tag input * fix: replace map_or with is_some_and to satisfy clippy * chore: use beta instead of rc for pre-release naming --------- Co-authored-by: thepagent <thepagent@users.noreply.github.com>
(Updated and co-authored by @thepagent)
問題
原本的 CI 只有 push-to-main 觸發的 build workflow,沒有:
我們曾考慮使用第三方 action Songmu/tagpr 來自動化 release,但評估後認為其僅 292 stars、需要授予 GitHub App 廣泛的 repo 權限,存在供應鏈風險,因此改用原生 GitHub workflows 實現。
設計
採用 tag-driven release 流程,核心原則:測過什麼就發什麼
零第三方依賴,只使用 GitHub 官方 actions + shell 實現:
實現
ci.ymlrelease-pr.ymltag-on-merge.ymlbuild.ymlrelease.ymlRELEASING.mdGitHub App 權限從 8 項簡化為 3 項(Contents、Metadata、Pull requests)。