-
Notifications
You must be signed in to change notification settings - Fork 379
Add workflow for rolling back release #3033
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
base: main
Are you sure you want to change the base?
Changes from all commits
bd8a3ce
049a0a7
a1212db
541b8e4
41dab09
c700209
c9665e6
4205856
e1654f1
e22f34a
1e21ce3
67e42fe
25c4fcc
15ed54f
8f01f5d
43d629c
b06d325
9389ce0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
name: "Prepare mergeback branch" | ||
description: Prepares a mergeback branch and opens a PR for it | ||
inputs: | ||
base: | ||
description: "The name of the base branch" | ||
required: true | ||
head: | ||
description: "The name of the head branch" | ||
required: true | ||
branch: | ||
description: "The name of the branch to create." | ||
required: true | ||
version: | ||
description: "The new version" | ||
required: true | ||
token: | ||
description: "The token to use" | ||
required: true | ||
dry-run: | ||
description: "Set to true to skip creating the PR. The branch will still be pushed." | ||
default: "false" | ||
runs: | ||
using: composite | ||
steps: | ||
- name: Create mergeback branch | ||
shell: bash | ||
env: | ||
VERSION: "${{ inputs.version }}" | ||
NEW_BRANCH: "${{ inputs.branch }}" | ||
run: | | ||
set -exu | ||
|
||
# Ensure we are on the new branch | ||
git checkout "${NEW_BRANCH}" | ||
|
||
# Update the version number ready for the next release | ||
npm version patch --no-git-tag-version | ||
|
||
# Update the changelog, adding a new version heading directly above the most recent existing one | ||
awk '!f && /##/{print "'"## [UNRELEASED]\n\nNo user facing changes.\n"'"; f=1}1' CHANGELOG.md > temp && mv temp CHANGELOG.md | ||
git add . | ||
git commit -m "Update changelog and version after ${VERSION}" | ||
|
||
git push origin "${NEW_BRANCH}" | ||
|
||
- name: Create PR | ||
shell: bash | ||
if: inputs.dry-run != 'true' | ||
env: | ||
VERSION: "${{ inputs.version }}" | ||
BASE_BRANCH: "${{ inputs.base }}" | ||
HEAD_BRANCH: "${{ inputs.head }}" | ||
NEW_BRANCH: "${{ inputs.branch }}" | ||
GITHUB_TOKEN: "${{ inputs.token }}" | ||
run: | | ||
set -exu | ||
pr_title="Mergeback ${VERSION} ${HEAD_BRANCH} into ${BASE_BRANCH}" | ||
pr_body=$(cat << EOF | ||
This PR bumps the version number and updates the changelog after the ${VERSION} release. | ||
|
||
Please do the following: | ||
|
||
- [ ] Remove and re-add the "Rebuild" label to the PR to trigger just this workflow. | ||
- [ ] Wait for the "Rebuild" workflow to push a commit updating the distribution files. | ||
- [ ] Mark the PR as ready for review to trigger the full set of PR checks. | ||
- [ ] Approve and merge the PR. When merging the PR, make sure "Create a merge commit" is | ||
selected rather than "Squash and merge" or "Rebase and merge". | ||
EOF | ||
) | ||
|
||
# PR checks won't be triggered on PRs created by Actions. Therefore mark the PR as draft | ||
# so that a maintainer can take the PR out of draft, thereby triggering the PR checks. | ||
gh pr create \ | ||
--head "${NEW_BRANCH}" \ | ||
--base "${BASE_BRANCH}" \ | ||
--title "${pr_title}" \ | ||
--label "Rebuild" \ | ||
--body "${pr_body}" \ | ||
--assignee "${GITHUB_ACTOR}" \ | ||
--draft |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
name: Prepare release | ||
on: | ||
workflow_call: | ||
outputs: | ||
version: | ||
description: "The version that is being released." | ||
value: ${{ jobs.prepare.outputs.version }} | ||
major_version: | ||
description: "The major version of the release." | ||
value: ${{ jobs.prepare.outputs.major_version }} | ||
latest_tag: | ||
description: "The most recent, existing release tag." | ||
value: ${{ jobs.prepare.outputs.latest_tag }} | ||
backport_source_branch: | ||
description: "The release branch for the given tag." | ||
value: ${{ jobs.prepare.outputs.backport_source_branch }} | ||
backport_target_branches: | ||
description: "JSON encoded list of branches to target with backports." | ||
value: ${{ jobs.prepare.outputs.backport_target_branches }} | ||
|
||
push: | ||
paths: | ||
- .github/workflows/prepare-release.yml | ||
|
||
jobs: | ||
prepare: | ||
name: "Prepare release" | ||
runs-on: ubuntu-latest | ||
if: github.repository == 'github/codeql-action' | ||
|
||
permissions: | ||
contents: read | ||
|
||
outputs: | ||
version: ${{ steps.versions.outputs.version }} | ||
major_version: ${{ steps.versions.outputs.major_version }} | ||
latest_tag: ${{ steps.versions.outputs.latest_tag }} | ||
backport_source_branch: ${{ steps.branches.outputs.backport_source_branch }} | ||
backport_target_branches: ${{ steps.branches.outputs.backport_target_branches }} | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v5 | ||
with: | ||
fetch-depth: 0 # Need full history for calculation of diffs | ||
|
||
- name: Configure runner for release | ||
uses: ./.github/actions/release-initialise | ||
|
||
- name: Get version tags | ||
id: versions | ||
run: | | ||
VERSION="v$(jq '.version' -r 'package.json')" | ||
echo "version=${VERSION}" >> $GITHUB_OUTPUT | ||
MAJOR_VERSION=$(cut -d '.' -f1 <<< "${VERSION}") | ||
echo "major_version=${MAJOR_VERSION}" >> $GITHUB_OUTPUT | ||
LATEST_TAG=$(git tag --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+' | head -1) | ||
echo "latest_tag=${LATEST_TAG}" >> $GITHUB_OUTPUT | ||
|
||
- name: Determine older release branches | ||
id: branches | ||
uses: ./.github/actions/release-branches | ||
with: | ||
major_version: ${{ steps.versions.outputs.major_version }} | ||
latest_tag: ${{ steps.versions.outputs.latest_tag }} | ||
|
||
- name: Print release information | ||
run: | | ||
echo 'version: ${{ steps.versions.outputs.version }}' | ||
echo 'major_version: ${{ steps.versions.outputs.major_version }}' | ||
echo 'latest_tag: ${{ steps.versions.outputs.latest_tag }}' | ||
echo 'backport_source_branch: ${{ steps.branches.outputs.backport_source_branch }}' | ||
echo 'backport_target_branches: ${{ steps.branches.outputs.backport_target_branches }}' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
name: Rollback release | ||
on: | ||
# You can trigger this workflow via workflow dispatch to start a rollback. | ||
# This will create a draft release that mirrors the release for `rollback-tag`. | ||
workflow_dispatch: | ||
inputs: | ||
rollback-tag: | ||
type: string | ||
description: "The tag of an old release to roll-back to." | ||
required: true | ||
# Only for dry-runs of changes to the workflow. | ||
push: | ||
paths: | ||
- .github/workflows/rollback-release.yml | ||
- .github/actions/prepare-mergeback-branch/** | ||
|
||
jobs: | ||
prepare: | ||
name: "Prepare release" | ||
if: github.repository == 'github/codeql-action' | ||
|
||
permissions: | ||
contents: read | ||
|
||
uses: ./.github/workflows/prepare-release.yml | ||
|
||
rollback: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll soon be needing to release CodeQL Action v4 to run on Node 24. I think the backport automation in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd propose doing this in a follow-up PR once we have the basic version of this workflow working. |
||
name: "Create rollback release" | ||
if: github.repository == 'github/codeql-action' | ||
runs-on: ubuntu-latest | ||
timeout-minutes: 45 | ||
|
||
# Don't set the deployment environment for test runs | ||
mbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# The Actions token does not have permissions to push changes to workflow files. | ||
# Since workflow files may change as part of a backport PR, we use the "Automation" environment for real runs to authenticate as a GitHub App and push these changes. | ||
environment: ${{ github.event_name == 'workflow_dispatch' && 'Automation' || '' }} | ||
|
||
needs: | ||
- prepare | ||
|
||
permissions: | ||
contents: write # needed to push to the repo (tags and releases) | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v5 | ||
with: | ||
fetch-depth: 0 # Need full history for calculation of diffs | ||
|
||
- name: Configure runner for release | ||
uses: ./.github/actions/release-initialise | ||
|
||
- name: Create tag for testing | ||
if: github.event_name != 'workflow_dispatch' | ||
shell: bash | ||
run: git tag v0.0.0 | ||
|
||
# We start by preparing the mergeback branch, mainly so that we have the updated changelog | ||
# readily available for the partial changelog that's needed for the release. | ||
- name: Prepare mergeback branch | ||
id: mergeback-branch | ||
env: | ||
BASE_BRANCH: ${{ (github.event_name == 'workflow_dispatch' && 'main') || github.ref_name }} | ||
VERSION: ${{ needs.prepare.outputs.version }} | ||
run: | | ||
set -x | ||
|
||
# Checkout the base branch, since we may be testing on a different branch | ||
git checkout "$BASE_BRANCH" | ||
|
||
# Generate a new branch name for the mergeback PR | ||
short_sha="${GITHUB_SHA:0:8}" | ||
NEW_BRANCH="mergeback/${VERSION}-to-${BASE_BRANCH}-${short_sha}" | ||
echo "new-branch=${NEW_BRANCH}" >> $GITHUB_OUTPUT | ||
|
||
# Create the mergeback branch | ||
git checkout -b "${NEW_BRANCH}" | ||
|
||
- name: Prepare rollback changelog | ||
env: | ||
NEW_CHANGELOG: "${{ runner.temp }}/new_changelog.md" | ||
# We usually expect to checkout `inputs.rollback-tag` (required for `workflow_dispatch`), | ||
# but use `v0.0.0` for testing. | ||
ROLLBACK_TAG: ${{ inputs.rollback-tag || 'v0.0.0' }} | ||
LATEST_TAG: ${{ needs.prepare.outputs.latest_tag }} | ||
VERSION: "${{ needs.prepare.outputs.version }}" | ||
run: | | ||
python .github/workflows/script/rollback_changelog.py \ | ||
--target-version "${ROLLBACK_TAG:1}" \ | ||
--rollback-version "${LATEST_TAG:1}" \ | ||
--new-version "$VERSION" > $NEW_CHANGELOG | ||
|
||
echo "::group::New CHANGELOG" | ||
cat $NEW_CHANGELOG | ||
echo "::endgroup::" | ||
|
||
- name: Create tags | ||
shell: bash | ||
env: | ||
# We usually expect to checkout `inputs.rollback-tag` (required for `workflow_dispatch`), | ||
# but use `v0.0.0` for testing. | ||
ROLLBACK_TAG: ${{ inputs.rollback-tag || 'v0.0.0' }} | ||
RELEASE_TAG: ${{ needs.prepare.outputs.version }} | ||
MAJOR_VERSION_TAG: ${{ needs.prepare.outputs.major_version }} | ||
run: | | ||
git checkout "refs/tags/${ROLLBACK_TAG}" | ||
git tag --annotate "${RELEASE_TAG}" --message "${RELEASE_TAG}" | ||
git tag --annotate "${MAJOR_VERSION_TAG}" --message "${MAJOR_VERSION_TAG}" --force | ||
|
||
- name: Push tags | ||
# skip when testing | ||
if: github.event_name == 'workflow_dispatch' | ||
mbg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
shell: bash | ||
env: | ||
RELEASE_TAG: ${{ needs.prepare.outputs.version }} | ||
MAJOR_VERSION_TAG: ${{ needs.prepare.outputs.major_version }} | ||
run: | | ||
git push origin --atomic --force refs/tags/"${RELEASE_TAG}" refs/tags/"${MAJOR_VERSION_TAG}" | ||
|
||
- name: Prepare partial Changelog | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it could be clearer what we mean here by "partial changelog". It's still not fully clear, but we could call it "release description" for instance? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I used the existing terminology for this from the release workflow. Happy to change this to something else here, but we should probably update it there then as well to be consistent. |
||
env: | ||
NEW_CHANGELOG: "${{ runner.temp }}/new_changelog.md" | ||
PARTIAL_CHANGELOG: "${{ runner.temp }}/partial_changelog.md" | ||
VERSION: "${{ needs.prepare.outputs.version }}" | ||
run: | | ||
python .github/workflows/script/prepare_changelog.py $NEW_CHANGELOG "$VERSION" > $PARTIAL_CHANGELOG | ||
|
||
echo "::group::Partial CHANGELOG" | ||
cat $PARTIAL_CHANGELOG | ||
echo "::endgroup::" | ||
|
||
- name: Generate token | ||
if: github.event_name == 'workflow_dispatch' | ||
uses: actions/create-github-app-token@v2.1.1 | ||
id: app-token | ||
with: | ||
app-id: ${{ vars.AUTOMATION_APP_ID }} | ||
private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} | ||
|
||
- name: Create the rollback release | ||
if: github.event_name == 'workflow_dispatch' | ||
env: | ||
PARTIAL_CHANGELOG: "${{ runner.temp }}/partial_changelog.md" | ||
VERSION: "${{ needs.prepare.outputs.version }}" | ||
GH_TOKEN: ${{ steps.app-token.outputs.token }} | ||
RELEASE_URL: "${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ needs.prepare.outputs.version }}" | ||
run: | | ||
set -exu | ||
|
||
# Do not mark this release as latest. The most recent bundle release must be marked as latest. | ||
# Set as a draft to give us an opportunity to review the rollback release. | ||
gh release create \ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this print a link to the new release? It might be nice to add a link to the job summary to make it easier to move forwards to the next step of reviewing and publishing the release. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it automatically does that, but I have pushed a change which computes the release URL and adds it to the job summary. |
||
"$VERSION" \ | ||
--latest=false \ | ||
--draft \ | ||
--title "$VERSION" \ | ||
--notes-file "$PARTIAL_CHANGELOG" | ||
|
||
echo "Created draft rollback release at $RELEASE_URL" >> $GITHUB_STEP_SUMMARY | ||
|
||
- name: Update changelog | ||
shell: bash | ||
env: | ||
NEW_CHANGELOG: "${{ runner.temp }}/new_changelog.md" | ||
NEW_BRANCH: "${{ steps.mergeback-branch.outputs.new-branch }}" | ||
run: | | ||
git checkout "${NEW_BRANCH}" | ||
mv ${NEW_CHANGELOG} CHANGELOG.md | ||
|
||
- name: Create mergeback branch and PR | ||
uses: ./.github/actions/prepare-mergeback-branch | ||
with: | ||
base: "main" | ||
head: "" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this blank? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
branch: "${{ steps.mergeback-branch.outputs.new-branch }}" | ||
version: "${{ needs.prepare.outputs.version }}" | ||
token: "${{ secrets.GITHUB_TOKEN }}" | ||
# Setting this to `true` for non-workflow_dispatch events will | ||
# still push the `branch`, but won't create a corresponding PR | ||
dry-run: "${{ github.event_name != 'workflow_dispatch' }}" | ||
|
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.
I assume this is intended to be triggered on
main
?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.
Yeah, that's the intention. I think it could probably work if triggered from a different branch, but I haven't verified that.