cast/.github/workflows/ci.yml
claude-bot-andresmgsl 76926785f5 feat(release): consume the shared ceremony at 0.1.0 — callers, artifact hook, labels.conf
The 250-line release.yml becomes the caller stub (version-source:
package-json — the backend's first exercise); the prebuilt-asset build
moves into .github/actions/release-artifact/ per ceremony#9's hook
contract (setup-node moves into the hook — the shared workflow is
node-free). labels.yml becomes its caller; the panel and cast's six
scope rows extract into .github/labels.conf (data only — the parser
refuses comment lines). ci.yml swaps the guard script steps for the
pinned actions and adds changelog-armed (cast regains the guard
reverted in cast#108) and docs-sync. The four shared scripts die;
test/labels-reconcile.sh dies with the reconciler it sourced
(machinery test files go whole — rig #13's rule).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 13:57:10 +00:00

99 lines
4.3 KiB
YAML

name: ci
on:
push:
branches: [main]
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
# changelog-monotonic compares HEAD against the merge base; a
# checkout that cannot resolve it is a hard failure in CI, not
# a skip (a guard that can quietly stop guarding is the failure
# shape this repo keeps refusing).
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
# the secrets tests round-trip a real age identity
- run: sudo apt-get update && sudo apt-get install -y age
- run: npm ci
- run: npm run check
- run: npm run build
- run: npm test
- name: installer is valid bash
run: bash -n install.sh bin/cast scripts/*.sh .github/scripts/*.sh
# `bash -n` above is a syntax check on a hand-maintained list; it is not
# a linter and it does not notice a script it was never told about.
# This sweep derives its list from git and asserts the list covers every
# tracked *.sh, so a new script cannot go unlinted quietly (#118).
- name: shellcheck — every tracked shell script
run: bash .github/scripts/shellcheck-all.sh
# The release guards, doctrine in heavy-duty/ceremony's README
# (ceremony#15 is this conversion). Each guard's war story — why it
# exists, what it refuses — lives with its implementation upstream;
# the four pins below and the two workflow callers must always name
# the same ceremony tag.
#
# changelog-armed: the version-keyed arming rule (rig#66 is the
# incident; the unconditional form cast#108 reverted — this is its
# correct return).
- uses: heavy-duty/ceremony/actions/changelog-armed@0.1.0
with:
version-source: package-json
# changelog-monotonic: no shipped heading deleted or duplicated
# (#133; box#122's guard, box#143's ordering fix). Strict by default:
# an unresolvable base ref is red, never a quiet skip — hence the
# fetch-depth: 0 above.
- uses: heavy-duty/ceremony/actions/changelog-monotonic@0.1.0
# drill-recorded: a release version carries drills/<version>.md
# (cast's drill meaning: drills/README.md). Vacuous on -dev trees; it
# requires a RECORD, not a pass — a maintainer waiver is legal, and
# is itself the content of the file.
- uses: heavy-duty/ceremony/actions/drill-recorded@0.1.0
with:
version-source: package-json
# docs-sync: the .ceremony/ doctrine mirror is byte-identical to the
# pin read from release.yml (ceremony#19) — a hand edit or a
# half-done pin bump goes red here.
- uses: heavy-duty/ceremony/actions/docs-sync@0.1.0
# The installer, proven by RUNNING it — CAST_INSTALL_SOURCE points it at
# this checkout, so CI proves the installer under review (the versioned
# layout, the current symlink, the PATH chain, the uninstall's absence
# assert), not a hand-built imitation of it. Box's CI installs box the
# same way. This is the one place the real npm ci + tsc build path runs
# end to end; the vitest installer tests cover the layout semantics
# offline with a shimmed npm.
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
- name: install via install.sh, from this checkout
run: |
CAST_NO_MODIFY_PATH=1 CAST_INSTALL_SOURCE="$GITHUB_WORKSPACE" bash install.sh
# assert what landed: the layout, the chain, and that it answers
readlink -f "$HOME/.local/bin/cast" | grep '/versions/'
"$HOME/.local/bin/cast" --version
"$HOME/.local/bin/cast" versions
- name: converging no-op — a re-run changes nothing and builds nothing
run: |
CAST_NO_MODIFY_PATH=1 CAST_INSTALL_SOURCE="$GITHUB_WORKSPACE" bash install.sh \
| tee /tmp/rerun.log
grep -q 'already installed' /tmp/rerun.log
- name: uninstall --all — ends with the absence assert
run: |
CAST_YES=1 "$HOME/.local/bin/cast" uninstall --all
test ! -e "$HOME/.local/share/cast"
test ! -e "$HOME/.local/bin/cast"
test ! -L "$HOME/.local/bin/cast"