Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 56 additions & 46 deletions .github/workflows/create-release-tag.yml
Original file line number Diff line number Diff line change
@@ -1,91 +1,101 @@
name: Create release tag
run-name: Create ${{ inputs.release_type }} release tag

# Tags master as soon as the version in package.json changes, whether the bump
# came from the "Prepare release" workflow or was pushed by hand. Editing the
# version field in an unrelated pull request therefore ships a release: it is
# not a casually editable field.
on:
workflow_dispatch:
inputs:
release_type:
description: 'Type of version bump'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
push:
branches:
- master
paths:
- package.json
Comment thread
cursor[bot] marked this conversation as resolved.

permissions:
contents: write
# Needed to dispatch the release workflows on the new tag.
actions: write

# Two overlapping runs would bump from the same tip and race on the same tag.
concurrency:
group: create-release-tag
cancel-in-progress: false

jobs:
create-release-tag:
name: Bump version and push tag
name: Tag the new version
runs-on: ubuntu-latest
steps:
- name: 🛑 Ensure workflow runs on master
if: github.ref != 'refs/heads/master'
env:
REF_NAME: ${{ github.ref_name }}
run: |
echo "::error::This workflow can only be run on master, got ${REF_NAME}."
exit 1
- name: ⬇️ Checkout Gladys code
uses: actions/checkout@v4
with:
# Always release from the current tip of master, not from the commit
# master pointed at when the workflow was dispatched.
ref: master
fetch-depth: 0
- name: 💽 Setup nodejs
uses: actions/setup-node@v4
with:
node-version-file: './package.json'
- name: 🔍 Read the version to tag
id: version
run: |
TAG="v$(node -p "require('./package.json').version")"
# package.json also changes for plain dependency updates: only an
# unreleased version is worth tagging. An empty output skips the
# remaining steps.
TAGGED_COMMIT=$(git rev-parse -q --verify "refs/tags/${TAG}^{commit}" || true)
if [ -z "${TAGGED_COMMIT}" ]; then
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
echo "create=true" >> "$GITHUB_OUTPUT"
elif [ "${TAGGED_COMMIT}" = "${GITHUB_SHA}" ]; then
# The tag was created by an earlier attempt on this very commit, which
# then failed. Keep going, without recreating it, so re-running the job
# replays the dispatches it never reached.
echo "Tag ${TAG} already points at this commit, replaying the dispatches."
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
else
echo "Tag ${TAG} already exists on another commit, nothing to release."
fi
- name: 🔧 Configure git
if: steps.version.outputs.create
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: 🔖 Bump version and create tag
id: bump
env:
RELEASE_TYPE: ${{ inputs.release_type }}
run: |
NEW_VERSION=$(npm version "${RELEASE_TYPE}")
echo "version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
echo "Created tag ${NEW_VERSION}"
- name: 🚀 Push commit and tag
- name: 🔖 Create and push the tag
if: steps.version.outputs.create
env:
NEW_VERSION: ${{ steps.bump.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
run: |
git push --atomic origin master "refs/tags/${NEW_VERSION}"
git tag -a "${TAG}" -m "${TAG}"
git push origin "refs/tags/${TAG}"
- name: 🎬 Trigger the release workflows
if: steps.version.outputs.tag
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
NEW_VERSION: ${{ steps.bump.outputs.version }}
TAG: ${{ steps.version.outputs.tag }}
run: |
# A tag pushed with the default GITHUB_TOKEN does not trigger the
# workflows listening on `push: tags`, so they are dispatched explicitly
# on the new tag. workflow_dispatch is one of the two events GitHub does
# start from a GITHUB_TOKEN, which is why no PAT is needed here.
for workflow in docker-release-build.yml build-demo-website.yml build-apidoc-documentation.yml; do
echo "Triggering ${workflow} on ${NEW_VERSION}"
gh workflow run "${workflow}" --ref "${NEW_VERSION}"
echo "Triggering ${workflow} on ${TAG}"
# The tag was pushed a second ago and may not be visible to the API yet.
for attempt in 1 2 3; do
if gh workflow run "${workflow}" --ref "${TAG}"; then
break
fi
if [ "${attempt}" = 3 ]; then
echo "::error::Could not dispatch ${workflow} on ${TAG}. Re-run this job to replay the dispatches."
exit 1
fi
echo "Dispatch failed, retrying in 5s (attempt ${attempt}/3)"
sleep 5
done
done
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: 📝 Job summary
if: steps.version.outputs.tag
env:
NEW_VERSION: ${{ steps.bump.outputs.version }}
RELEASE_TYPE: ${{ inputs.release_type }}
TAG: ${{ steps.version.outputs.tag }}
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
run: |
{
echo "### 🚀 Release ${NEW_VERSION} created"
echo "### 🚀 Release ${TAG} created"
echo ""
echo "- Bump type: \`${RELEASE_TYPE}\`"
echo "- Tag: [\`${NEW_VERSION}\`](${{ github.server_url }}/${{ github.repository }}/releases/tag/${NEW_VERSION})"
echo "- Tag: [\`${TAG}\`](${REPO_URL}/releases/tag/${TAG})"
echo "- Release workflows dispatched on the tag: production images, demo website, apidoc"
} >> "$GITHUB_STEP_SUMMARY"
100 changes: 100 additions & 0 deletions .github/workflows/prepare-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Prepare release
run-name: Prepare ${{ inputs.release_type }} release

on:
workflow_dispatch:
inputs:
release_type:
description: 'Type of version bump'
required: true
default: 'patch'
type: choice
options:
- patch
- minor

permissions:
contents: write

# Two overlapping runs would bump from the same tip and race on the same version.
concurrency:
group: prepare-release
cancel-in-progress: false

jobs:
prepare-release:
name: Bump version on a release branch
runs-on: ubuntu-latest
steps:
- name: 🛑 Ensure workflow runs on master
if: github.ref != 'refs/heads/master'
env:
REF_NAME: ${{ github.ref_name }}
run: |
echo "::error::This workflow can only be run on master, got ${REF_NAME}."
exit 1
- name: ⬇️ Checkout Gladys code
uses: actions/checkout@v4
with:
# Always release from the current tip of master, not from the commit
# master pointed at when the workflow was dispatched.
ref: master
fetch-depth: 0
- name: 💽 Setup nodejs
uses: actions/setup-node@v4
with:
node-version-file: './package.json'
- name: 🔧 Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: 🔖 Bump version on a release branch
id: bump
env:
RELEASE_TYPE: ${{ inputs.release_type }}
run: |
npm version "${RELEASE_TYPE}" --no-git-tag-version
VERSION=$(node -p "require('./package.json').version")
TAG="v${VERSION}"
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
echo "::error::Tag ${TAG} already exists, master may not have been released yet."
exit 1
fi
BRANCH="release/${TAG}"
if git ls-remote --exit-code --heads origin "${BRANCH}" >/dev/null 2>&1; then
echo "::error::Branch ${BRANCH} already exists, from an abandoned release."
echo "::error::Reuse its pull request, or delete the branch and run this workflow again."
exit 1
fi
git switch -c "${BRANCH}"
git add package.json package-lock.json
# Version-only commit message, as every release commit before it.
git commit -m "${VERSION}"
git push origin "${BRANCH}"
Comment thread
cursor[bot] marked this conversation as resolved.
{
echo "version=${VERSION}"
echo "tag=${TAG}"
echo "branch=${BRANCH}"
} >> "$GITHUB_OUTPUT"
- name: 📝 Job summary
env:
TAG: ${{ steps.bump.outputs.tag }}
BRANCH: ${{ steps.bump.outputs.branch }}
RELEASE_TYPE: ${{ inputs.release_type }}
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
run: |
{
echo "### 📦 Release ${TAG} ready for review"
echo ""
echo "- Bump type: \`${RELEASE_TYPE}\`"
echo "- Branch: [\`${BRANCH}\`](${REPO_URL}/tree/${BRANCH})"
echo ""
echo "**[👉 Open the release pull request](${REPO_URL}/compare/master...${BRANCH}?expand=1)**"
echo ""
echo "The pull request has to be opened by a human: GitHub does not run the"
echo "required checks on a pull request opened by the \`GITHUB_TOKEN\`, so an"
echo "automatically opened one would stay blocked on them forever."
echo ""
echo "Once it is merged, the \`Create release tag\` workflow tags \`${TAG}\` on"
echo "master and starts the production images, demo website and apidoc builds."
} >> "$GITHUB_STEP_SUMMARY"
Loading