Skip to content

Release

Release #14

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
release_type:
description: Release type
required: true
type: choice
options:
- prep
- rc
- stable
version:
description: "Version number (e.g. 0.11.0)"
required: true
type: string
rc_number:
description: "RC number (e.g. 1) — required for RC releases, must be empty for prep"
required: false
type: string
permissions:
contents: write
issues: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
environment: release
env:
POETRY: poetry
steps:
- name: Restrict to release managers
if: github.actor != 'yyyyyyyan' && github.actor != 'maxbube'
run: |
echo "::error::Only release managers (yyyyyyyan, maxbube) can trigger this workflow."
exit 1
- name: Validate inputs
env:
RELEASE_TYPE: ${{ inputs.release_type }}
VERSION: ${{ inputs.version }}
RC_NUMBER: ${{ inputs.rc_number }}
run: |
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "::error::version must match X.Y.Z (e.g. 0.11.0)"
exit 1
fi
if [ "$RELEASE_TYPE" = "rc" ]; then
if [ -z "$RC_NUMBER" ]; then
echo "::error::rc_number is required when release_type is 'rc'"
exit 1
fi
if ! [[ "$RC_NUMBER" =~ ^[1-9][0-9]*$ ]]; then
echo "::error::rc_number must be a positive integer"
exit 1
fi
fi
if [ "$RELEASE_TYPE" = "prep" ] && [ -n "$RC_NUMBER" ]; then
echo "::error::rc_number must be empty when release_type is 'prep'"
exit 1
fi
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: ${{ inputs.release_type == 'stable' && format('release/v{0}', inputs.version) || 'main' }}
fetch-depth: 0
token: ${{ secrets.RELEASE_PAT }}
- name: Configure git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Checkout release branch if it exists
if: inputs.release_type == 'rc'
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
ls_remote_status=0
git ls-remote --exit-code --heads origin "release/v${VERSION}" >/dev/null 2>&1 || ls_remote_status=$?
if [ "$ls_remote_status" -eq 0 ]; then
git fetch origin "release/v${VERSION}:release/v${VERSION}"
git checkout "release/v${VERSION}"
echo "Gates will run against release/v${VERSION} (cherries included)."
elif [ "$ls_remote_status" -eq 2 ]; then
echo "release/v${VERSION} does not exist yet (rc1-fresh path); gates run against main."
else
echo "::error::git ls-remote failed (exit ${ls_remote_status}); cannot determine whether release/v${VERSION} exists. Aborting so gates don't silently run against the wrong target."
exit 1
fi
- name: Setup Python
uses: ./.github/actions/setup-python-job
with:
python-version: "3.11"
- name: Pre-tag lint gate (all-files pre-commit)
run: make run-pre-commit
- name: Pre-tag security audit (bandit + pip-audit)
run: make audit
- name: Pre-tag migration check
env:
CASDOOR__CLIENT_SECRET: notatoken
CASDOOR__CLIENT_ID: notatoken
run: make checkmigrations
- name: Run release
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT }}
GH_PR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TYPE: ${{ inputs.release_type }}
VERSION: ${{ inputs.version }}
RC_NUMBER: ${{ inputs.rc_number }}
JIRA_VERSION_CREATE_WEBHOOK_URL: ${{ secrets.JIRA_VERSION_CREATE_WEBHOOK_URL }}
JIRA_VERSION_CREATE_WEBHOOK_SECRET: ${{ secrets.JIRA_VERSION_CREATE_WEBHOOK_SECRET }}
JIRA_VERSION_RELEASE_WEBHOOK_URL: ${{ secrets.JIRA_VERSION_RELEASE_WEBHOOK_URL }}
JIRA_VERSION_RELEASE_WEBHOOK_SECRET: ${{ secrets.JIRA_VERSION_RELEASE_WEBHOOK_SECRET }}
run: |
if [ "$RELEASE_TYPE" = "rc" ]; then
make release-rc VERSION="$VERSION" RC="$RC_NUMBER" SIGN_VIA_API=1
elif [ "$RELEASE_TYPE" = "prep" ]; then
make release-prep VERSION="$VERSION" SIGN_VIA_API=1
else
make release-stable VERSION="$VERSION" SIGN_VIA_API=1
fi
- name: Assert back-merge ancestor invariant
if: ${{ inputs.release_type == 'stable' }}
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
git fetch origin main
if ! git merge-base --is-ancestor "v${VERSION}" origin/main; then
echo "::error::Post-release invariant failed: v${VERSION} is NOT an ancestor of origin/main. The back-merge in cmd_stable did not land. Investigate before re-running."
exit 1
fi
echo "OK: v${VERSION} is an ancestor of origin/main."