ci(publish): wire Scoop bucket + Homebrew tap jobs (D3 §3b/§3c)
Add sibling publish.yaml jobs (scoop-bucket, homebrew-tap) that render a manifest from the release .sha256 sidecars and idempotently push it to the org-level lazyeval/scoop-bucket and lazyeval/homebrew-tap repos, using the scoped lazyeval-ci bot token (LAZYEVAL_PKG_TOKEN). Render logic lives in dependency-free bash (the CI image has no jq/ruby): scripts/render-scoop-manifest.sh and scripts/render-homebrew-formula.sh. scripts/test-package-renders.sh exercises both: it validates the Scoop JSON with node and asserts fields on both manifests, and additionally runs `ruby -c` on the formula where ruby is present (dev box), skipping it gracefully otherwise. A new ci.yaml `manifests` job runs that test on every push so a render regression surfaces immediately, not at the next manual publish dispatch. The CI image has no ruby, so in CI the gate covers the Scoop JSON (node) and field assertions for both manifests; the formula's Ruby syntax is checked dev-side only (the static heredoc's variable parts cannot introduce syntax errors). - Scoop: x64 (gnu) + arm64 (gnullvm); #/-rename fragment so the bin shim is version-stable; checkver, no autoupdate (the pipeline is the updater). - Homebrew: on_macos/on_linux x arch bare-binary formula; no Windows. Docs: ADR-0056 Amendment 2 (+ README index, requirements D3). Unverified pending real use: scoop/brew install, the HEAD:main branch assumption, macOS Gatekeeper-via-brew on the ad-hoc-signed binary.
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
# was enabled once the tree was reformatted on main (ADR-ci-002 Amendment 1 /
|
||||
# issue #35). The release job (static binary for D2) and the platform matrix
|
||||
# layer on later, step by step.
|
||||
#
|
||||
# A separate, lightweight `manifests` job logic-tests the package-manifest
|
||||
# render scripts (Scoop/Homebrew) used by publish.yaml — bash + node only, no
|
||||
# toolchain — so a render regression surfaces on the breaking push rather than
|
||||
# weeks later at the next manual publish dispatch (ADR-0056 Amendment 2).
|
||||
name: ci
|
||||
on:
|
||||
push:
|
||||
@@ -46,3 +51,21 @@ jobs:
|
||||
run: nix develop -c cargo clippy --all-targets -- -D warnings
|
||||
- name: test
|
||||
run: nix develop -c cargo test --no-fail-fast
|
||||
|
||||
# Logic test for the package-manifest render scripts. Renders with DUMMY
|
||||
# inputs and validates the output — it never publishes or touches the lazyeval
|
||||
# repos (that is publish.yaml's manual job). Runs on the same image but skips
|
||||
# nix: it needs only bash + node, both in the base image.
|
||||
#
|
||||
# NOTE: the CI image has no ruby, so the script's `ruby -c` formula syntax
|
||||
# check is skipped here (it degrades gracefully); the Scoop JSON is still
|
||||
# validated with node and both manifests' fields are asserted. Full formula
|
||||
# syntax is checked dev-side (ruby present) on every pre-commit local run.
|
||||
manifests:
|
||||
runs-on: ci-public
|
||||
container:
|
||||
image: git.lazyeval.net/oli/rdbms-playground-ci:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: render-script tests (Scoop + Homebrew)
|
||||
run: bash scripts/test-package-renders.sh
|
||||
|
||||
@@ -71,9 +71,133 @@ jobs:
|
||||
nix develop -c cargo publish --locked
|
||||
echo "published rdbms-playground $VER to crates.io."
|
||||
|
||||
# Future manual publication targets go here as independent, idempotent jobs,
|
||||
# e.g.:
|
||||
# scoop-bucket: { ... update the lazyeval Scoop bucket manifest ... }
|
||||
# homebrew-tap: { ... update the lazyeval Homebrew formula ... }
|
||||
# winget: { ... komac submit, or a manual PR helper ... }
|
||||
# No `needs:` between them — each checks the target and skips if already done.
|
||||
# Update the lazyeval Scoop bucket (Windows). Renders the manifest from the
|
||||
# release's .sha256 sidecars and commits it to lazyeval/scoop-bucket. Pushes
|
||||
# with the lazyeval-ci bot token (LAZYEVAL_PKG_TOKEN), which is scoped — via
|
||||
# the bot's org-team membership — to the lazyeval package repos only, so a
|
||||
# leak cannot touch oli/rdbms-playground.
|
||||
scoop-bucket:
|
||||
runs-on: ci-public
|
||||
container:
|
||||
image: git.lazyeval.net/oli/rdbms-playground-ci:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4 # default ref (main) — current render script
|
||||
|
||||
- name: update the lazyeval Scoop bucket (idempotent)
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ inputs.tag }}
|
||||
# Passed via env, never inlined into the script, so the value stays
|
||||
# masked in logs; it only materialises in the clone URL at runtime.
|
||||
PKG_TOKEN: ${{ secrets.LAZYEVAL_PKG_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VER="${TAG#v}"
|
||||
echo "scoop: targeting rdbms-playground $VER ($TAG)"
|
||||
|
||||
base="https://git.lazyeval.net/oli/rdbms-playground/releases/download/$TAG"
|
||||
fetch_hash() {
|
||||
local asset="$1" line
|
||||
echo "scoop: fetching $asset.sha256" >&2
|
||||
line=$(curl -fsSL "$base/$asset.sha256") \
|
||||
|| { echo "ERROR: cannot fetch $asset.sha256 — is $TAG released with assets?" >&2; exit 1; }
|
||||
# First whitespace-delimited field is the hash. `read` is a bash
|
||||
# builtin (no awk, which the slim CI image may lack).
|
||||
local hash _
|
||||
read -r hash _ <<<"$line"
|
||||
printf '%s' "$hash"
|
||||
}
|
||||
h_x64=$(fetch_hash "rdbms-playground-$TAG-x86_64-pc-windows-gnu.exe")
|
||||
h_arm=$(fetch_hash "rdbms-playground-$TAG-aarch64-pc-windows-gnullvm.exe")
|
||||
|
||||
echo "scoop: rendering manifest"
|
||||
bash scripts/render-scoop-manifest.sh "$VER" "$h_x64" "$h_arm" > /tmp/rdbms-playground.json
|
||||
node -e 'JSON.parse(require("fs").readFileSync("/tmp/rdbms-playground.json","utf8"))' \
|
||||
|| { echo "ERROR: rendered Scoop manifest is not valid JSON" >&2; exit 1; }
|
||||
|
||||
work=$(mktemp -d)
|
||||
echo "scoop: cloning lazyeval/scoop-bucket"
|
||||
git clone --depth 1 "https://lazyeval-ci:${PKG_TOKEN}@git.lazyeval.net/lazyeval/scoop-bucket.git" "$work"
|
||||
cp /tmp/rdbms-playground.json "$work/rdbms-playground.json"
|
||||
|
||||
cd "$work"
|
||||
git config user.name "lazyeval-ci"
|
||||
git config user.email "ci@lazyeval.net"
|
||||
git add rdbms-playground.json
|
||||
if git diff --cached --quiet; then
|
||||
echo "scoop: manifest already at $VER — nothing to commit."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "rdbms-playground $VER"
|
||||
# Push to main explicitly: a freshly-created (empty) repo clone may put
|
||||
# the first commit on a differently-named local branch. Assumes the
|
||||
# bucket/tap default branch is `main` (Gitea's default for new repos).
|
||||
git push origin HEAD:main
|
||||
echo "scoop: bucket updated to rdbms-playground $VER."
|
||||
|
||||
# Update the lazyeval Homebrew tap (macOS + Linux). Same shape as scoop-bucket;
|
||||
# writes Formula/rdbms-playground.rb into lazyeval/homebrew-tap.
|
||||
homebrew-tap:
|
||||
runs-on: ci-public
|
||||
container:
|
||||
image: git.lazyeval.net/oli/rdbms-playground-ci:latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: update the lazyeval Homebrew tap (idempotent)
|
||||
shell: bash
|
||||
env:
|
||||
TAG: ${{ inputs.tag }}
|
||||
PKG_TOKEN: ${{ secrets.LAZYEVAL_PKG_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
VER="${TAG#v}"
|
||||
echo "homebrew: targeting rdbms-playground $VER ($TAG)"
|
||||
|
||||
base="https://git.lazyeval.net/oli/rdbms-playground/releases/download/$TAG"
|
||||
fetch_hash() {
|
||||
local asset="$1" line
|
||||
echo "homebrew: fetching $asset.sha256" >&2
|
||||
line=$(curl -fsSL "$base/$asset.sha256") \
|
||||
|| { echo "ERROR: cannot fetch $asset.sha256 — is $TAG released with assets?" >&2; exit 1; }
|
||||
# First whitespace-delimited field is the hash. `read` is a bash
|
||||
# builtin (no awk, which the slim CI image may lack).
|
||||
local hash _
|
||||
read -r hash _ <<<"$line"
|
||||
printf '%s' "$hash"
|
||||
}
|
||||
mac_arm=$(fetch_hash "rdbms-playground-$TAG-aarch64-apple-darwin")
|
||||
mac_x64=$(fetch_hash "rdbms-playground-$TAG-x86_64-apple-darwin")
|
||||
lin_arm=$(fetch_hash "rdbms-playground-$TAG-aarch64-unknown-linux-musl")
|
||||
lin_x64=$(fetch_hash "rdbms-playground-$TAG-x86_64-unknown-linux-musl")
|
||||
|
||||
echo "homebrew: rendering formula"
|
||||
bash scripts/render-homebrew-formula.sh "$VER" "$mac_arm" "$mac_x64" "$lin_arm" "$lin_x64" \
|
||||
> /tmp/rdbms-playground.rb
|
||||
grep -q '^class RdbmsPlayground < Formula$' /tmp/rdbms-playground.rb \
|
||||
|| { echo "ERROR: rendered formula looks malformed" >&2; exit 1; }
|
||||
|
||||
work=$(mktemp -d)
|
||||
echo "homebrew: cloning lazyeval/homebrew-tap"
|
||||
git clone --depth 1 "https://lazyeval-ci:${PKG_TOKEN}@git.lazyeval.net/lazyeval/homebrew-tap.git" "$work"
|
||||
mkdir -p "$work/Formula"
|
||||
cp /tmp/rdbms-playground.rb "$work/Formula/rdbms-playground.rb"
|
||||
|
||||
cd "$work"
|
||||
git config user.name "lazyeval-ci"
|
||||
git config user.email "ci@lazyeval.net"
|
||||
git add Formula/rdbms-playground.rb
|
||||
if git diff --cached --quiet; then
|
||||
echo "homebrew: formula already at $VER — nothing to commit."
|
||||
exit 0
|
||||
fi
|
||||
git commit -m "rdbms-playground $VER"
|
||||
# Push to main explicitly: a freshly-created (empty) repo clone may put
|
||||
# the first commit on a differently-named local branch. Assumes the
|
||||
# bucket/tap default branch is `main` (Gitea's default for new repos).
|
||||
git push origin HEAD:main
|
||||
echo "homebrew: tap updated to rdbms-playground $VER."
|
||||
|
||||
# winget remains a future sibling job here (komac on Linux CI, or a manual PR
|
||||
# to microsoft/winget-pkgs). No `needs:` between jobs — each is independent and
|
||||
# idempotent, so one failing or being added never breaks another.
|
||||
|
||||
Reference in New Issue
Block a user