133 lines
4.7 KiB
YAML
133 lines
4.7 KiB
YAML
name: Unraid stable release deployment
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
release_tag:
|
|
description: Annotated stable release tag (for example, v1.2.1)
|
|
required: true
|
|
type: string
|
|
release_commit:
|
|
description: Exact lowercase 40-character commit SHA referenced by the tag
|
|
required: true
|
|
type: string
|
|
action:
|
|
description: Verify provenance only, or deploy the verified stable release
|
|
required: true
|
|
default: VERIFY_ONLY
|
|
type: choice
|
|
options:
|
|
- VERIFY_ONLY
|
|
- DEPLOY_STABLE_TO_PRODUCTION
|
|
|
|
concurrency:
|
|
group: unraid-production-itworx-modelforge
|
|
cancel-in-progress: false
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
deploy:
|
|
name: Verify and optionally deploy a stable release
|
|
runs-on: unraid-deploy
|
|
timeout-minutes: 180
|
|
steps:
|
|
- name: Validate immutable dispatch inputs
|
|
shell: bash
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.release_tag }}
|
|
RELEASE_COMMIT: ${{ inputs.release_commit }}
|
|
DEPLOY_ACTION: ${{ inputs.action }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
if [[ "${GITHUB_REF:-}" != "refs/heads/master" ]]; then
|
|
echo "Stable production deployment must be dispatched from refs/heads/master" >&2
|
|
exit 2
|
|
fi
|
|
if [[ ! "${RELEASE_TAG}" =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
|
|
echo "release_tag must be a strict stable SemVer tag such as v1.2.1" >&2
|
|
exit 2
|
|
fi
|
|
if [[ ! "${RELEASE_COMMIT}" =~ ^[0-9a-f]{40}$ ]]; then
|
|
echo "release_commit must be an exact lowercase 40-character SHA" >&2
|
|
exit 2
|
|
fi
|
|
case "${DEPLOY_ACTION}" in
|
|
VERIFY_ONLY|DEPLOY_STABLE_TO_PRODUCTION) ;;
|
|
*) echo "action is not allowlisted: ${DEPLOY_ACTION}" >&2; exit 2 ;;
|
|
esac
|
|
|
|
- name: Check out the exact release commit with full history
|
|
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
with:
|
|
ref: ${{ inputs.release_commit }}
|
|
fetch-depth: 0
|
|
# The following provenance step performs an authenticated exact-ref fetch.
|
|
persist-credentials: true
|
|
|
|
- name: Verify stable release provenance
|
|
shell: bash
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.release_tag }}
|
|
RELEASE_COMMIT: ${{ inputs.release_commit }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
git fetch --force --no-recurse-submodules origin \
|
|
"refs/tags/${RELEASE_TAG}:refs/tags/${RELEASE_TAG}" \
|
|
"refs/heads/master:refs/remotes/origin/master"
|
|
|
|
tag_ref="refs/tags/${RELEASE_TAG}"
|
|
if [[ "$(git cat-file -t "${tag_ref}")" != "tag" ]]; then
|
|
echo "${RELEASE_TAG} must be an annotated tag" >&2
|
|
exit 1
|
|
fi
|
|
|
|
tag_object="$(git rev-parse "${tag_ref}^{tag}")"
|
|
tag_commit="$(git rev-parse "${tag_ref}^{commit}")"
|
|
head_commit="$(git rev-parse HEAD)"
|
|
if [[ "${tag_commit}" != "${RELEASE_COMMIT}" ]]; then
|
|
echo "Tag commit ${tag_commit} does not match release_commit ${RELEASE_COMMIT}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "${head_commit}" != "${RELEASE_COMMIT}" ]]; then
|
|
echo "Checked-out HEAD ${head_commit} does not match release_commit ${RELEASE_COMMIT}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! -f VERSION ]]; then
|
|
echo "VERSION is missing at the release commit" >&2
|
|
exit 1
|
|
fi
|
|
version="$(tr -d '\r\n' < VERSION)"
|
|
expected_version="${RELEASE_TAG#v}"
|
|
if [[ "${version}" != "${expected_version}" ]]; then
|
|
echo "VERSION ${version} does not match release tag ${RELEASE_TAG}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! git merge-base --is-ancestor "${RELEASE_COMMIT}" refs/remotes/origin/master; then
|
|
echo "Release commit ${RELEASE_COMMIT} is not an ancestor of origin/master" >&2
|
|
exit 1
|
|
fi
|
|
|
|
printf 'DEPLOY_COMMIT=%s\n' "${RELEASE_COMMIT}" >> "${GITHUB_ENV}"
|
|
echo "Verified annotated ${RELEASE_TAG} object ${tag_object} at immutable commit ${RELEASE_COMMIT}"
|
|
|
|
- name: Verification-only result
|
|
if: ${{ inputs.action == 'VERIFY_ONLY' }}
|
|
shell: bash
|
|
run: echo "Stable release provenance verified; production was not changed."
|
|
|
|
- name: Deploy verified stable release to production
|
|
if: ${{ inputs.action == 'DEPLOY_STABLE_TO_PRODUCTION' }}
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
test -n "${DEPLOY_COMMIT:-}"
|
|
docker exec gitea-deploy-control \
|
|
/opt/gitea-deploy/deploy.py deploy \
|
|
"${GITHUB_REPOSITORY}" "${DEPLOY_COMMIT}"
|