-
Notifications
You must be signed in to change notification settings - Fork 21
chore(release): add release workflows #255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
dmcilvaney
wants to merge
8
commits into
microsoft:main
Choose a base branch
from
dmcilvaney:damcilva/changelog_workflows
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
fe5e057
chore(release): add release workflows
dmcilvaney 8baf12c
fixup! chore(release): add release workflows
dmcilvaney bb6a46f
Apply suggestions from code review
dmcilvaney b062234
fixup! Apply suggestions from code review
dmcilvaney 8cb4bd0
fixup! Apply suggestions from code review
dmcilvaney 7870af7
fixup! Apply suggestions from code review
dmcilvaney 6c38614
fixup! Apply suggestions from code review
dmcilvaney 3e5f6f5
fixup! Apply suggestions from code review
dmcilvaney File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,17 @@ | ||
| name: 'Get go tools' | ||
| description: 'Install go and related go tools' | ||
| name: "Get go tools" | ||
| description: "Install go and related go tools" | ||
| runs: | ||
| using: 'composite' | ||
| using: "composite" | ||
| steps: | ||
| - name: Install go | ||
| uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 | ||
| with: | ||
| go-version-file: 'go.mod' | ||
| - name: Install go | ||
| uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 | ||
| with: | ||
| go-version-file: "go.mod" | ||
|
|
||
| - name: Build and install mage | ||
| shell: bash | ||
| run: | | ||
| echo "Building and installing mage..." | ||
| go install github.com/magefile/mage@latest | ||
| - name: Build and install mage | ||
| shell: bash | ||
| run: | | ||
| echo "Building and installing mage..." | ||
| # No @version: inside the module this installs the mage version pinned in | ||
| # go.mod, so Dependabot keeps it current from a single source of truth. | ||
| go install github.com/magefile/mage |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| name: "Prepare release" | ||
|
|
||
| # Manually triggered. Generates the changelog draft on a release branch and | ||
| # pushes it. It does NOT open a PR (that needs auth we avoid) -- a maintainer | ||
| # opens the PR from the pushed branch, curates the draft, and merges it. Tagging | ||
| # happens afterwards in the "Release" workflow. See | ||
| # docs/developer/how-to/releasing.md. | ||
| on: | ||
| workflow_dispatch: | ||
|
|
||
| # Don't run two release preparations at once. | ||
| concurrency: | ||
| group: ${{ github.workflow }} | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: {} | ||
|
|
||
| jobs: | ||
| prepare-release: | ||
| name: "Prepare release branch" | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # Push the release branch. | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | ||
| with: | ||
| # Always draft from the repo's default branch (main upstream), not the | ||
| # branch this workflow_dispatch happened to be launched from. | ||
| ref: ${{ github.event.repository.default_branch }} | ||
| # git-cliff needs full history and tags to compute the next version. | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - name: Get go tools | ||
| uses: ./.github/getgotools | ||
|
|
||
| - name: Read pinned git-cliff version | ||
| id: gitcliff | ||
| run: | | ||
| set -euo pipefail | ||
| version="$(sed -n 's/^[[:space:]]*git-cliff = "=\([0-9.]*\)".*/\1/p' tools/git-cliff/Cargo.toml)" | ||
| if [ -z "$version" ]; then | ||
| echo "could not read git-cliff version from tools/git-cliff/Cargo.toml" >&2 | ||
| exit 1 | ||
| fi | ||
| echo "version=$version" >> "$GITHUB_OUTPUT" | ||
|
|
||
| - name: Install git-cliff | ||
| uses: taiki-e/install-action@bffeee26d4db9be238a4ea78d8826604ebcb594d # v2.82.5 | ||
| with: | ||
| tool: git-cliff@${{ steps.gitcliff.outputs.version }} | ||
|
|
||
| - name: Generate changelog draft | ||
| run: mage changelog | ||
|
|
||
| - name: Push release branch | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| REPO: ${{ github.repository }} | ||
| SERVER_URL: ${{ github.server_url }} | ||
| run: | | ||
| set -euo pipefail | ||
|
|
||
| # Nothing to release: `mage changelog` left CHANGELOG.md unchanged (no new entries since | ||
| # the last release). Report it in the job summary and stop -- this is not a failure. | ||
| if git diff --quiet -- CHANGELOG.md; then | ||
| { | ||
| echo "### Nothing to release" | ||
| echo "" | ||
| echo "No new changelog entries since the last release, so no release branch was created." | ||
| } >> "$GITHUB_STEP_SUMMARY" | ||
| echo "Nothing to release: CHANGELOG.md is unchanged." | ||
| exit 0 | ||
| fi | ||
|
|
||
| version="$(sed -n 's/^##[[:space:]]\+\[\([0-9]\+\.[0-9]\+\.[0-9]\+\)\].*/\1/p' CHANGELOG.md | head -1)" | ||
| if [ -z "$version" ]; then | ||
| echo "no '## [X.Y.Z]' heading found in CHANGELOG.md" >&2 | ||
| exit 1 | ||
| fi | ||
| branch="release/v${version}" | ||
|
|
||
| # A release branch for this version already exists (e.g. a prior prepare-release run | ||
| # that hasn't been merged or cleaned up). Fail rather than clobber it -- but leave a | ||
| # summary with the PR link so recovery is a click away. ($GITHUB_STEP_SUMMARY still | ||
| # renders even though the step exits non-zero.) | ||
| if git ls-remote --exit-code --heads origin "refs/heads/${branch}" >/dev/null 2>&1; then | ||
| pr_url="${SERVER_URL}/${REPO}/pull/new/${branch}" | ||
| { | ||
| echo "### Release branch already exists" | ||
| echo "" | ||
| echo "Branch \`${branch}\` already exists, so no new draft was created." | ||
| echo "" | ||
| echo "**[Open its pull request →](${pr_url})** to finish the release, or delete the" | ||
| echo "branch and re-run this workflow to regenerate the draft from the latest \`main\`." | ||
| } >> "$GITHUB_STEP_SUMMARY" | ||
| echo "Release branch '${branch}' already exists; open its PR or delete it and re-run." >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| git switch -c "$branch" | ||
| git add CHANGELOG.md | ||
| git commit -m "chore: prepare release v${version}" | ||
| gh auth setup-git | ||
| git push origin "$branch" | ||
|
|
||
| # Build the create-PR URL from the current server/repo so it points at this repo (fork or | ||
| # upstream). GitHub's pull/new/<branch> form targets the repo's default branch as the base. | ||
| pr_url="${SERVER_URL}/${REPO}/pull/new/${branch}" | ||
| { | ||
| echo "Pushed branch \`$branch\` with the v${version} changelog draft." | ||
| echo "" | ||
| echo "**[Open the pull request →](${pr_url})**, curate the changelog into user-facing notes, then merge." | ||
| } >> "$GITHUB_STEP_SUMMARY" | ||
| echo "Open a PR: ${pr_url}" | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| name: "Release" | ||
|
|
||
| # Runs when a push to main changes CHANGELOG.md -- i.e. when a release PR merges. | ||
| # Tags the new version via the idempotent `mage release`, pushes the tag, and | ||
| # publishes a GitHub Release with that version's changelog notes. Still idempotent: | ||
| # if the top version is already tagged (e.g. a later CHANGELOG.md edit) it's a | ||
| # no-op. See docs/developer/how-to/releasing.md. | ||
| on: | ||
| push: | ||
| branches: [main] | ||
|
dmcilvaney marked this conversation as resolved.
|
||
| paths: | ||
| - CHANGELOG.md | ||
|
|
||
| # Don't run two releases at once. | ||
| concurrency: | ||
| group: ${{ github.workflow }} | ||
| cancel-in-progress: false | ||
|
|
||
| permissions: {} | ||
|
|
||
| jobs: | ||
| release: | ||
| name: "Tag release" | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # Push the release tag. | ||
| steps: | ||
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | ||
| with: | ||
| # Need full history and tags to detect existing releases and tag HEAD. | ||
| fetch-depth: 0 | ||
| persist-credentials: false | ||
|
|
||
| - name: Get go tools | ||
| uses: ./.github/getgotools | ||
|
|
||
| - name: Create release tag from changelog | ||
| run: | | ||
| # Annotated tags (git tag -a) need a committer identity, which the runner lacks. | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "github-actions[bot]@users.noreply.github.com" | ||
| mage release | ||
|
|
||
| - name: Publish release | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| REPO: ${{ github.repository }} | ||
| run: | | ||
| set -euo pipefail | ||
| version="$(sed -n 's/^##[[:space:]]\+\[\([0-9]\+\.[0-9]\+\.[0-9]\+\)\].*/\1/p' CHANGELOG.md | head -1)" | ||
| if [ -z "$version" ]; then | ||
| echo "no '## [X.Y.Z]' heading found in CHANGELOG.md" >&2 | ||
| exit 1 | ||
| fi | ||
| tag="v${version}" | ||
|
|
||
| # Push the tag if the remote lacks it. Tag push is kept separate from publishing the | ||
| # release so a rerun can finish a half-done release that pushed the tag but never | ||
| # published (e.g. a prior run that failed between the two steps). | ||
| if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then | ||
| echo "Tag \`${tag}\` already on remote." >> "$GITHUB_STEP_SUMMARY" | ||
| else | ||
| gh auth setup-git | ||
| git push origin "refs/tags/${tag}" | ||
| echo "Pushed tag \`${tag}\`." >> "$GITHUB_STEP_SUMMARY" | ||
| fi | ||
|
|
||
| # If the GitHub Release already exists, there's nothing left to publish or warm. | ||
| if gh release view "${tag}" --repo "${REPO}" >/dev/null 2>&1; then | ||
| echo "Release \`${tag}\` already exists; nothing to publish." >> "$GITHUB_STEP_SUMMARY" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Release notes = this version's changelog section (its body, without the heading line). | ||
| # Match only numeric version headings so this stays in sync with the version parsed | ||
| # above and can never capture a non-release heading. Tolerate any whitespace after '##' | ||
| # to match `mage release`. | ||
| notes="${RUNNER_TEMP}/release-notes.md" | ||
| awk '/^##[[:space:]]+\[[0-9]/{n++; next} n==1' CHANGELOG.md > "${notes}" | ||
| if [ ! -s "${notes}" ]; then | ||
| echo "no changelog notes found for ${tag}" >&2 | ||
| exit 1 | ||
| fi | ||
| gh release create "${tag}" --repo "${REPO}" --title "${tag}" --notes-file "${notes}" | ||
| echo "Published release \`${tag}\` with notes from CHANGELOG.md." >> "$GITHUB_STEP_SUMMARY" | ||
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you remind me who is allowed to run this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need write perms, and to be in the collaborator group or better.
I wasn't too worried about this, since all it can do is create a branch, you still need to make the PR, get it approved, and merge it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are ways to filter in the workflow itself if needed.