ci(refactor-release): automate release preparation and backports - #12823
ci(refactor-release): automate release preparation and backports#12823DariuszPorowski wants to merge 7 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements the “PR 12” phase of the GoReleaser release-lifecycle plan by introducing automated release preparation (version policy + deterministic generated artifacts) and serialized, label-driven backports, with validation workflows to ensure generated plans/metadata are trustworthy and reproducible.
Changes:
- Add
prepare-release,release-plan,release-backport, andrelease-branch-commitsworkflows plus supporting scripts/tests for deterministic release PR generation, plan validation, and backport automation. - Switch release publishing to always use prepared release notes files (including RCs), removing the prior PR-comment-generated notes path.
- Update release documentation/templates and register new focused test targets in
make test.
Reviewed changes
Copilot reviewed 28 out of 28 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| docs/release-notes/template_patch.md | Updates patch release-note template wording and keeps generated changelog marker. |
| docs/release-notes/README.md | Updates release-notes guidance to reflect Prepare Release + git-cliff generation and tag-based filenames. |
| docs/contributing/contributing-releases/README.md | Updates maintainer runbook for automated preparation/backports and adds break-glass manual path. |
| cliff.toml | Minor formatting change to postprocessors definition. |
| build/test.mk | Adds/stitches new PR12 test targets into aggregate test target. |
| .github/workflows/release.yaml | Removes PR-time generated release-note comment workflow path (push-only release trigger remains). |
| .github/workflows/release-plan.yaml | Adds pull_request_target + merge_group validation of generated release plans and regenerated artifacts. |
| .github/workflows/release-branch-commits.yaml | Adds pull_request_target validator for Conventional Commits + backport base/source markers on release-branch PRs. |
| .github/workflows/release-backport.yaml | Adds serialized, label-driven backport automation with App-signed commits and conflict handoff behavior. |
| .github/workflows/prepare-release.yaml | Adds workflow_dispatch release preparation that generates release PRs, artifacts, and plans via fixed policy. |
| .github/workflows/__publish-release.yaml | Publishes both RC and stable GitHub Releases using prepared docs/release-notes/ files (no auto-generated notes). |
| .github/scripts/verify-deployment-engine-tag.sh | Verifies a signed annotated Deployment Engine tag exists and is signature-verified before preparation proceeds. |
| .github/scripts/verify-deployment-engine-tag_test.sh | Adds unit tests for Deployment Engine tag verification script behavior and error messaging. |
| .github/scripts/validate-release-plan.sh | Adds trusted-regeneration validator for generated release plans + versions/changelog/notes contracts. |
| .github/scripts/validate-release-plan_test.sh | Adds fixture tests covering acceptance and rejection cases for release plan validation. |
| .github/scripts/validate-release-merge-group.sh | Adds merge-group selector/validator to ensure queued merge groups match exactly one release PR’s release-metadata tree. |
| .github/scripts/validate-release-merge-group_test.sh | Adds fixture tests for merge-group validation scenarios (release-only, batched rejection, etc.). |
| .github/scripts/validate-conventional-commits.mjs | Adds Conventional Commit validation plus generated-backport marker/trailer enforcement helpers. |
| .github/scripts/validate-conventional-commits_test.mjs | Adds node:test coverage for Conventional Commit validation and marker/trailer enforcement. |
| .github/scripts/select-release-backports.mjs | Implements backport selection/serialization logic and parsing of release-plan expected base. |
| .github/scripts/select-release-backports_test.mjs | Adds node:test coverage for serialized backport selection behavior. |
| .github/scripts/preserve-release-note-sections.sh | Preserves curated sections (Highlights/Upgrading) across regenerated release-note runs. |
| .github/scripts/prepare-release.sh | Core generator: computes version by policy, validates backports, renders git-cliff output, updates versions/changelog/notes, writes plan + PR metadata. |
| .github/scripts/prepare-release_test.sh | Adds bash fixtures covering version policy, regeneration behavior, prepared-notes publishing usage, and backport gating. |
| .github/scripts/create-release-backport.sh | Builds a backport branch (or conflict handoff) pinned to the release base and emits PR/commit metadata. |
| .github/scripts/create-release-backport_test.sh | Adds fixtures validating successful backport staging, conflict handoff safety, and stale-base rejection. |
| .github/scripts/collect-release-backports.sh | Collects labeled/explicit backport sources and correlates them with existing release-branch PRs + exact -x trailers. |
| .github/scripts/collect-release-backports_test.sh | Adds fixtures for collecting labeled+explicit PRs and rejecting invalid explicit PRs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| recovery="git tag -s ${TAG} -m 'release tag ${TAG}'" | ||
| recovery+=" && git push origin ${TAG}" |
4072990 to
5982a7f
Compare
5982a7f to
2ba1103
Compare
|
This PR requires exactly 1 of the following labels: pr:standard, pr:important. Label descriptions:
@DariuszPorowski, please add the appropriate label to this PR before merging. |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
Unit Tests 2 files 461 suites 7m 26s ⏱️ Results for commit e5263ef. ♻️ This comment has been updated with latest results. |
2ba1103 to
a70729a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dp/dotted-rc-identifiers #12823 +/- ##
===========================================================
Coverage ? 59.81%
===========================================================
Files ? 779
Lines ? 46058
Branches ? 0
===========================================================
Hits ? 27551
Misses ? 18507
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Functional Tests - upgrade-noncloud1 tests 0 ✅ 5m 5s ⏱️ For more details on these failures, see this check. Results for commit e5263ef. ♻️ This comment has been updated with latest results. |
a70729a to
1c6fccc
Compare
Apply the fixed Radius version policy, render canonical changelog and release notes, and open signed release pull requests with a validated structured plan. Create backports serially per release channel, preserve source commit metadata, and fail closed on conflicts, stale bases, merge-queue drift, or incomplete backports. Refs: #12814 Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
prepare-release.sh sourced release-version.sh but never called it, and re-implemented the version policy inline five times. Two of those copies disagreed: the final-release check accepted -rc.0 while highest_rc_number only ever counted -rc.1 and above, so a versions.yaml pinned to an out-of-policy RC could be promoted to a final release. Build the channel-scoped RC and patch patterns from the shared RADIUS_RC_NUMBER and RADIUS_SEMVER_NUMBER constants, and route the stable tag checks through is_radius_release_version so the policy has one home. Align the canonical gates in validate-release-plan.sh and verify-deployment-engine-tag.sh with the same rule, which rejects the leading zeros that semver forbids. Add a regression test covering the -rc.0 promotion path. Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
The action cherry-picks with -x and detects the merge method, which fits this design, but it commits and pushes with git. Backport commits could then only be signed by introducing a bot GPG key, and this job instead asserts that the release App produced a verified commit through the API. It also opens every labelled backport at once against the current branch head rather than serialising one per channel, and its conflict mode commits conflict markers that the completion check rejects. Record the evaluation next to the job and in the implementation plan so the question is not reopened without the constraints, and name the condition that would change the answer. Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
collect-release-backports.sh matched the source marker with contains(), while select-release-backports.mjs requires exactly one marker and skips an ambiguous body. Both encode the same completion contract, so a body naming two sources was read differently depending on which consumer ran. Require a single marker in the collector too. The exact -x trailer check already prevented a wrong release decision, so this closes a divergence rather than a live bug, but it leaves one reading of the contract instead of two. Record the script language boundary in the implementation plan: GitHub API work belongs in actions/github-script ESM modules, local git and artifact work stays in shell, and neither choice affects signing. Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
The backport pull request set sign-commits, which makes the action ignore the committer and author inputs entirely. The committer line was already dead config, and the author fell back to github.actor - the person who labelled the PR or pushed to the release branch, not the contributor whose change is being backported. GitHub only verifies a bot signature when the request carries no custom author, so author preservation and bot signing cannot both apply. The release/* ruleset settles it: it requires no signatures and permits only rebase merges, which add commits to the base branch without signature verification. The signature was going to be discarded when the backport landed, while the author survives the rebase. Capture the source commit author and pass it through, keep the release App as committer, and drop sign-commits. The conflict placeholder is the bot's own commit, so it keeps the bot as author and its signoff matches. A real backport carries the source commit body, including the original Signed-off-by, so DCO still matches its author. Replace the signature assertion with an authorship assertion, since that is the property that now reaches the release branch. Prepare Release is the opposite case and is unchanged: its commits have no human author and target main, which requires signatures and squash merges, so bot signing both applies and survives. Correct the backport-action comparison, which credited API-signed commits that this path no longer relies on. Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
Signed-off-by: Dariusz Porowski <3431813+DariuszPorowski@users.noreply.github.com>
1c6fccc to
e5263ef
Compare
Radius functional test overviewClick here to see the test run details
Test Status⌛ Building Radius and pushing container images for functional tests... |
Functional Tests - corerp-noncloud190 tests ±0 186 ✅ ±0 1h 15m 18s ⏱️ + 13m 19s For more details on these failures, see this check. Results for commit e5263ef. ± Comparison against base commit 6848ff9. |
Summary
Automates PR 12 of the GoReleaser release-lifecycle plan:
prepare-releaseworkflow that applies the fixed RC/final/patch version policy, renders the canonical changelog and release notes, updatesversions.yaml, records a structured release plan, and opens an App-signed release PR;-xtraceability, signed commits, conflict handoff, and stale-base protection;This is PR 12 in stack #12738 and is based on #12793.
Reason for change
Release preparation currently requires manual version editing, changelog/release-note assembly, and commit discovery/cherry-picking. The design requires a reviewable release plan, deterministic version policy, canonical git-cliff output, and safe label-driven backports before the later release-controller cutover.
Fixes #12814
How to test
Focused and neighboring release suites:
The PR12 Bash fixtures also pass under Windows Git Bash. Additional validation completed:
actionlint -shellcheck=on every added or changed workflowshfmtprofile on every new Bash filemarkdownlint-cli2andmarkdown-table-formatter --checkgit diff --checkv0.61.0-rc.1, followed by independent trusted regeneration of the plan,versions.yaml,CHANGELOG.md, and prepared notesmainbase and batched-change rejectionPost-merge acceptance still requires one live RC, one final, and one label-driven backport, as specified by #12814.
File change summary
.github/workflows/prepare-release.yaml.github/workflows/release-backport.yaml.github/workflows/release-plan.yaml.github/workflows/release-branch-commits.yaml.github/scripts/*release*,.github/scripts/*backport*.github/workflows/release.yaml,.github/workflows/__publish-release.yamlbuild/test.mkdocs/contributing/contributing-releases/README.md,docs/release-notes/Post-merge setup
Validate release planonmain.Validate release branch commitsonrelease/*with branches required to be up to date before merge.radius.