Skip to content

Release

Release #16

Workflow file for this run

name: Release
on:
workflow_dispatch:
inputs:
version:
description: Exact next release version without the v prefix
required: true
type: string
increment:
description: Select minor only with explicit user authorization; otherwise next patch
required: true
type: choice
default: patch
options:
- patch
- minor
startup_receipt:
description: JSON receipt from the exact approved static package's headed cold and warm-upgrade movie/menu/playable-frame gate
required: false
type: string
package_run_id:
description: Successful Prepare release package run on this exact main commit; download and test its artifact before releasing
required: true
type: string
waive_v0012_startup_receipt:
description: Explicitly authorized v0.0.12-only startup receipt waiver; asset and binding checks remain mandatory
required: false
type: boolean
default: false
permissions:
contents: write
actions: read
concurrency:
group: playsrc-production-release
cancel-in-progress: false
jobs:
release:
name: Deploy latest main
runs-on: ubuntu-latest
timeout-minutes: 60
environment: production
steps:
- name: Check out latest main
uses: actions/checkout@v6
with:
ref: main
fetch-depth: 0
- name: Set up Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: canary
- name: Resolve release identity
id: release
shell: bash
env:
VERSION: ${{ inputs.version }}
INCREMENT: ${{ inputs.increment }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
latest="$(gh release view --json tagName --jq .tagName)"
git ls-remote --tags --refs origin | sed 's|.*refs/tags/||' | bun tools/playsrc/src/release-version.ts "$VERSION" "${latest#v}" "$INCREMENT"
tag="v${VERSION}"
sha="$(git rev-parse HEAD)"
remote_sha="$(git ls-remote origin refs/heads/main | cut -f1)"
if [[ "$sha" != "$remote_sha" ]]; then
echo "checked out commit is not latest main" >&2
exit 2
fi
existing_tag="$(git ls-remote origin "refs/tags/${tag}" | cut -f1)"
if [[ -n "$existing_tag" ]]; then
echo "${tag} already exists" >&2
exit 2
fi
if gh release view "$tag" >/dev/null 2>&1; then
echo "${tag} already has a GitHub Release" >&2
exit 2
fi
notes="apps/web/tf2/releases/notes/${tag}.md"
if [[ ! -s "$notes" ]]; then
echo "authored release notes are missing: ${notes}" >&2
exit 2
fi
if [[ "$(head -n 1 "$notes")" != "# playsrc ${tag}" ]]; then
echo "release notes must begin with # playsrc ${tag}" >&2
exit 2
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
echo "sha=${sha}" >> "$GITHUB_OUTPUT"
echo "notes=${notes}" >> "$GITHUB_OUTPUT"
- name: Set up Terraform
uses: hashicorp/setup-terraform@v4.0.1
with:
terraform_version: 1.15.8
terraform_wrapper: false
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Authenticate prepared artifact source
env:
PACKAGE_RUN_ID: ${{ inputs.package_run_id }}
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
[[ "$PACKAGE_RUN_ID" =~ ^[1-9][0-9]*$ ]]
gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${PACKAGE_RUN_ID}" | bun tools/playsrc/src/release-package-run.ts "$(git rev-parse HEAD)" "$GITHUB_REPOSITORY"
- name: Download the exact tested package
uses: actions/download-artifact@v8
with:
name: tf2-release-package
path: apps/web/tf2/dist/cloudflare
run-id: ${{ inputs.package_run_id }}
github-token: ${{ github.token }}
- name: Verify accepted bytes before any production operation
run: bun tools/playsrc/src/cli.ts verify release-package
env:
PLAYSRC_STATIC_STARTUP_RECEIPT: ${{ inputs.startup_receipt }}
PLAYSRC_RELEASE_VERSION: ${{ inputs.version }}
- name: Bootstrap Terraform state
run: bun run infra:bootstrap
env:
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- name: Deploy production
run: bun run infra:deploy
env:
PLAYSRC_STATIC_STARTUP_RECEIPT: ${{ inputs.startup_receipt }}
PLAYSRC_RELEASE_VERSION: ${{ inputs.version }}
PLAYSRC_WAIVE_V0012_STARTUP_RECEIPT: ${{ inputs.waive_v0012_startup_receipt }}
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_ZONE_ID: ${{ vars.CLOUDFLARE_ZONE_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
AWS_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_SECRET_ACCESS_KEY }}
- name: Create tag
if: success()
shell: bash
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.release.outputs.tag }}
SHA: ${{ steps.release.outputs.sha }}
run: |
set -euo pipefail
if ! git ls-remote --exit-code origin "refs/tags/${TAG}" >/dev/null 2>&1; then
gh api "repos/${GITHUB_REPOSITORY}/git/refs" \
--method POST \
--field "ref=refs/tags/${TAG}" \
--field "sha=${SHA}" >/dev/null
fi
- name: Create GitHub Release
if: success()
shell: bash
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.release.outputs.tag }}
RELEASE_NOTES: ${{ steps.release.outputs.notes }}
run: |
set -euo pipefail
gh release create "$TAG" \
"apps/web/tf2/dist/cloudflare/release.json#Cloudflare deployment manifest" \
--verify-tag \
--notes-file "$RELEASE_NOTES" \
--title "playsrc ${TAG}"