Create release branch workflow (TryGhost/Ghost)
The Create release branch workflow from TryGhost/Ghost, explained and optimized by Latchkey.
A
CI health: A - excellent
Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Create release branch workflow from the TryGhost/Ghost repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
workflow (.yml)
name: Create release branch
on:
workflow_dispatch:
inputs:
base-ref:
description: 'Git ref to base from (defaults to latest tag)'
type: string
default: 'latest'
required: false
bump-type:
description: 'Version bump type (patch, minor)'
type: string
required: false
default: 'patch'
env:
FORCE_COLOR: 1
permissions:
contents: write
jobs:
create-branch:
if: github.repository == 'TryGhost/Ghost'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: inputs.base-ref == 'latest'
with:
ref: main
fetch-depth: 0
submodules: true
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
if: inputs.base-ref != 'latest'
with:
ref: ${{ inputs.base-ref }}
fetch-depth: 0
submodules: true
- name: Checkout most recent tag
run: git checkout "$(git describe --tags --abbrev=0 --match=v*)"
if: inputs.base-ref == 'latest'
- uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 # v4
with:
tool_versions: |
semver 3.3.0
- run: |
CURRENT_TAG=$(git describe --tags --abbrev=0 --match=v*)
NEW_VERSION=$(semver bump "$BUMP_TYPE_INPUT" "$CURRENT_TAG")
printf 'CURRENT_SHA=%s\n' "$(git rev-parse HEAD)" >> "$GITHUB_ENV"
printf 'NEW_VERSION=%s\n' "$NEW_VERSION" >> "$GITHUB_ENV"
env:
BUMP_TYPE_INPUT: ${{ inputs.bump-type }}
- name: Create branch
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const branchName = `v${process.env.NEW_VERSION}`;
console.log(`Creating branch: ${branchName}`);
await github.request('POST /repos/{owner}/{repo}/git/refs', {
owner: context.repo.owner,
repo: context.repo.repo,
ref: `refs/heads/${branchName}`,
sha: process.env.CURRENT_SHA
});
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Create release branch on: workflow_dispatch: inputs: base-ref: description: 'Git ref to base from (defaults to latest tag)' type: string default: 'latest' required: false bump-type: description: 'Version bump type (patch, minor)' type: string required: false default: 'patch' env: FORCE_COLOR: 1 permissions: contents: write jobs: create-branch: timeout-minutes: 30 if: github.repository == 'TryGhost/Ghost' runs-on: latchkey-small steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 if: inputs.base-ref == 'latest' with: ref: main fetch-depth: 0 submodules: true - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 if: inputs.base-ref != 'latest' with: ref: ${{ inputs.base-ref }} fetch-depth: 0 submodules: true - name: Checkout most recent tag run: git checkout "$(git describe --tags --abbrev=0 --match=v*)" if: inputs.base-ref == 'latest' - uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47 # v4 with: tool_versions: | semver 3.3.0 - run: | CURRENT_TAG=$(git describe --tags --abbrev=0 --match=v*) NEW_VERSION=$(semver bump "$BUMP_TYPE_INPUT" "$CURRENT_TAG") printf 'CURRENT_SHA=%s\n' "$(git rev-parse HEAD)" >> "$GITHUB_ENV" printf 'NEW_VERSION=%s\n' "$NEW_VERSION" >> "$GITHUB_ENV" env: BUMP_TYPE_INPUT: ${{ inputs.bump-type }} - name: Create branch uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9 with: script: | const branchName = `v${process.env.NEW_VERSION}`; console.log(`Creating branch: ${branchName}`); await github.request('POST /repos/{owner}/{repo}/git/refs', { owner: context.repo.owner, repo: context.repo.repo, ref: `refs/heads/${branchName}`, sha: process.env.CURRENT_SHA });
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.