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
203 changes: 203 additions & 0 deletions .github/workflows/hsm-collector-registry-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
name: hsm-collector registry publish

# Automates publishing a new hsm-collector version into this repo's vcpkg registry, so there is no
# manual "recipe" to remember. Push a `collector-v<semver>` tag (or run this manually) and it:
# 1. computes the source tarball SHA512 for that tag,
# 2. updates ports/hsm-collector/ (portfile REF + SHA512, vcpkg.json version),
# 3. refreshes the version database (versions/),
# 4. builds+installs the updated port to prove it's valid, then
# 5. opens a PR to master.
#
# Scope / limits: publishes SOURCE versions only — a port-only fix (no source change) needs a manual
# port-version bump. Two publishes opened before either merges will conflict in versions/ (rebase the
# second). Build validation runs on Linux; the Windows/MSVC consumer path is the hsm-collector-registry
# check, which a human runs before merge (a GITHUB_TOKEN-opened PR doesn't auto-trigger it).
# Re-runs force-push the version's branch, so any manual commit pushed onto an open auto-PR is lost.

on:
push:
tags:
- 'collector-v*'
workflow_dispatch:
inputs:
version:
description: 'Version to publish, e.g. 0.6.3 (a matching collector-v<version> tag must already exist).'
required: true
dry_run:
description: 'Only compute + validate + show the diff; do not open a PR.'
type: boolean
default: true

permissions:
contents: write
pull-requests: write

# Serialize publishes so two tag pushes can't race on the shared version database.
concurrency:
group: hsm-collector-registry-publish
cancel-in-progress: false

jobs:
publish:
runs-on: ubuntu-latest
env:
VCPKG_DISABLE_METRICS: '1'
steps:
- uses: actions/checkout@v4
with:
ref: master
fetch-depth: 1

- name: Resolve + validate version
id: v
# Pass the dispatch input through env (never interpolate ${{ }} into the shell body — that
# would let an input like $(...) run on the runner). GITHUB_REF_NAME is already a safe env var.
env:
EVENT: ${{ github.event_name }}
INPUT_VERSION: ${{ github.event.inputs.version }}
run: |
set -euo pipefail
if [ "$EVENT" = "push" ]; then
tag="$GITHUB_REF_NAME"
else
tag="collector-v${INPUT_VERSION}"
fi
ver="${tag#collector-v}"
if ! printf '%s' "$ver" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::bad version '$ver' — expected X.Y.Z (tag collector-vX.Y.Z)"; exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "ver=$ver" >> "$GITHUB_OUTPUT"
echo "Publishing hsm-collector $ver (source tag $tag)"

