|
1 | 1 | name: prepare release |
2 | 2 |
|
3 | 3 | # Manually dispatched from `develop`. Computes the next version from Conventional |
4 | | -# Commits, regenerates CHANGELOG.md, and opens a PR into `main`. The PR carries the |
5 | | -# full develop payload plus the changelog commit, so merging it promotes develop -> |
| 4 | +# Commits, regenerates CHANGELOG.md, and pushes a `release/<tag>` branch carrying the |
| 5 | +# full develop payload plus the changelog commit. Merging that branch promotes develop -> |
6 | 6 | # main with the changelog already in place — BEFORE the release workflow cuts the tag. |
| 7 | +# |
| 8 | +# This workflow deliberately does NOT open the pull request. Opening it here would make |
| 9 | +# the PR authored by github-actions[bot], and a bot-authored PR does not trigger the |
| 10 | +# `pull_request` workflows (CI, Integration Tests, Commit Lint) that gate `main` — the |
| 11 | +# release would arrive unverified. Instead the release PR text is written to a file on |
| 12 | +# the release branch and a prefilled "create PR" link is put in the job summary, so a |
| 13 | +# maintainer opens it in two clicks and the checks run as normal. |
7 | 14 |
|
8 | 15 | on: |
9 | 16 | workflow_dispatch: |
|
16 | 23 |
|
17 | 24 | permissions: |
18 | 25 | contents: write |
19 | | - pull-requests: write |
20 | 26 |
|
21 | 27 | jobs: |
22 | 28 | prepare: |
23 | | - name: Regenerate changelog and open release PR |
| 29 | + name: Regenerate changelog and stage the release branch |
24 | 30 | runs-on: ubuntu-latest |
25 | 31 | if: github.ref == 'refs/heads/develop' |
26 | 32 | steps: |
@@ -53,22 +59,62 @@ jobs: |
53 | 59 | - name: Regenerate CHANGELOG.md |
54 | 60 | run: uv run git-changelog --bump '${{ inputs.bump }}' |
55 | 61 |
|
56 | | - - name: Open release PR |
57 | | - env: |
58 | | - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 62 | + - name: Write the release PR text |
| 63 | + id: pr_text |
| 64 | + run: | |
| 65 | + set -euo pipefail |
| 66 | + tag="${{ steps.version.outputs.tag }}" |
| 67 | + body_file=".github/release-pr/${tag}.md" |
| 68 | + mkdir -p "$(dirname "${body_file}")" |
| 69 | +
|
| 70 | + # Pull just this version's section out of the freshly regenerated changelog: |
| 71 | + # start at its anchor, stop at the next one. |
| 72 | + notes="$(awk -v t="${tag}" \ |
| 73 | + 'BEGIN{p="^<a name=\""t"\"></a>$"} $0 ~ p {f=1} f && /^<a name=/ && ++n>1 {exit} f' \ |
| 74 | + CHANGELOG.md)" |
| 75 | +
|
| 76 | + { |
| 77 | + printf 'Automated release prep for **%s**. CHANGELOG.md regenerated via git-changelog.\n\n' "${tag}" |
| 78 | + printf 'Merging promotes `develop` -> `main` with the changelog already in place.\n' |
| 79 | + printf 'Afterwards, run the **release** workflow on `main` to build, publish, and tag %s.\n\n' "${tag}" |
| 80 | + printf -- '---\n\n' |
| 81 | + printf '%s\n' "${notes}" |
| 82 | + } > "${body_file}" |
| 83 | +
|
| 84 | + echo "body_file=${body_file}" >> "$GITHUB_OUTPUT" |
| 85 | +
|
| 86 | + - name: Push the release branch |
59 | 87 | run: | |
60 | 88 | set -euo pipefail |
61 | 89 | tag="${{ steps.version.outputs.tag }}" |
62 | 90 | branch="release/${tag}" |
63 | 91 | git config user.name "github-actions[bot]" |
64 | 92 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
65 | 93 | git switch -c "${branch}" |
66 | | - git add CHANGELOG.md |
| 94 | + git add CHANGELOG.md "${{ steps.pr_text.outputs.body_file }}" |
67 | 95 | # `chore` keeps this bookkeeping commit out of the rendered sections; |
68 | 96 | # `docs` would list every release's regeneration in the next release. |
69 | 97 | git commit -m "chore(changelog): update for ${tag}" |
70 | 98 | git push --force-with-lease origin "${branch}" |
71 | | - gh pr create \ |
72 | | - --base main --head "${branch}" \ |
73 | | - --title "chore(release): ${tag}" \ |
74 | | - --body "Automated release prep for **${tag}**. Regenerated CHANGELOG.md via git-changelog. Merging promotes develop -> main; then run the release workflow on main to build, publish, and tag ${tag}." |
| 99 | +
|
| 100 | + - name: Summarise how to open the release PR |
| 101 | + run: | |
| 102 | + set -euo pipefail |
| 103 | + tag="${{ steps.version.outputs.tag }}" |
| 104 | + branch="release/${tag}" |
| 105 | + body_file="${{ steps.pr_text.outputs.body_file }}" |
| 106 | + title="chore(release): ${tag}" |
| 107 | + # Only the title is prefilled via the URL: bodies routinely exceed what a query |
| 108 | + # string can carry, so the body is copied from the file on the branch instead. |
| 109 | + encoded_title="$(jq -rn --arg t "${title}" '$t|@uri')" |
| 110 | + url="${{ github.server_url }}/${{ github.repository }}/compare/main...${branch}?expand=1&title=${encoded_title}" |
| 111 | +
|
| 112 | + { |
| 113 | + printf '## %s is staged\n\n' "${tag}" |
| 114 | + printf 'Branch `%s` is pushed. Open the PR manually — a bot-authored PR would not run the `pull_request` checks that gate `main`.\n\n' "${branch}" |
| 115 | + printf '### [→ Open the release PR](%s)\n\n' "${url}" |
| 116 | + printf 'Base `main`, head `%s`, title:\n\n```\n%s\n```\n\n' "${branch}" "${title}" |
| 117 | + printf 'The body below is also committed to `%s` on that branch — copy it in:\n\n' "${body_file}" |
| 118 | + printf -- '---\n\n' |
| 119 | + cat "${body_file}" |
| 120 | + } >> "$GITHUB_STEP_SUMMARY" |
0 commit comments