Skip to content

ci(refactor-release): automate release preparation and backports - #12823

Draft
DariuszPorowski wants to merge 7 commits into
dp/dotted-rc-identifiersfrom
dp/prepare-release-backports
Draft

ci(refactor-release): automate release preparation and backports#12823
DariuszPorowski wants to merge 7 commits into
dp/dotted-rc-identifiersfrom
dp/prepare-release-backports

Conversation

@DariuszPorowski

@DariuszPorowski DariuszPorowski commented Aug 25, 2026

Copy link
Copy Markdown
Member

Summary

Automates PR 12 of the GoReleaser release-lifecycle plan:

  • adds a prepare-release workflow that applies the fixed RC/final/patch version policy, renders the canonical changelog and release notes, updates versions.yaml, records a structured release plan, and opens an App-signed release PR;
  • adds label-driven, one-at-a-time backports per release channel with exact -x traceability, signed commits, conflict handoff, and stale-base protection;
  • validates generated plans and release metadata through trusted regeneration on pull requests and squash merge groups;
  • validates Conventional Commit history, source/base markers, and exact source trailers on release-branch PRs;
  • removes the superseded GitHub-generated release-note comment path and publishes prepared notes for RCs as well as stable releases;
  • updates the maintainer runbook while retaining a temporary break-glass path through phase 18.

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:

make test-prepare-release
make test-release-plan
make test-release-backport
make test-release-branch-commits
make test-changelog-range
make test-release-get-version
make test-release-tag-and-branch
make test-release-version-format
make test-monitor-remote-workflow

The PR12 Bash fixtures also pass under Windows Git Bash. Additional validation completed:

  • actionlint -shellcheck= on every added or changed workflow
  • ShellCheck and repository shfmt profile on every new Bash file
  • markdownlint-cli2 and markdown-table-formatter --check
  • git diff --check
  • real-history dry run for v0.61.0-rc.1, followed by independent trusted regeneration of the plan, versions.yaml, CHANGELOG.md, and prepared notes
  • squash-shaped merge-group fixtures, including an advanced main base and batched-change rejection
  • two-backport serialized progression and conflict recovery from a stale single-branch clone

Post-merge acceptance still requires one live RC, one final, and one label-driven backport, as specified by #12814.

File change summary

