Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 75 additions & 78 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,94 +1,91 @@
# Generated by labkit (python -m labkit gen). Do not edit by hand.
# Edit labs/<lab>/publish.config.json and regenerate; drift fails `labkit doctor`.
# Install into operatorstack/interlock at .github/workflows/release.yml (bootstrap step).
name: Release Interlock
# interlock release — rendered by distribution/render.mjs; hand-install into operatorstack/interlock's
# .github/workflows/ (control plane can't be projected). Builds prebuilt binaries + bindings and
# publishes them to GCP Artifact Registry (fronted by get.operatorstack.systems). No GitHub Releases.
#
# The AR project/location/repos come from repo VARIABLES (not hardcoded) so the private project id
# never lands in public source. Set on operatorstack/interlock:
# vars: WIF_PROVIDER, DEPLOYER_SA_EMAIL (the pkg-deployer SA),
# AR_PROJECT, AR_LOCATION, AR_GENERIC_REPO, AR_NPM_REPO, AR_PYTHON_REPO
name: release-interlock

on:
push:
branches: [main]
tags: ["v*"]
workflow_dispatch:
inputs:
bump:
description: Version bump for a manual release
type: choice
options: [patch, minor, major]
default: patch

permissions:
contents: write
pull-requests: read

concurrency:
group: release-interlock
cancel-in-progress: false
contents: read
id-token: write # Workload Identity Federation — no keys
attestations: write # build provenance

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: actions/setup-go@v5
with: { go-version: "stable" }
- uses: actions/setup-node@v4
with: { node-version: "22" }
- uses: actions/setup-python@v5
with: { python-version: "3.11" }

- id: auth
uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{ vars.WIF_PROVIDER }}
service_account: ${{ vars.DEPLOYER_SA_EMAIL }}
- uses: google-github-actions/setup-gcloud@v2

- name: build binaries + checksums + SBOM
uses: goreleaser/goreleaser-action@v6
with:
version: "~> v2"
args: release --clean

- name: attest build provenance
uses: actions/attest-build-provenance@v2
with:
fetch-depth: 0
- name: Resolve release policy
id: policy
env:
GH_TOKEN: ${{ github.token }}
MANUAL_BUMP: ${{ inputs.bump }}
shell: bash
subject-path: "dist/interlock_*.tar.gz, dist/interlock_*.zip, dist/checksums.txt"

- name: publish binaries -> Artifact Registry (generic)
run: |
bump="${MANUAL_BUMP:-patch}"
skip="false"
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
labels="$(gh api \
-H 'Accept: application/vnd.github+json' \
"/repos/${GITHUB_REPOSITORY}/commits/${GITHUB_SHA}/pulls" \
--jq '.[0].labels[].name' 2>/dev/null || true)"
if grep -qx 'skip-release' <<<"$labels"; then skip="true"; fi
if grep -qx 'major' <<<"$labels"; then
bump="major"
elif grep -qx 'minor' <<<"$labels"; then
bump="minor"
fi
fi
echo "bump=$bump" >> "$GITHUB_OUTPUT"
echo "skip=$skip" >> "$GITHUB_OUTPUT"
- name: Compute version
if: steps.policy.outputs.skip != 'true'
id: version
env:
BUMP: ${{ steps.policy.outputs.bump }}
shell: bash
set -euo pipefail
VER="${GITHUB_REF_NAME}"
for f in dist/interlock_*.tar.gz dist/interlock_*.zip dist/checksums.txt; do
[ -e "$f" ] || continue
gcloud artifacts generic upload \
--project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" \
--repository="${{ vars.AR_GENERIC_REPO }}" \
--package=interlock --version="${VER}" --source="$f"
done

- name: update latest channel manifest
run: |
latest="$(git tag --list 'v[0-9]*' --sort=-v:refname | head -n 1)"
if [[ -z "$latest" ]]; then
next="v0.1.0"
else
raw="${latest#v}"
IFS=. read -r major minor patch <<<"$raw"
case "$BUMP" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
*) echo "Invalid bump: $BUMP" >&2; exit 2 ;;
esac
next="v${major}.${minor}.${patch}"
fi
echo "version=$next" >> "$GITHUB_OUTPUT"
- name: Publish release
if: steps.policy.outputs.skip != 'true'
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.version.outputs.version }}
shell: bash
set -euo pipefail
printf '{"version":"%s"}\n' "${GITHUB_REF_NAME}" > latest.json
gcloud artifacts generic upload \
--project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" \
--repository="${{ vars.AR_GENERIC_REPO }}" \
--package=interlock-channel --version=latest --source=latest.json

- name: publish npm binding (@operatorstack/interlock)
working-directory: clients/typescript
run: |
set -euo pipefail
gcloud artifacts print-settings npm \
--project="${{ vars.AR_PROJECT }}" --location="${{ vars.AR_LOCATION }}" \
--repository="${{ vars.AR_NPM_REPO }}" --scope=@operatorstack > .npmrc
npx -y google-artifactregistry-auth .npmrc
npm publish

- name: publish python binding (interlock-protocol)
working-directory: clients/python
run: |
if git rev-parse --verify --quiet "refs/tags/$VERSION"; then
echo "Tag $VERSION already exists; nothing to release."
exit 0
fi
git tag "$VERSION" "$GITHUB_SHA"
git push origin "$VERSION"
gh release create "$VERSION" \
--repo "$GITHUB_REPOSITORY" \
--title "$VERSION" \
--generate-notes \
--verify-tag
set -euo pipefail
pip install --quiet build twine keyrings.google-artifactregistry-auth
python -m build
twine upload \
--repository-url "https://${{ vars.AR_LOCATION }}-python.pkg.dev/${{ vars.AR_PROJECT }}/${{ vars.AR_PYTHON_REPO }}/" \
dist/*
Loading