# This workflow runs after a merge to any release branch of the action. It: # 1. Tags the merge commit on the release branch that represents the new release with an `vN.x.y` # tag # 2. Updates the `vN` tag to refer to this merge commit. # 3. Iff vN == vLatest, merges any changes from the release back into the main branch. # Typically, this is two commits – one to update the version number and one to update dependencies. name: Tag release and merge back on: workflow_dispatch: inputs: baseBranch: description: 'The base branch to merge into' default: main required: false push: branches: - releases/v* jobs: merge-back: runs-on: ubuntu-latest environment: Automation if: github.repository == 'github/codeql-action' env: BASE_BRANCH: "${{ github.event.inputs.baseBranch || 'main' }}" HEAD_BRANCH: "${{ github.head_ref || github.ref }}" permissions: contents: write # needed to create tags and push commits pull-requests: write steps: - name: Dump environment run: env - name: Dump GitHub context env: GITHUB_CONTEXT: '${{ toJson(github) }}' run: echo "${GITHUB_CONTEXT}" - uses: actions/checkout@v4 with: fetch-depth: 0 # ensure we have all tags and can push commits - uses: actions/setup-node@v4 - name: Update git config run: | git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" git config --global user.name "github-actions[bot]" - name: Get version and new branch id: getVersion run: | VERSION="v$(jq '.version' -r 'package.json')" echo "version=${VERSION}" >> $GITHUB_OUTPUT short_sha="${GITHUB_SHA:0:8}" NEW_BRANCH="mergeback/${VERSION}-to-${BASE_BRANCH}-${short_sha}" echo "newBranch=${NEW_BRANCH}" >> $GITHUB_OUTPUT LATEST_RELEASE_BRANCH=$(git branch -r | grep -E "origin/releases/v[0-9]+$" | sed 's/origin\///g' | sort -V | tail -1 | xargs) echo "latest_release_branch=${LATEST_RELEASE_BRANCH}" >> $GITHUB_OUTPUT - name: Dump branches env: NEW_BRANCH: "${{ steps.getVersion.outputs.newBranch }}" run: | echo "BASE_BRANCH ${BASE_BRANCH}" echo "HEAD_BRANCH ${HEAD_BRANCH}" echo "NEW_BRANCH ${NEW_BRANCH}" echo "LATEST_RELEASE_BRANCH ${LATEST_RELEASE_BRANCH}" echo "GITHUB_REF ${GITHUB_REF}" - name: Create mergeback branch env: NEW_BRANCH: "${{ steps.getVersion.outputs.newBranch }}" run: | git checkout -b "${NEW_BRANCH}" - name: Check for tag id: check env: VERSION: "${{ steps.getVersion.outputs.version }}" run: | set +e # don't fail on an errored command git ls-remote --tags origin | grep "${VERSION}" exists="$?" if [ "${exists}" -eq 0 ]; then echo "Tag ${VERSION} exists. Not going to re-release." echo "exists=true" >> $GITHUB_OUTPUT else echo "Tag ${VERSION} does not exist yet." fi # we didn't tag the release during the update-release-branch workflow because the # commit that actually makes it to the release branch is a merge commit, # and not yet known during the first workflow. We tag now because we know the correct commit. - name: Tag release if: steps.check.outputs.exists != 'true' env: VERSION: ${{ steps.getVersion.outputs.version }} run: | # Create the `vx.y.z` tag git tag --annotate "${VERSION}" --message "${VERSION}" # Update the `vx` tag major_version_tag=$(cut -d '.' -f1 <<< "${VERSION}") # Use `--force` to overwrite the major version tag git tag --annotate "${major_version_tag}" --message "${major_version_tag}" --force # Push the tags, using: # - `--atomic` to make sure we either update both tags or neither (an intermediate state, # e.g. where we update the vN.x.y tag on the remote but not the vN tag, could result in # unwanted Dependabot updates, e.g. from vN to vN.x.y) # - `--force` since we're overwriting the `vN` tag git push origin --atomic --force refs/tags/"${VERSION}" refs/tags/"${major_version_tag}" - name: Prepare partial Changelog env: PARTIAL_CHANGELOG: "${{ runner.temp }}/partial_changelog.md" VERSION: "${{ steps.getVersion.outputs.version }}" run: | python .github/workflows/script/prepare_changelog.py CHANGELOG.md "$VERSION" > $PARTIAL_CHANGELOG echo "::group::Partial CHANGELOG" cat $PARTIAL_CHANGELOG echo "::endgroup::" - name: Create mergeback branch if: ${{ steps.check.outputs.exists != 'true' && endsWith(github.ref_name, steps.getVersion.outputs.latest_release_branch) }} env: VERSION: "${{ steps.getVersion.outputs.version }}" NEW_BRANCH: "${{ steps.getVersion.outputs.newBranch }}" GITHUB_TOKEN: "${{ secrets.GITHUB_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 "Update dependencies" label to the PR to trigger just this workflow. - [ ] Wait for the "Update dependencies" workflow to push a commit updating the dependencies. - [ ] 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 ) # 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}" # 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 "Update dependencies" \ --body "${pr_body}" \ --assignee "${GITHUB_ACTOR}" \ --draft - name: Generate token uses: actions/create-github-app-token@c1a285145b9d317df6ced56c09f525b5c2b6f755 id: app-token with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} - name: Create the GitHub release env: PARTIAL_CHANGELOG: "${{ runner.temp }}/partial_changelog.md" VERSION: "${{ steps.getVersion.outputs.version }}" GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | # Do not mark this release as latest. The most recent CLI release must be marked as latest. gh release create \ "$VERSION" \ --latest=false \ --title "$VERSION" \ --notes-file "$PARTIAL_CHANGELOG"