Web Analytics

What’s happening at Joshu?

Implementing cascading merges in GitHub Actions (Part 2)

  • Zohar ZilbermanZohar Zilberman
  • November 2022
Merging

In Part 1 we implemented cascading merges in GitHub Actions. The implementation used release branches named release/YEAR.MONTH (for example release/2022.10).

In this part we’ll add another workflow that creates new release branches automatically every month.

Why create release branches automatically

The first release branch naming we looked at resembled Semantic Versioning, which is simple and intuitive: release/1.0, release/2.0, etc.

However, this means that when a version’s development is about to end and we want to enter code freeze, the next release branch has to be created manually.

Nothing wrong with that, but here we’ll try a different approach: Instead of creating release branches manually, we’ll create them automatically every month.

What we’ll implement

The workflow we’ll add will create a new release branch every month on the 22nd at midnight UTC.

Once the new release branch is created, we also set it as the default branch for the repo.

The idea is to have at least a week between the time the workflow runs and when a version would be released, assuming it’s at the end of the month. This gives us time to stabilize the release while new changes are pushed to the next release.

We might still want to push changes to the current release branch, such as be fixes and small changes to help stabilize the release.

The workflow

Let’s see the new workflow and walk through each step below. We’ll create the new workflow in .github/workflows/create-next-release.yml:

						name: ✨ Create Next Release
						on:
						  schedule:
						    - cron: "0 0 22 * *"
						jobs:
						  create_next_release:
						    name: ✨ Create Next Release
						    runs-on: ubuntu-latest
						    steps:
						      - name: 🛎 Checkout
						        uses: actions/checkout@v3
						        with:
						          token: ${{ secrets.CI_PAT }}
						          fetch-depth: "0"
						      - name: 🔍 Find next release branch
						        id: branches
						        run: |
						          current_branch="release/`date +%Y.%m`"
						          git checkout "${current_branch}"
						          ./.github/scripts/next-release-branch.sh
						      - name: 🏗 Create next branch
						        run: |
						          current_branch="${{ steps.branches.outputs.current }}"
						          next_branch="${{ steps.branches.outputs.next }}"
						          if git branch -r --format "%(refname:short)" | grep "^origin/${next_branch}$"
						          then
						            echo "Next branch already exists"
						          else
						            echo "Creating next branch"
						            git checkout -b "${next_branch}"
						            git push origin --set-upstream "${next_branch}"
						          fi
						      - name: 🛠 Set default branch
						        env:
						          GITHUB_TOKEN: ${{ secrets.CI_PAT }}
						        run: |
						          gh repo edit "${{ github.repository }}" \
						            --default-branch "${{ steps.branches.outputs.next }}"
						

1. On… schedule… cron

This is when the workflow would be executed.

2. Checkout step

Like in the previous workflow, we’re checking out the code using a custom PAT (personal access token) so that we can push branches to the origin repo.

3. Find next release branch

Since the workflow starts on a schedule, we can’t assume which branch we’d start running from.

This step only assumes the release branch for the current month already exists and checks it out.

Then, we run the same next-release-branch.sh script from Part 1 to find the next release branch.

4. Create next branch

This step tests if the next release branch already exists, as we may still be creating it manually sometimes. For example, this might happen if we needed to create several release branches in advance.

If the next release branch doesn’t exist, we simply create it from the current branch, which is assumed to be the latest as the next branch doesn’t exist yet.

5. Set default branch

The last step uses GitHub’s CLI gh to set the default branch of the repo as the next branch.

Note that we always do this, regardless of whether we had to create the next release branch or not.

Setting the default branch will make all new PRs open against the next release branch by default, encouraging everyone to only push critical changes to the current release branch.

Up next

In Part 3 we’ll add Slack notifications to both workflows so everyone can get notified whenever a cascading merged happens, when it failed and requires manual fixing and when a new release branch is created.