Skip to content

Release

Release #68

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
version:
description: "New version, for example 0.4.13"
required: true
type: string
permissions:
contents: write
packages: write
concurrency:
group: workout-relay-release
cancel-in-progress: false
jobs:
release:
name: Validate and publish release
runs-on: ubuntu-latest
steps:
- name: Checkout main
uses: actions/checkout@v5
with:
ref: main
fetch-depth: 0
- name: Normalize and validate version
id: version
shell: bash
run: |
VERSION="${{ inputs.version }}"
VERSION="${VERSION#v}"
if ! echo "$VERSION" |
grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "Invalid version: $VERSION"
echo "Use semantic versioning, for example: 0.4.13"
exit 1
fi
TAG="v$VERSION"
git fetch origin main --tags
if git rev-parse "refs/tags/$TAG" \
>/dev/null 2>&1; then
echo "Tag $TAG already exists"
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "tag=$TAG" >> "$GITHUB_OUTPUT"
- name: Prepare release commit and tag
id: release-commit
shell: bash
run: |
VERSION="${{ steps.version.outputs.version }}"
TAG="${{ steps.version.outputs.tag }}"
git config user.name "github-actions[bot]"
git config user.email \
"41898282+github-actions[bot]@users.noreply.github.com"
echo "$VERSION" > boot/version
git add boot/version
if git diff --cached --quiet; then
echo "boot/version already contains $VERSION"
exit 1
fi
git commit -m "Release $TAG [skip ci]"
git tag -a "$TAG" -m "Release $TAG"
RELEASE_SHA="$(git rev-parse HEAD)"
echo "sha=$RELEASE_SHA" >> "$GITHUB_OUTPUT"
- name: Set up Java
uses: actions/setup-java@v5
with:
distribution: corretto
java-version: "21"
cache: gradle
cache-dependency-path: |
boot/*.gradle*
boot/gradle/wrapper/gradle-wrapper.properties
- name: Make Gradle wrapper executable
working-directory: boot
run: chmod +x gradlew
- name: Run backend tests
working-directory: boot
run: ./gradlew clean test --no-daemon
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: "22.23.1"
cache: npm
cache-dependency-path: ui/package-lock.json
- name: Install frontend dependencies
working-directory: ui
run: npm ci
- name: Build frontend
working-directory: ui
run: npm run build
- name: Run frontend tests
working-directory: ui
run: >
npm test --
--watch=false
--browsers=ChromeHeadless
- name: Verify main has not changed
shell: bash
run: |
git fetch origin main
RELEASE_BASE="$(git rev-parse HEAD^)"
REMOTE_MAIN="$(git rev-parse origin/main)"
if [ "$RELEASE_BASE" != "$REMOTE_MAIN" ]; then
echo "main changed while the release was running"
echo "Expected: $RELEASE_BASE"
echo "Current: $REMOTE_MAIN"
exit 1
fi
- name: Set Docker image name
id: image
shell: bash
run: |
IMAGE="ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/workout-relay"
echo "image=$IMAGE" >> "$GITHUB_OUTPUT"
- name: Login to GHCR
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Build and push Docker image
uses: docker/build-push-action@v7
with:
context: .
push: true
tags: |
${{ steps.image.outputs.image }}:${{ steps.version.outputs.version }}
${{ steps.image.outputs.image }}:${{ steps.release-commit.outputs.sha }}
${{ steps.image.outputs.image }}:latest
labels: |
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.version=${{ steps.version.outputs.version }}
org.opencontainers.image.revision=${{ steps.release-commit.outputs.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Push release commit and tag
shell: bash
run: |
TAG="${{ steps.version.outputs.tag }}"
git push \
--atomic \
origin \
HEAD:main \
"$TAG"
- name: Create GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
run: |
gh release create \
"${{ steps.version.outputs.tag }}" \
--verify-tag \
--title "${{ steps.version.outputs.tag }}" \
--generate-notes