chore: automate releases via workflow_dispatch#1246
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Automates the Mercure release process: a thin release.sh validates preconditions and dispatches a new release.yml workflow that bumps the Caddy module + Helm chart, regenerates docs, commits/tags via the GitHub API (server-signed under github-actions[bot]), and triggers the downstream cd.yml build. The workflow is designed to be idempotent so partial failures can be resumed.
Changes:
- Add
.github/workflows/release.ymlperforming version bump, helm-docs regeneration, API-based commit and tagging, and downstreamcd.ymldispatch. - Replace
release.shwith a small dispatcher that retains operator-side semver/branch/tree/in-sync guards and callsgh workflow run.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
.github/workflows/release.yml |
New end-to-end release workflow with resume detection, API-based tree/commit/tag creation, and downstream build dispatch. |
release.sh |
Shrunk to a pre-flight checker and gh workflow run dispatcher; drops the previous local bump/tag/push pipeline. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This was referenced May 16, 2026
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 16, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Use matching-refs in create_tag so transient API failures aren't read as "tag absent". - Build the release tree from `git status` partitions so additions, deletions, and modifications round-trip correctly. - Clarify the "no file changes" error with operator guidance. - Check that git is installed in release.sh.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 16, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Verify the resumed commit actually contains the expected caddy/go.mod frankenphp pin and a non-trivial PGO profile before re-tagging or dispatching downstream builds. - Use --no-renames so renames decompose into add+delete and both halves land in the API tree mutation. - Preserve each file's existing mode (executable bit) when building tree entries instead of hardcoding 100644. - Scope the concurrency group per version so a pending environment approval doesn't block dispatches for a different version.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 16, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Match the frankenphp require entry in caddy/go.mod under both block and single-line forms so a future `go mod tidy` reformat doesn't fail the resume verification. - Detect a release-shaped main HEAD without tags as resumable, covering the case where a previous run pushed the commit but failed before create_tag. - Guard against main advancing between checkout and the commit step by asserting parent_sha equals the original checkout SHA before building the API tree. - release.sh: restore set -o errtrace so the ERR trap fires inside any future helpers, and fetch tags so the operator sees existing release tags before dispatching.
Replace the local release.sh logic with a Release workflow that bumps the Caddy module and Helm chart, regenerates chart docs, commits and tags via the GitHub API (server-signed under github-actions[bot]), and dispatches cd.yml against the new tag. release.sh becomes a thin dispatcher that keeps the pre-flight guards (semver, on-main, clean tree, in-sync with origin/main).
- Drop the unused GOFLAGS env from the release job (this workflow never compiles Mercure code; build tags belong to ci.yml/cd.yml). - Validate the version input inside the workflow as well, so a UI-triggered dispatch can't slip a non-semver string through. - Pin helm-docs to v1.14.2 instead of @latest for reproducibility. - Replace fragile "(HTTP 404)" stderr grepping with a matching-refs lookup that returns an empty array for absent tags, and extend the split-state guard so a mismatched caddy/v<version> on the resume path is caught up-front instead of inside create_tag. - Build the release tree from `git diff --name-only HEAD` so any file the bump or helm-docs touches (e.g. an unexpected top-level go.sum delta) is captured, matching the previous `git commit -a` behavior. - On resume, skip the cd.yml dispatch when a prior run is already in flight or has succeeded; only failed runs are retried. - Restore the three-way behind/ahead/diverged diagnostic in release.sh that the rewrite collapsed into a single equality check.
Trim explanatory comments to one or two lines each and drop the operator-side semver regex from release.sh — release.yml validates it.
- Hard-fail the cd.yml dispatch step on error (was emitting a warning while reporting success). - Use matching-refs in create_tag so transient API failures aren't read as "tag absent". - Build the release tree from `git status` partitions so additions, deletions, and modifications round-trip correctly. - Detect cd.yml in-flight via the runs API instead of `gh run list --branch`, and skip dispatch only if a GitHub Release already exists or a run is still active — cancelled/failed runs are now retried. - Clarify the "no file changes" error with operator guidance. - Check that git is installed in release.sh.
- Verify the resumed commit actually contains the expected Chart.yaml version and caddy/go.mod mercure pin before re-tagging or dispatching. - Use --no-renames so renames decompose into add+delete and both halves land in the API tree mutation. - Preserve each file's existing mode (executable bit) when building tree entries instead of hardcoding 100644. - Scope the concurrency group per version so a pending environment approval doesn't block dispatches for a different version; document why same-version dispatches still serialize. - Clarify that the release-existence guard works because GoReleaser is configured with `release.draft: true`.
- Match the mercure require entry in caddy/go.mod under both block and single-line forms so a future `go mod tidy` reformat doesn't fail the resume verification. - Detect a release-shaped main HEAD without tags as resumable, covering the case where a previous run pushed the commit but failed before create_tag. - Guard against main advancing between checkout and the commit step by asserting parent_sha equals the original checkout SHA before building the API tree. - release.sh: restore set -o errtrace so the ERR trap fires inside any future helpers, and fetch tags so the operator sees existing release tags before dispatching.
- Add `set -euo pipefail` to the Validate inputs step for consistency with the other run blocks. - Hardcode mode 100644 for deletion entries since the mode is purely formal when sha is null. - Reword the verify_release_content comment to spell out that omitting the `require` keyword from the grep is what makes it match both block and single-line layouts.
0c014d1 to
273c1d5
Compare
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 18, 2026
Cross-port of dunglas/mercure#1246 review feedback: - Validate the version input inside release.yaml as well, so a UI-triggered dispatch can't slip a non-semver string through. - Replace the fragile "(HTTP 404)" stderr grep with a matching-refs lookup that returns an empty array for absent tags, and extend the split-state guard so a mismatched caddy/v<version> on the resume path is caught up-front instead of inside create_tag. - Build the release tree from `git diff --name-only HEAD` so anything the PGO refresh or `go mod tidy` step touches (beyond the previously hardcoded three paths) is captured. - Restore the three-way behind/ahead/diverged diagnostic in release.sh that the rewrite collapsed into a single equality check.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 18, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Use matching-refs in create_tag so transient API failures aren't read as "tag absent". - Build the release tree from `git status` partitions so additions, deletions, and modifications round-trip correctly. - Clarify the "no file changes" error with operator guidance. - Check that git is installed in release.sh.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 18, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Verify the resumed commit actually contains the expected caddy/go.mod frankenphp pin and a non-trivial PGO profile before re-tagging or dispatching downstream builds. - Use --no-renames so renames decompose into add+delete and both halves land in the API tree mutation. - Preserve each file's existing mode (executable bit) when building tree entries instead of hardcoding 100644. - Scope the concurrency group per version so a pending environment approval doesn't block dispatches for a different version.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 18, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Match the frankenphp require entry in caddy/go.mod under both block and single-line forms so a future `go mod tidy` reformat doesn't fail the resume verification. - Detect a release-shaped main HEAD without tags as resumable, covering the case where a previous run pushed the commit but failed before create_tag. - Guard against main advancing between checkout and the commit step by asserting parent_sha equals the original checkout SHA before building the API tree. - release.sh: restore set -o errtrace so the ERR trap fires inside any future helpers, and fetch tags so the operator sees existing release tags before dispatching.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 18, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Add `set -euo pipefail` to the Validate inputs step. - Hardcode mode 100644 for deletion entries since the mode is purely formal when sha is null. - Reword the verify_release_content comment to spell out that omitting the `require` keyword from the grep is what makes it match both block and single-line layouts.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 26, 2026
Cross-port of dunglas/mercure#1246 review feedback: - Validate the version input inside release.yaml as well, so a UI-triggered dispatch can't slip a non-semver string through. - Replace the fragile "(HTTP 404)" stderr grep with a matching-refs lookup that returns an empty array for absent tags, and extend the split-state guard so a mismatched caddy/v<version> on the resume path is caught up-front instead of inside create_tag. - Build the release tree from `git diff --name-only HEAD` so anything the PGO refresh or `go mod tidy` step touches (beyond the previously hardcoded three paths) is captured. - Restore the three-way behind/ahead/diverged diagnostic in release.sh that the rewrite collapsed into a single equality check.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 26, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Use matching-refs in create_tag so transient API failures aren't read as "tag absent". - Build the release tree from `git status` partitions so additions, deletions, and modifications round-trip correctly. - Clarify the "no file changes" error with operator guidance. - Check that git is installed in release.sh.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 26, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Verify the resumed commit actually contains the expected caddy/go.mod frankenphp pin and a non-trivial PGO profile before re-tagging or dispatching downstream builds. - Use --no-renames so renames decompose into add+delete and both halves land in the API tree mutation. - Preserve each file's existing mode (executable bit) when building tree entries instead of hardcoding 100644. - Scope the concurrency group per version so a pending environment approval doesn't block dispatches for a different version.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 26, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Match the frankenphp require entry in caddy/go.mod under both block and single-line forms so a future `go mod tidy` reformat doesn't fail the resume verification. - Detect a release-shaped main HEAD without tags as resumable, covering the case where a previous run pushed the commit but failed before create_tag. - Guard against main advancing between checkout and the commit step by asserting parent_sha equals the original checkout SHA before building the API tree. - release.sh: restore set -o errtrace so the ERR trap fires inside any future helpers, and fetch tags so the operator sees existing release tags before dispatching.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
May 26, 2026
Cross-port of dunglas/mercure#1246 follow-up: - Add `set -euo pipefail` to the Validate inputs step. - Hardcode mode 100644 for deletion entries since the mode is purely formal when sha is null. - Reword the verify_release_content comment to spell out that omitting the `require` keyword from the grep is what makes it match both block and single-line layouts.
dunglas
added a commit
to php/frankenphp
that referenced
this pull request
Jun 3, 2026
Cross-port of review feedback from dunglas/mercure#1246, applied to the changes that this workflow shares structurally with Mercure's. ## Summary - **Validate the `version` input inside `release.yaml`.** The semver regex in `release.sh` only protects operators using the script; a UI-triggered dispatch could otherwise propagate `latest`, `1.2`, or any string containing `/` straight into `go get @v...`, `sed`, and tag refs. - **Replace the `(HTTP 404)` stderr grep** with a `git/matching-refs/tags/...` lookup that returns an empty array for absent tags. Distinguishing "tag missing" from rate-limit / 5xx / auth failures no longer depends on the exact wording of `gh`'s error messages. The split-state guard now also fires symmetrically: a mismatched `caddy/v<version>` on the resume path is caught before any writes. - **Build the release tree from `git diff --name-only HEAD`** so the commit captures every file the PGO refresh or `go mod tidy` step touches, rather than the previously hardcoded three paths. - **Restore the three-way behind/ahead/diverged diagnostic in `release.sh`** so the operator knows whether to `git pull`, `git push`, or reconcile a divergence.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.github/workflows/release.yml, modeled after FrankenPHP's new release workflow: bumpscaddy/go.mod, bumpscharts/mercure/Chart.yaml, regenerates the chart README viahelm-docs, commits + tagsv<version>andcaddy/v<version>through the GitHub API (server-signed undergithub-actions[bot]), then dispatchescd.ymlagainst the new tag so GoReleaser drafts the release.release.shto a thin dispatcher that keeps the existing operator-side guards (on-main, clean tree, in-sync withorigin/main) and callsgh workflow run release.yml. The semver check now lives in the workflow itself so UI-triggered dispatches are also validated.The workflow is idempotent: re-dispatching after a partial failure detects which steps already completed (tag existence is the source of truth) and skips them. As a fallback, a release-shaped
mainHEAD without tags is also detected as resumable.Notes
pushevents, socd.ymlis dispatched explicitly against the tag ref;cd-chart.ymlcontinues to fire automatically onrelease: published.