name: Release
on:
workflow_dispatch:
inputs:
level:
description: Release level
required: true
type: choice
default: patch
options:
- major
- minor
- patch
- version
version:
description: Version to release (if level is "version"), for example 1.0.0
required: false
type: string
permissions:
actions: write
contents: write
jobs:
release:
name: Prepare the release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: main
fetch-depth: 0
- name: Select the release version
env:
LEVEL: ${{ inputs.level }}
VERSION_INPUT: ${{ inputs.version }}
run: |
set -euo pipefail
if [ "$LEVEL" = "version" ]; then
version="${VERSION_INPUT#v}"
else
latest="$(git tag -l 'v*' --sort=-v:refname | head -n1)"
latest="${latest:-v0.0.0}"
[[ "$latest" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]] || { echo "invalid latest tag: $latest" >&2; exit 1; }
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
case "$LEVEL" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
*) echo "invalid release level: $LEVEL" >&2; exit 1 ;;
esac
version="${major}.${minor}.${patch}"
fi
[[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "invalid release version: $version" >&2; exit 1; }
echo "VERSION=$version" >> "$GITHUB_ENV"
echo "TAG=v$version" >> "$GITHUB_ENV"
- name: Set the workspace version
run: |
set -euo pipefail
current="$(awk '
/^\[/ { in_package = ($0 == "[workspace.package]") }
in_package && /^version = "/ { gsub(/^version = "|"$/, ""); print; exit }
' Cargo.toml)"
[ -n "$current" ] || { echo "Cargo.toml has no [workspace.package] version" >&2; exit 1; }
if [ "$current" != "$VERSION" ]; then
sed -i \
-e "s/^version = \"${current}\"\$/version = \"${VERSION}\"/" \
-e "s/version = \"=${current}\"/version = \"=${VERSION}\"/" \
Cargo.toml
if grep -q "\"=${current}\"" Cargo.toml; then
echo "Cargo.toml still pins a crate to ${current}" >&2
exit 1
fi
fi
- name: Promote the changelog
run: |
set -euo pipefail
if grep -q "^## ${VERSION} - " CHANGELOG.md; then
exit 0
fi
grep -q '^## Unreleased$' CHANGELOG.md || { echo "CHANGELOG.md has no ## Unreleased section" >&2; exit 1; }
awk -v heading="## ${VERSION} - $(date -u +%Y-%m-%d)" '
!done && $0 == "## Unreleased" { print; print ""; print heading; done = 1; next }
{ print }
' CHANGELOG.md > "$RUNNER_TEMP/CHANGELOG.md"
mv "$RUNNER_TEMP/CHANGELOG.md" CHANGELOG.md
- name: Push the release commit and tag
run: |
set -euo pipefail
git config user.name 'github-actions[bot]'
git config user.email '41898282+github-actions[bot]@users.noreply.github.com'
git add Cargo.toml CHANGELOG.md
if ! git diff --cached --quiet; then
git commit -m "Release zvidlib ${VERSION}"
git push origin HEAD:main
fi
if ! git ls-remote --exit-code --tags origin "refs/tags/${TAG}" > /dev/null 2>&1; then
git tag "$TAG"
git push origin "$TAG"
fi
- name: Start Finalize release
env:
GH_TOKEN: ${{ github.token }}
run: gh workflow run finalize-release.yml --repo "$GITHUB_REPOSITORY" --ref "$TAG" -f tag="$TAG"