- name: Compute source tarball SHA512
id: sha
env:
TAG: ${{ steps.v.outputs.tag }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
url="https://github.com/${REPO}/archive/${TAG}.tar.gz"
# Download to a file (with -f so a missing tag → non-zero exit under set -e) rather than piping
# curl into sha512sum, where a 404 would otherwise be hashed as an empty stream.
curl -fsSL --retry 3 --retry-connrefused --max-time 300 "$url" -o source.tgz
sha=$(sha512sum source.tgz | awk '{print $1}')
empty="cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"
if [ "${#sha}" -ne 128 ] || [ "$sha" = "$empty" ]; then
echo "::error::bad SHA512 for $url (does the tag exist?)"; exit 1
fi
rm -f source.tgz
echo "sha=$sha" >> "$GITHUB_OUTPUT"

- name: Prepare registry update
id: prep
env:
TAG: ${{ steps.v.outputs.tag }}
VER: ${{ steps.v.outputs.ver }}
SHA: ${{ steps.sha.outputs.sha }}
run: |
set -euo pipefail
br="registry/hsm-collector-${VER}"
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -b "$br"

sed -i -E "s|REF collector-v[0-9]+\.[0-9]+\.[0-9]+|REF ${TAG}|" ports/hsm-collector/portfile.cmake
sed -i -E "s|SHA512 [0-9a-f]{128}|SHA512 ${SHA}|" ports/hsm-collector/portfile.cmake
sed -i -E "s|(\"version\"[[:space:]]*:[[:space:]]*\")[0-9]+\.[0-9]+\.[0-9]+(\")|\1${VER}\2|" ports/hsm-collector/vcpkg.json

# Commit the port first so the recorded git-tree is the NEW port content.
git add ports/hsm-collector
git commit -q -m "vcpkg registry: publish hsm-collector ${VER}"
tree=$(git rev-parse "HEAD:ports/hsm-collector")

VER="$VER" TREE="$tree" python3 - <<'PY'
import json, os, sys
ver, tree = os.environ['VER'], os.environ['TREE']
f = 'versions/h-/hsm-collector.json'
d = json.load(open(f))
# vcpkg version->git-tree mappings are immutable. If this version is already published with a
# DIFFERENT tree (e.g. its source tag was recreated with new content), refuse — bump instead.
existing = next((e for e in d['versions'] if e.get('version') == ver), None)
if existing and existing.get('git-tree') != tree:
print(f"::error::hsm-collector {ver} is already published with git-tree "
f"{existing['git-tree']}; refusing to rewrite it to {tree}. Bump the version.")
sys.exit(1)
b = json.load(open('versions/baseline.json'))
cur = b['default']['hsm-collector'].get('baseline', '0.0.0')
semver = lambda v: tuple(int(x) for x in v.split('.'))
# Only ADVANCE the baseline. A strictly newer version resets port-version; re-publishing the
# SAME baseline version leaves port-version alone (a manual port-only bump must not be
# clobbered); an OLDER version (backport) still gets its versions/ entry (below) but never
# rolls the default that consumers resolve backward.
if semver(ver) > semver(cur):
b['default']['hsm-collector']['baseline'] = ver
b['default']['hsm-collector']['port-version'] = 0
with open('versions/baseline.json', 'w') as fh:
json.dump(b, fh, indent=2); fh.write('\n')
elif semver(ver) < semver(cur):
print(f"::warning::published {ver}, but the baseline stays at {cur} (newer) — not rolling back.")
else: # ver == cur: baseline already correct; leave baseline.json (and its port-version) alone.
if b['default']['hsm-collector'].get('port-version', 0):
print(f"::warning::re-published {ver} while baseline port-version is "
f"{b['default']['hsm-collector']['port-version']}; the versions/ entry records port-version 0. "
f"Port-only changes need a manual port-version bump (see the header note).")
# Idempotent (pre-merge re-runs): drop any existing entry for this version, then prepend it
# (newest-first — the sanity-check step's `grep ... | head -1` relies on this ordering).
d['versions'] = [e for e in d['versions'] if e.get('version') != ver]
d['versions'].insert(0, {"version": ver, "git-tree": tree})
with open(f, 'w') as fh:
json.dump(d, fh, indent=2); fh.write('\n')
PY

# Fold versions/ into the same commit (ports/ tree — and thus the recorded git-tree — is
# unchanged by touching versions/).
git add versions
git commit -q --amend --no-edit
echo "branch=$br" >> "$GITHUB_OUTPUT"

- name: Sanity-check version DB git-tree
env:
VER: ${{ steps.v.outputs.ver }}
run: |
set -euo pipefail
# Read the git-tree recorded for THIS version (order-independent — not `head -1`).
recorded=$(python3 -c "import json,os; d=json.load(open('versions/h-/hsm-collector.json')); print(next(e['git-tree'] for e in d['versions'] if e['version']==os.environ['VER']))")
actual=$(git rev-parse "HEAD:ports/hsm-collector")
echo "recorded=$recorded actual=$actual"
[ "$recorded" = "$actual" ]

- name: Set up vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgGitCommitId: 6f29f12e82a8293156836ad81cc9bf5af41fe836

- name: Validate the updated port builds + installs
# Proves the refreshed SHA512 + REF actually resolve and the collector builds from them, so the
# PR is known-good even though (see below) the separate registry check won't auto-run on it.
env:
VCPKG_BINARY_SOURCES: clear
run: |
"$VCPKG_ROOT/vcpkg" install "hsm-collector[http]" --overlay-ports=ports

- name: Show the computed change
run: git show --stat HEAD

- name: Open PR
if: github.event_name == 'push' || github.event.inputs.dry_run == 'false'
env:
GH_TOKEN: ${{ github.token }}
BR: ${{ steps.prep.outputs.branch }}
VER: ${{ steps.v.outputs.ver }}
run: |
set -euo pipefail
git push -f -u origin "$BR"
# Check for an OPEN PR explicitly (gh pr view also resolves merged/closed ones) rather than
# masking every gh failure with `|| echo`.
if [ -n "$(gh pr list --head "$BR" --state open --json number --jq '.[].number')" ]; then
echo "A PR for $BR is already open; pushed the refreshed branch to it."
else
gh pr create --base master --head "$BR" \
--title "vcpkg registry: hsm-collector ${VER}" \
--body "Automated by \`hsm-collector-registry-publish\`: the port now fetches \`collector-v${VER}\` (SHA512 refreshed) and the version DB is updated. The updated port was **built + installed on Linux in the publish run** (validates the SHA512/REF resolve and the collector compiles with \`[http]\`). The consumer-facing **hsm-collector-registry** check is Windows/MSVC and does NOT auto-run on a \`GITHUB_TOKEN\` PR — **run it manually** (Actions -> hsm-collector-registry -> Run workflow on this branch) before merging to cover the Windows path."
fi
Loading