File Summary of change
.github/workflows/prepare-release.yaml Prepares and updates App-signed release PRs from the fixed version policy.
.github/workflows/release-backport.yaml Creates serialized, label-driven release-branch backports and conflict handoffs.
.github/workflows/release-plan.yaml Regenerates and validates plans and generated files on PRs and merge groups.
.github/workflows/release-branch-commits.yaml Enforces Conventional Commits, immutable base/source markers, and exact trailers.
.github/scripts/*release*, .github/scripts/*backport* Implements versioning, generation, plan validation, backport selection, and focused fixtures.
.github/workflows/release.yaml, .github/workflows/__publish-release.yaml Removes superseded PR comments and uses prepared notes for every release type.
build/test.mk Registers PR12 tests in the aggregate test target.
docs/contributing/contributing-releases/README.md, docs/release-notes/ Documents automated preparation/backports and the temporary break-glass flow.

Post-merge setup

  • Require Validate release plan on main.
  • Require Validate release branch commits on release/* with branches required to be up to date before merge.
  • Keep generated release PRs isolated in one-PR merge groups.
  • Confirm the release App has Contents, Issues, and Pull requests write access on radius.
  • Create the signed annotated Deployment Engine tag before each Prepare Release run until the upstream signing dependency is resolved.

@DariuszPorowski
DariuszPorowski requested review from a team as code owners August 25, 2026 05:32
Copilot AI lite review requested due to automatic review settings August 25, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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, and release-branch-commits workflows 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.

Comment on lines +39 to +40
recovery="git tag -s ${TAG} -m 'release tag ${TAG}'"
recovery+=" && git push origin ${TAG}"
@github-actions

Copy link
Copy Markdown

This PR requires exactly 1 of the following labels: pr:standard, pr:important.
Currently applied labels: .

Label descriptions:

  • pr:important - Major features, breaking changes, deprecations, or other high-impact changes that need special attention during release.
  • pr:standard - Ongoing maintenance, minor improvements, documentation updates, and routine development work.

@DariuszPorowski, please add the appropriate label to this PR before merging.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

PackageVersionScoreDetails
actions/actions/checkout 3d3c42e5aac5ba805825da76410c181273ba90b1 🟢 7
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Maintained🟢 1024 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10
Binary-Artifacts🟢 10no binaries found in the repo
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions⚠️ 0detected GitHub workflow tokens with excessive permissions
Packaging⚠️ -1packaging workflow not detected
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies⚠️ 3dependency not pinned by hash detected -- score normalized to 3
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 6branch protection is not maximal on development and all release branches
actions/actions/github-script 3a2844b7e9c422d3c10d287c895573f7108da1b3 🟢 6.7
Details
CheckScoreReason
Code-Review🟢 10all changesets reviewed
Packaging⚠️ -1packaging workflow not detected
Binary-Artifacts🟢 10no binaries found in the repo
Maintained⚠️ 00 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Token-Permissions🟢 9detected GitHub workflow tokens with excessive permissions
Pinned-Dependencies⚠️ 1dependency not pinned by hash detected -- score normalized to 1
Fuzzing⚠️ 0project is not fuzzed
License🟢 10license file detected
Signed-Releases⚠️ -1no releases found
Security-Policy🟢 9security policy file detected
SAST🟢 10SAST tool is run on all commits
Branch-Protection🟢 6branch protection is not maximal on development and all release branches

Scanned Files

  • .github/workflows/release-plan.yaml
  • .github/workflows/release.yaml

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Unit Tests

    2 files    461 suites   7m 26s ⏱️
6 532 tests 6 530 ✅ 2 💤 0 ❌
7 808 runs  7 806 ✅ 2 💤 0 ❌

Results for commit e5263ef.

♻️ This comment has been updated with latest results.

@DariuszPorowski
DariuszPorowski force-pushed the dp/prepare-release-backports branch from 2ba1103 to a70729a Compare August 28, 2026 16:54
@codecov

codecov Bot commented Aug 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (dp/dotted-rc-identifiers@6848ff9). Learn more about missing BASE report.

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

Functional Tests - upgrade-noncloud

1 tests   0 ✅  5m 5s ⏱️
1 suites  0 💤
1 files    1 ❌

For more details on these failures, see this check.

Results for commit e5263ef.

♻️ This comment has been updated with latest results.

@DariuszPorowski
DariuszPorowski force-pushed the dp/prepare-release-backports branch from a70729a to 1c6fccc Compare August 28, 2026 20:07
@DariuszPorowski DariuszPorowski changed the title ci: automate release preparation and backports ci(refactor-release): automate release preparation and backports Aug 28, 2026
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>
@DariuszPorowski
DariuszPorowski force-pushed the dp/prepare-release-backports branch from 1c6fccc to e5263ef Compare September 3, 2026 16:22
@radius-functional-tests

radius-functional-tests Bot commented Sep 3, 2026

Copy link
Copy Markdown

Radius functional test overview

🔍 Go to test action run

Click here to see the test run details
Name Value
Repository radius-project/radius
Commit ref e5263ef
Unique ID funccd49f0568f
Image tag pr-funccd49f0568f
  • Dapr: 1.14.4
  • Azure KeyVault CSI driver: 1.4.2
  • Azure Workload identity webhook: 1.3.0
  • Bicep recipe location ghcr.io/radius-project/dev/test/testrecipes/test-bicep-recipes/<name>:pr-funccd49f0568f
  • Terraform recipe location http://tf-module-server.radius-test-tf-module-server.svc.cluster.local/<name>.zip (in cluster)
  • applications-rp test image location: ghcr.io/radius-project/dev/applications-rp:pr-funccd49f0568f
  • dynamic-rp test image location: ghcr.io/radius-project/dev/dynamic-rp:pr-funccd49f0568f
  • controller test image location: ghcr.io/radius-project/dev/controller:pr-funccd49f0568f
  • ucp test image location: ghcr.io/radius-project/dev/ucpd:pr-funccd49f0568f
  • deployment-engine test image location: ghcr.io/radius-project/deployment-engine:latest

Test Status

⌛ Building Radius and pushing container images for functional tests...
✅ Container images build succeeded
⌛ Publishing Bicep Recipes for functional tests...
✅ Recipe publishing succeeded
⌛ Starting ucp-cloud functional tests...
⌛ Starting corerp-cloud functional tests...
✅ ucp-cloud functional tests succeeded
✅ corerp-cloud functional tests succeeded

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

Functional Tests - corerp-noncloud

190 tests  ±0   186 ✅ ±0   1h 15m 18s ⏱️ + 13m 19s
  3 suites ±0     2 💤 ±0 
  1 files   ±0     2 ❌ ±0 

For more details on these failures, see this check.

Results for commit e5263ef. ± Comparison against base commit 6848ff9.

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.

Automate release preparation and backports

2 participants