mirror of
https://github.com/gastownhall/beads.git
synced 2026-09-14 20:17:24 +08:00
935afe2466
* fix(examples): tidy both example modules and build them in CI
Both Go modules under examples/ fail a plain `go build` on current main:
go: updates to go.mod needed; to update it:
go mod tidy
They are separate modules that reach the parent through
`replace github.com/steveyegge/beads => ../..`, so their go.mod and go.sum
record the parent's entire dependency graph. Every root dependency change
therefore invalidates them — and nothing in CI ever compiled them, so the drift
accumulated silently. examples/ is the first code a new user copies, which makes
this a bad first five minutes rather than a cosmetic wart.
Two parts:
1. `go mod tidy` in examples/bd-example-extension-go and examples/library-usage.
The extension example carries most of the churn (~1.6k lines of go.sum),
which is inherent to recording the parent graph through the replace directive
and is why an earlier fix (#4942, the Go 1.26.5 bump) deliberately left it
out. Both modules now build clean with the project's canonical
`-tags gms_pure_go`.
2. scripts/build-examples.sh plus a `build-examples` job in the PR workflow, so
the same drift cannot recur unnoticed. The script discovers example modules
from `git ls-files 'examples/*/go.mod'` (no hardcoded list), sources
.buildflags for the canonical CGO/tag settings, builds into a scratch
directory so it leaves no untracked binaries, reports every failing module
rather than stopping at the first, and prints the exact `go mod tidy`
command to run.
The job is deliberately NOT added to ci-gate's required list. Because of the
replace directive it would fail on any root go.mod change not mirrored into the
examples, so making it blocking imposes a "tidy the examples too" step on every
dependency bump. That is a maintainer call about contributor friction; the job
is visible on the checks list either way, and pr.yml records how to promote it.
Verified locally: both modules build with -tags gms_pure_go; the script exits 1
and names the module when an example go.mod is reverted to its pre-tidy state;
scripts/check-build-tags.sh stays clean (the script sources .buildflags).
Agent-Signature: claude-opus-5-high on behalf of matt wilkie
* fix(examples): address dual-vendor review — vet not build, advisory job, portability
Reviewed by a claude reviewer and scripts/codex-agent reviewer (gpt-5.6-sol).
Four fixes, two of them correctness.
1. `go build -o <dir>/ ./...` was a FALSE GREEN: with -o naming a directory, Go
compiles only the MAIN packages and silently skips every library package.
Reproduced in an isolated module with a good main package plus a library
package containing a type error — `go build -o dir/ ./...` exits 0 while
`go build ./...` and `go vet ./...` both exit 1. The mirror-image bug: a
library-only example module fails `go build` with "no main packages to
build", a false red. Switched to `go vet ./...`, which type-checks every
package INCLUDING test files (examples/library-usage/main_test.go exercises
a lot of live API, and `go mod tidy` counts its imports, so a build that
never compiles it left part of the recorded graph unverified), writes no
artifacts, and still fails on the stale-go.mod condition this exists for.
That also deletes the mktemp/trap/scratch-dir machinery entirely.
2. "Not in ci-gate" is NOT "non-blocking", which the previous comment claimed.
Verified in source: pr-preflight.sh gates on every FAILURE in the raw
statusCheckRollup and calls block(), and pr-babysit requires all rollup
entries SUCCESS/NEUTRAL/SKIPPED before merging. Both ignore ci-gate
membership. So the previous state was the one posture that stalls the merge
patrol repo-wide after any un-mirrored dependency bump while advertising
itself as optional. The job is now continue-on-error: true — genuinely
advisory — and the comment records how to promote it to a real gate. Whether
it SHOULD be a gate remains the maintainers' call.
3. Portability and robustness in the script, all reproduced by the reviewers:
- `mapfile` does not exist in bash 3.2 (stock macOS) and `xargs -r` is
GNU-only, so the advertised local check could not run on macOS. Replaced
with a NUL-delimited read loop, which also fixes module paths containing
whitespace (`git ls-files | xargs -n1 dirname` turned "examples/has
space/go.mod" into two bogus entries).
- `source ./.buildflags` was unguarded under `set -uo pipefail`; a failure
continued with GOFLAGS unset and would type-check the ICU path while
check-build-tags.sh still passed, since that only greps for the literal
string. Now a hard exit.
- Finding zero modules exited 0. A job that checks nothing must not report
success; it is now an error.
Verified: both modules vet clean; reverting an example go.mod to its pre-tidy
state still exits 1 with the exact `go mod tidy` command; a broken library
package now fails where it previously passed; check-build-tags.sh clean
(97 files); shellcheck clean.
Agent-Signature: claude-opus-5-high on behalf of matt wilkie
* fix(examples): drop GNU-only sort -z from the module discovery pipeline
BSD sort has no -z, so on stock macOS — the exact platform the Bash-3.2
compatibility block targets — the sort stage emptied the pipeline and the
script exited claiming 'found no example modules'. git ls-files output is
already sorted, so the stage bought nothing. Found by cross-vendor review
(codex gpt-5.6-sol) of this branch.
Agent-Signature: claude-fable-5-high on behalf of maphew
* fix(ci,examples): disable setup-go cache in build-examples; re-tidy examples after merge
TestGoCacheOwnershipTopology requires every setup-go step in pr.yml to set
cache: false (caching is owned by explicit restore/save steps); the new
build-examples job predates that policy landing on main. Also re-run
go mod tidy in both example modules so their recorded dependency graphs
match the merged main — exactly the drift this PR's CI job exists to catch.
Agent-Signature: claude-fable-5-high on behalf of maphew
* ci(examples): bound build-examples with timeout-minutes: 10
continue-on-error keeps a red result advisory, but a hung job at the
6-hour default timeout holds the check pending, stalling merge-lane
consumers the advisory posture was meant to protect. Matches
pr-preflight-platforms' bound.
Agent-Signature: claude-fable-5-high on behalf of maphew
* ci(examples): make the advisory posture real - step-level continue-on-error
Job-level continue-on-error still reports the check run as FAILURE in the
PR rollup (only the workflow-run conclusion flips), and pr-preflight /
pr-babysit gate on per-check-run conclusions - so the job as written was
de facto blocking while advertising itself advisory. Follow the cygwin-leg
precedent: continue-on-error on the build step, outcome-guarded ::warning
annotation on failure. Also restore the repo-wide Go module cache (the
examples' graph is the parent's via the replace directive) so the job
stops cold-downloading the full dependency graph on every PR.
Agent-Signature: claude-fable-5-high on behalf of maphew
* test: register build-examples' module-cache restore in the cache topology registry
TestGoCacheOwnershipTopology keeps an explicit inventory of every cache
step per job; the advisory-lane fix added a restore step to build-examples
without registering it, so the whole scripts package went red on this
head. Register the job (inventory, managed map, ordering, setup-go id)
and drop the step's unused 'restore-cache' id — the registry compares
ids, and nothing references it.
Agent-Signature: claude-fable-5-high on behalf of maphew
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019CwiLhLbAGZdJtKYT76CPp
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1314 lines
55 KiB
YAML
1314 lines
55 KiB
YAML
name: PR
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [ main ]
|
|
merge_group:
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
BD_DISABLE_METRICS: "1"
|
|
BD_DISABLE_EVENT_FLUSH: "1"
|
|
|
|
jobs:
|
|
|
|
build-artifacts:
|
|
name: Build Artifacts
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Restore non-race Go build cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/go-cache/non-race
|
|
key: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-${{ github.sha }}
|
|
restore-keys: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-
|
|
|
|
- name: Build reusable Linux artifacts
|
|
env:
|
|
GOCACHE: ${{ runner.temp }}/go-cache/non-race
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p artifacts
|
|
source ./.buildflags
|
|
go_version="$(go version)"
|
|
commit="$(git rev-parse HEAD)"
|
|
go build -tags "$BEADS_BUILD_TAGS" -o artifacts/bd-linux-gms-pure ./cmd/bd
|
|
chmod +x artifacts/bd-linux-gms-pure
|
|
(
|
|
cd artifacts
|
|
sha256sum bd-linux-gms-pure > SHA256SUMS
|
|
)
|
|
{
|
|
echo "commit=${commit}"
|
|
echo "go_version=${go_version}"
|
|
echo "build_tags=${BEADS_BUILD_TAGS}"
|
|
echo "artifact=bd-linux-gms-pure"
|
|
} > artifacts/build-manifest.txt
|
|
|
|
- name: Upload build artifacts
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: ci-build-artifacts
|
|
path: artifacts/
|
|
retention-days: 1
|
|
if-no-files-found: error
|
|
|
|
# examples/ holds separate Go modules that reach the parent through a
|
|
# `replace` directive, so their go.mod/go.sum record the parent's whole
|
|
# dependency graph and go stale whenever the root module's does. Nothing in
|
|
# CI compiled them, so that drift was invisible: on 2026-08-01 BOTH example
|
|
# modules failed a plain `go build` on main with "updates to go.mod needed".
|
|
# Examples are the first code a new user copies; this keeps them buildable.
|
|
#
|
|
# Advisory on purpose, and NOT in ci-gate's required list.
|
|
#
|
|
# Because of the `replace` directive, any root go.mod change that is not
|
|
# mirrored into the examples fails this job. Whether that should block a merge
|
|
# is a maintainer call about contributor friction, so this PR does not make it
|
|
# one. Advisory has to be implemented at the STEP level: a job-level
|
|
# continue-on-error job still reports its check run as FAILURE in the PR
|
|
# rollup (only the workflow-run conclusion turns success), and pr-preflight
|
|
# and the pr-babysit merge patrol gate on per-check-run conclusions — so a
|
|
# job-level red here would stall the merge lane repo-wide while claiming to
|
|
# be optional. Step-level continue-on-error (the cygwin-leg precedent below)
|
|
# keeps the check run green and surfaces failures as warning annotations.
|
|
#
|
|
# To promote it to a real gate: drop the step's continue-on-error and the
|
|
# warning step, then add `build-examples` to ci-gate's `needs`,
|
|
# `CI_GATE_REQUIRED`, and its env map.
|
|
build-examples:
|
|
name: Build example modules
|
|
runs-on: ubuntu-latest
|
|
# No job-level timeout on purpose: a job-level timeout CANCELS the job,
|
|
# and a cancelled advisory job is a red check run — blocking again by a
|
|
# different door. Instead every step below carries its own
|
|
# timeout-minutes AND continue-on-error, so a hang or failure anywhere
|
|
# (setup download stall, cache stall, build hang) degrades to a warning
|
|
# annotation while the job itself always concludes green.
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
id: checkout
|
|
continue-on-error: true
|
|
timeout-minutes: 5
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
continue-on-error: true
|
|
timeout-minutes: 5
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
# The examples' dependency graph is the parent module's (via the
|
|
# `replace` directive), so the repo-wide module cache key is a
|
|
# near-perfect hit; without it this job cold-downloads the whole
|
|
# dolt-sized graph on every PR.
|
|
- name: Restore Go module cache
|
|
continue-on-error: true
|
|
timeout-minutes: 5
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Type-check every module under examples/
|
|
id: build-examples
|
|
if: steps.checkout.outcome == 'success' && steps.setup-go.outcome == 'success'
|
|
continue-on-error: true
|
|
timeout-minutes: 10
|
|
run: ./scripts/build-examples.sh
|
|
|
|
- name: Warn when example modules are stale or fail to build
|
|
if: steps.build-examples.outcome == 'failure'
|
|
run: |
|
|
echo "::warning title=Example modules out of date::examples/ failed to type-check against this tree. Run 'go mod tidy' in each module under examples/ (see scripts/build-examples.sh output above). Advisory only; this does not block the merge."
|
|
|
|
- name: Warn when the advisory job could not run at all
|
|
if: steps.checkout.outcome != 'success' || steps.setup-go.outcome != 'success'
|
|
run: |
|
|
echo "::warning title=Example build check skipped::checkout or Go setup failed, so examples/ could not be checked this run (checkout: ${{ steps.checkout.outcome }}, setup-go: ${{ steps.setup-go.outcome }}). Advisory only; this does not block the merge."
|
|
|
|
# Fast check: every `go build|test|run|generate|install` invocation in
|
|
# tracked scripts/hooks/CI carries -tags=gms_pure_go. Prevents ICU-linkage
|
|
# regressions from re-entering the build (see engdocs/ICU-POLICY.md).
|
|
check-build-tags:
|
|
name: Check build-tag policy
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
- run: ./scripts/check-build-tags.sh
|
|
- run: ./scripts/check-go-install-guidance.sh
|
|
|
|
# Lock in two CGO-disabled portability boundaries. cmd/bd carries a mix of
|
|
# cgo-only test helpers (embedded Dolt, sql.DB) and pure-Go tests; compiling
|
|
# and running its pure-Go subset prevents test contamination (mybd-ycx /
|
|
# GH#3683 follow-up). internal/hooks also declares a js/wasm boundary where
|
|
# process execution must fail explicitly, so this required leaf job compiles
|
|
# the complete package test binary and executes that exact contract under
|
|
# Node rather than allowing a missing platform implementation to recur.
|
|
check-cmd-bd-puregeo-tests:
|
|
name: Check pure-Go and js/wasm boundaries (CGO_ENABLED=0)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
|
with:
|
|
node-version: '24'
|
|
|
|
- name: Run js/wasm hook boundary
|
|
env:
|
|
CGO_ENABLED: "0"
|
|
GOARCH: wasm
|
|
GOOS: js
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
# This required lane owns the exact js/wasm refusal contract. If the
|
|
# wasm test surface grows, widen this selector and its count guard
|
|
# together rather than assuming compilation executes new tests.
|
|
test_status=0
|
|
test_output="$(go test -tags gms_pure_go -count=1 -timeout=2m \
|
|
-exec="$(go env GOROOT)/lib/wasm/go_js_wasm_exec" \
|
|
-run '^TestRunHookReportsUnsupportedExecution$' \
|
|
-v ./internal/hooks 2>&1)" || test_status=$?
|
|
printf '%s\n' "$test_output"
|
|
(( test_status == 0 )) || exit "$test_status"
|
|
|
|
run_count=0
|
|
pass_count=0
|
|
nonpass_count=0
|
|
pass_pattern='^--- PASS: TestRunHookReportsUnsupportedExecution \([0-9.]+s\)$'
|
|
nonpass_pattern='^[[:space:]]*--- (FAIL|SKIP): '
|
|
while IFS= read -r line; do
|
|
if [[ "$line" == "=== RUN TestRunHookReportsUnsupportedExecution" ]]; then
|
|
((run_count += 1))
|
|
fi
|
|
if [[ "$line" =~ $pass_pattern ]]; then
|
|
((pass_count += 1))
|
|
fi
|
|
if [[ "$line" =~ $nonpass_pattern ]]; then
|
|
((nonpass_count += 1))
|
|
fi
|
|
done <<< "$test_output"
|
|
if (( run_count != 1 || pass_count != 1 || nonpass_count != 0 )); then
|
|
printf 'expected one exact js/wasm hook test run and pass with no failures or skips; got runs=%s passes=%s nonpasses=%s\n' \
|
|
"$run_count" "$pass_count" "$nonpass_count" >&2
|
|
exit 1
|
|
fi
|
|
|
|
- name: Build cmd/bd (CGO_ENABLED=0, gms_pure_go)
|
|
env:
|
|
CGO_ENABLED: "0"
|
|
run: go build -tags gms_pure_go -o /tmp/bd-puregeo ./cmd/bd
|
|
|
|
- name: Compile pure-Go test binaries (CGO_ENABLED=0, gms_pure_go)
|
|
env:
|
|
CGO_ENABLED: "0"
|
|
run: |
|
|
go test -tags gms_pure_go -c -o /tmp/bd-cmd-puregeo-test ./cmd/bd
|
|
go test -tags gms_pure_go -c -o /tmp/bd-embeddeddolt-puregeo-test ./internal/storage/embeddeddolt
|
|
go test -tags gms_pure_go -c -o /tmp/bd-tracker-puregeo-test ./internal/tracker
|
|
|
|
- name: Run pure-Go cmd/bd test subset (CGO_ENABLED=0)
|
|
env:
|
|
CGO_ENABLED: "0"
|
|
# Restrict to tests that exercise pure-Go code paths. Tests that
|
|
# need a Dolt store skip themselves at runtime when no test server
|
|
# is available; the goal here is to catch compile-time contamination,
|
|
# not run the full suite.
|
|
run: |
|
|
go test -tags gms_pure_go -count=1 -short -run '^Test(Help|CheckRemoteSafety|FormatDestroyToken|ShouldWireInitRemote|ExtractPrefix|IsNumericID|GetWorktreeGitDir|DriftItemStatuses|RunDriftChecks|IsServerProbablyRunning|CheckHooksDriftNotGitRepo|CheckServerDriftNoBeadsDir|CheckRemoteDriftNoBeadsDir)' ./cmd/bd
|
|
|
|
# The lingering-handle liveness regression test is //go:build windows: the
|
|
# Ubuntu job above selects it by name but compiles it out, and main.yml's
|
|
# Windows job runs only on pushes to main (build/smoke, no go test). Run
|
|
# exactly the liveness pair on windows-latest so the regression guard
|
|
# actually executes at PR time.
|
|
test-windows-liveness:
|
|
name: Test (Windows) cmd/bd liveness regression
|
|
runs-on: windows-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Run Windows liveness regression test
|
|
run: go test -tags gms_pure_go -count=1 -run '^TestIsServerProbablyRunning' ./cmd/bd
|
|
|
|
# Destructive worktree removal depends on native Windows path identity.
|
|
# This focused process suite requires NTFS per-directory case sensitivity
|
|
# and fails (rather than skips) when the runner cannot provide it.
|
|
worktree-remove-windows:
|
|
name: Worktree remove boundary (Windows)
|
|
runs-on: windows-latest
|
|
timeout-minutes: 15
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Restore non-race Go build cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/go-cache/non-race
|
|
key: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-${{ github.sha }}
|
|
restore-keys: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-
|
|
|
|
- name: Run native Windows worktree removal boundary tests
|
|
env:
|
|
CGO_ENABLED: "0"
|
|
GOCACHE: ${{ runner.temp }}/go-cache/non-race
|
|
run: go test -tags gms_pure_go -count=1 -run '^TestWorktreeRemove' ./cmd/bd
|
|
|
|
# Fast check to ensure all version files are in sync
|
|
check-version-consistency:
|
|
name: Check version consistency
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Check all versions match
|
|
run: ./scripts/check-versions.sh
|
|
|
|
# Migration hygiene: duplicate version numbers, nondeterministic SQL
|
|
# (UUID()/NOW()/RAND(), the #4259 root-cause class), and edits to migration
|
|
# files that already exist on the base branch (shipped migrations are
|
|
# frozen; fix forward with a new version). Fails at PR time, before any
|
|
# test even compiles. Details: scripts/check-migration-hygiene.sh.
|
|
check-migration-hygiene:
|
|
name: Check migration hygiene
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Run migration hygiene checks
|
|
env:
|
|
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
|
|
run: ./scripts/check-migration-hygiene.sh
|
|
|
|
# Check documentation references match actual CLI flags
|
|
check-doc-flags:
|
|
name: Check doc flags freshness
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
# Full history so check-cli-docs-drift.sh can regenerate docs at the
|
|
# merge-base and only fail PRs for drift they actually introduced.
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Build bd
|
|
run: CGO_ENABLED=0 go build -tags gms_pure_go -o bd ./cmd/bd/
|
|
|
|
- name: Validate docs against CLI
|
|
env:
|
|
DOC_DRIFT_PATCH_OUT: ${{ runner.temp }}/cli-docs-freshness.patch
|
|
run: |
|
|
./scripts/check-doc-flags.sh ./bd
|
|
./scripts/check-doc-freshness.sh
|
|
|
|
# When the drift check fails, it writes the exact regenerated-docs fix
|
|
# (produced with CI's canonical build) so contributors can apply it with
|
|
# `git apply` instead of reproducing CI's environment locally. The
|
|
# docs-autofix.yml workflow_run job consumes this same artifact to push
|
|
# the fix to same-repo PR branches automatically.
|
|
- name: Upload docs fix patch
|
|
if: failure()
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
with:
|
|
name: cli-docs-freshness-patch
|
|
path: ${{ runner.temp }}/cli-docs-freshness.patch
|
|
if-no-files-found: ignore
|
|
|
|
check-doc-freshness-platforms:
|
|
name: Check doc freshness (${{ matrix.os }})
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 10
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: ubuntu-latest
|
|
expected_goos: linux
|
|
- os: macos-latest
|
|
expected_goos: darwin
|
|
- os: windows-latest
|
|
expected_goos: windows
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Exercise native date and Bash process boundary
|
|
run: go test '-tags=integration,gms_pure_go' -count=1 -run '^TestDocFreshness' ./scripts
|
|
|
|
- name: Exercise repository text EOL policy boundary
|
|
run: go test '-tags=integration,gms_pure_go' -count=1 ./scripts/gitattributespolicy -args -required-host -expected-goos '${{ matrix.expected_goos }}'
|
|
|
|
pr-preflight-platforms:
|
|
name: PR preflight process (${{ matrix.os }})
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 20
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Exercise the real Bash process boundary
|
|
shell: bash
|
|
run: go test '-tags=integration,gms_pure_go' -count=1 -run '^TestPRPreflight' ./scripts
|
|
|
|
- name: Exercise test.sh prebuilt binary path
|
|
shell: bash
|
|
run: go test '-tags=gms_pure_go' -count=1 -run '^TestTestScriptPrebuiltBinaryContract$' ./scripts
|
|
|
|
- name: Exercise generated Git hook timeout process boundary
|
|
shell: bash
|
|
run: go test '-tags=gms_pure_go' -count=1 -run '^TestGeneratedHookTimeoutProcessBoundary$' ./cmd/bd
|
|
|
|
- name: Check benchmark environment scrubbing
|
|
if: matrix.os == 'windows-latest'
|
|
shell: bash
|
|
run: go test -tags gms_pure_go -count=1 -run '^(TestCleanEnvUsesHostKeySemantics|TestBenchmarkCommandBuildersStripDoltEnvOverrides)$' ./scripts/repro-dolt-prod-timeouts
|
|
|
|
# Fast check to catch accidental .beads/issues.jsonl changes from contributors
|
|
check-no-beads-changes:
|
|
name: Check for .beads changes
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'pull_request'
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Check for .beads/issues.jsonl changes
|
|
run: |
|
|
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -q "^\.beads/issues\.jsonl$"; then
|
|
echo "This PR includes changes to .beads/issues.jsonl"
|
|
echo ""
|
|
echo "This file is the project's issue database and should not be modified in PRs."
|
|
echo ""
|
|
echo "To fix, run:"
|
|
echo " git checkout origin/main -- .beads/issues.jsonl"
|
|
echo " git commit --amend"
|
|
echo " git push --force"
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
echo "No .beads/issues.jsonl changes detected"
|
|
|
|
detect-package-gates:
|
|
name: Detect package gates
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
mcp_package: ${{ steps.detect.outputs.mcp_package }}
|
|
npm_package: ${{ steps.detect.outputs.npm_package }}
|
|
reason: ${{ steps.detect.outputs.reason }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Decide package gates
|
|
id: detect
|
|
env:
|
|
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
|
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
|
PUSH_BEFORE_SHA: ${{ github.event.before }}
|
|
PUSH_AFTER_SHA: ${{ github.sha }}
|
|
run: ./scripts/ci/detect-package-gates.sh
|
|
|
|
package-mcp:
|
|
name: Package Gate (MCP)
|
|
runs-on: ubuntu-latest
|
|
needs: [detect-package-gates, build-artifacts]
|
|
steps:
|
|
- name: Check applicability
|
|
id: applicability
|
|
run: |
|
|
echo "run=${{ needs.detect-package-gates.outputs.mcp_package }}" >> "$GITHUB_OUTPUT"
|
|
if [[ "${{ needs.detect-package-gates.outputs.mcp_package }}" != "true" ]]; then
|
|
echo "MCP package gate is not applicable: ${{ needs.detect-package-gates.outputs.reason }}"
|
|
fi
|
|
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
if: steps.applicability.outputs.run == 'true'
|
|
|
|
- name: Set up Python
|
|
if: steps.applicability.outputs.run == 'true'
|
|
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
with:
|
|
python-version: '3.14'
|
|
|
|
- name: Install uv
|
|
if: steps.applicability.outputs.run == 'true'
|
|
run: python -m pip install uv==0.11.16
|
|
|
|
- name: Download build artifacts
|
|
if: steps.applicability.outputs.run == 'true'
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-build-artifacts
|
|
path: ci-build-artifacts
|
|
|
|
- name: Verify build artifacts
|
|
if: steps.applicability.outputs.run == 'true'
|
|
run: |
|
|
set -euo pipefail
|
|
cd ci-build-artifacts
|
|
sha256sum -c SHA256SUMS
|
|
chmod +x bd-linux-gms-pure
|
|
|
|
- name: Run MCP package gate
|
|
if: steps.applicability.outputs.run == 'true'
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/ci-build-artifacts/bd-linux-gms-pure
|
|
run: make ci-package-mcp
|
|
|
|
package-npm:
|
|
name: Package Gate (npm)
|
|
runs-on: ubuntu-latest
|
|
needs: [detect-package-gates, build-artifacts]
|
|
steps:
|
|
- name: Check applicability
|
|
id: applicability
|
|
run: |
|
|
echo "run=${{ needs.detect-package-gates.outputs.npm_package }}" >> "$GITHUB_OUTPUT"
|
|
if [[ "${{ needs.detect-package-gates.outputs.npm_package }}" != "true" ]]; then
|
|
echo "npm package gate is not applicable: ${{ needs.detect-package-gates.outputs.reason }}"
|
|
fi
|
|
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
if: steps.applicability.outputs.run == 'true'
|
|
|
|
- name: Set up Node.js
|
|
if: steps.applicability.outputs.run == 'true'
|
|
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
|
|
with:
|
|
node-version: '24'
|
|
|
|
- name: Download build artifacts
|
|
if: steps.applicability.outputs.run == 'true'
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-build-artifacts
|
|
path: ci-build-artifacts
|
|
|
|
- name: Verify build artifacts
|
|
if: steps.applicability.outputs.run == 'true'
|
|
run: |
|
|
set -euo pipefail
|
|
cd ci-build-artifacts
|
|
sha256sum -c SHA256SUMS
|
|
chmod +x bd-linux-gms-pure
|
|
|
|
- name: Run npm package gate
|
|
if: steps.applicability.outputs.run == 'true'
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/ci-build-artifacts/bd-linux-gms-pure
|
|
run: make ci-package-npm
|
|
|
|
|
|
pr-policy-wrapper:
|
|
name: PR Policy (wrapper timing)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Run PR policy wrapper
|
|
run: make ci-pr-policy
|
|
|
|
pr-core-wrapper:
|
|
name: PR Core (wrapper timing)
|
|
runs-on: ubuntu-latest
|
|
needs: build-artifacts
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Restore race Go build cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/go-cache/race
|
|
key: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-race-${{ github.sha }}
|
|
restore-keys: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-race-
|
|
|
|
- name: Install Dolt
|
|
run: curl -fsSL https://github.com/dolthub/dolt/releases/latest/download/install.sh | sudo bash
|
|
|
|
- name: Configure Git and Dolt identity
|
|
run: |
|
|
git config --global user.name "CI Bot"
|
|
git config --global user.email "ci@beads.test"
|
|
dolt config --global --add user.name "CI Bot"
|
|
dolt config --global --add user.email "ci@beads.test"
|
|
|
|
- name: Download build artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-build-artifacts
|
|
path: ci-build-artifacts
|
|
|
|
- name: Verify build artifacts
|
|
run: |
|
|
set -euo pipefail
|
|
cd ci-build-artifacts
|
|
sha256sum -c SHA256SUMS
|
|
chmod +x bd-linux-gms-pure
|
|
|
|
- name: Run PR core wrapper
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/ci-build-artifacts/bd-linux-gms-pure
|
|
GOCACHE: ${{ runner.temp }}/go-cache/race
|
|
run: make ci-pr-core
|
|
|
|
pr-lint-wrapper:
|
|
name: PR Lint (wrapper timing)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
# --new-from-merge-base below walks real history.
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Install golangci-lint
|
|
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
|
|
|
|
# Scope the wrapper's lint to what this PR introduces, matching the
|
|
# `lint` job's only-new-issues below. main.yml runs the same wrapper with
|
|
# this unset, so the whole tree is still swept on every push to main.
|
|
# Both PR triggers (pull_request, merge_group) target main.
|
|
- name: Run PR lint wrapper
|
|
env:
|
|
BD_LINT_NEW_FROM_MERGE_BASE: origin/main
|
|
run: make ci-pr-lint
|
|
|
|
# Focused job for the hexagonal storage layer (internal/storage/domain/* and
|
|
# internal/storage/uow). These packages back the proxied-server init path and
|
|
# also live behind the existing ./... matrix, but TestDomainDB requires the
|
|
# Dolt sql-server image cached locally (testcontainers checks `docker image
|
|
# inspect` and skips otherwise). Pulling the image up front guarantees the
|
|
# suite actually runs and surfaces failures here with a clear job name.
|
|
test-domain-uow:
|
|
name: Test (storage domain + uow)
|
|
runs-on: ubuntu-latest
|
|
needs: build-artifacts
|
|
# The race-enabled storage package has outgrown Go's implicit 10-minute
|
|
# timeout. Keep both per-package deadlines inside one finite job budget.
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Install Dolt CLI
|
|
run: curl -fsSL https://github.com/dolthub/dolt/releases/latest/download/install.sh | sudo bash
|
|
|
|
- name: Verify dolt on PATH
|
|
run: dolt version
|
|
|
|
- name: Configure Git and Dolt identity
|
|
run: |
|
|
git config --global user.name "CI Bot"
|
|
git config --global user.email "ci@beads.test"
|
|
dolt config --global --add user.name "CI Bot"
|
|
dolt config --global --add user.email "ci@beads.test"
|
|
|
|
- name: Pull Dolt sql-server image
|
|
# Keep tag in sync with internal/testutil/testdoltcommon.go:DoltDockerImage.
|
|
# Without this, RequireDoltContainer reports doltNoImage and TestDomainDB skips.
|
|
run: ./scripts/ci/pull-dolt-image.sh
|
|
|
|
- name: Download build artifacts
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
with:
|
|
name: ci-build-artifacts
|
|
path: ci-build-artifacts
|
|
|
|
- name: Verify build artifacts
|
|
run: |
|
|
set -euo pipefail
|
|
cd ci-build-artifacts
|
|
sha256sum -c SHA256SUMS
|
|
chmod +x bd-linux-gms-pure
|
|
|
|
- name: Test domain + uow + tracker
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/ci-build-artifacts/bd-linux-gms-pure
|
|
run: go test -tags gms_pure_go -race -count=1 -timeout 15m -v ./internal/storage/domain/... ./internal/storage/uow/... ./internal/tracker/...
|
|
|
|
# The doctor/fix DB-backed suite spins its own Dolt container in
|
|
# TestMain. BEADS_FIX_REQUIRE_DOLT=1 turns a missing container into a
|
|
# hard failure so the suite can never silently skip in CI again
|
|
# (bd-nxt5e: it was dark for months); this job pulls the image above.
|
|
- name: Test doctor/fix (Dolt-backed, hard-require container)
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/ci-build-artifacts/bd-linux-gms-pure
|
|
BEADS_FIX_REQUIRE_DOLT: "1"
|
|
run: go test -tags gms_pure_go -race -count=1 -timeout 10m -v ./cmd/bd/doctor/fix/
|
|
|
|
# macOS-only regressions were landing on main undetected: main.yml's Test
|
|
# (macos-latest) leg only runs `if: github.event_name == 'push' &&
|
|
# github.ref == 'refs/heads/main'`, so no PR ever exercises it. On
|
|
# 2026-08-01 that leg went red from three separately-merged PRs in a single
|
|
# day, all $TMPDIR=/var/folders symlink/path-depth consequences that only
|
|
# reproduce on macOS - none of the three could have seen the failure
|
|
# pre-merge, and the local bisect lane can't diagnose it either (Linux
|
|
# host, macOS-only failure). This job mirrors that leg's steps on every PR
|
|
# so the same class of regression fails here instead of on main. It is
|
|
# self-contained (no build-artifacts dependency): the macOS leg in main.yml
|
|
# never downloads or verifies the Linux build-artifacts bundle, it just
|
|
# builds and tests directly.
|
|
#
|
|
# Deliberately NOT continue-on-error: unlike the advisory legs elsewhere in
|
|
# this file that tolerate infrastructure flakiness, a red macOS test here is
|
|
# a real regression, and blocking the merge lane on it is the entire point.
|
|
#
|
|
# Deliberately NOT yet added to ci-gate's `needs`/`CI_GATE_REQUIRED`:
|
|
# promoting a new job to required-for-merge, once it has run clean for a
|
|
# while, is a separate maintainer call - same pattern as other jobs in this
|
|
# file that run on every PR without yet gating the merge.
|
|
test-macos:
|
|
name: Test (macos-latest)
|
|
runs-on: macos-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
id: setup-go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Restore Go module cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ~/go/pkg/mod
|
|
key: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-${{ hashFiles('go.mod', 'go.sum') }}
|
|
restore-keys: beads-go-mod-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-
|
|
|
|
- name: Restore non-race Go build cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/go-cache/non-race
|
|
key: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-${{ github.sha }}
|
|
restore-keys: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-non-race-
|
|
|
|
- name: Restore race Go build cache
|
|
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ runner.temp }}/go-cache/race
|
|
key: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-race-${{ github.sha }}
|
|
restore-keys: beads-go-build-v2-${{ runner.os }}-${{ runner.arch }}-go-${{ steps.setup-go.outputs.go-version }}-base-gms_pure_go-race-
|
|
|
|
- name: Install Dolt (Linux/macOS)
|
|
run: curl -fsSL https://github.com/dolthub/dolt/releases/latest/download/install.sh | sudo bash
|
|
|
|
- name: Verify dolt on PATH
|
|
run: dolt version
|
|
|
|
- name: Configure Git and Dolt identity
|
|
run: |
|
|
git config --global user.name "CI Bot"
|
|
git config --global user.email "ci@beads.test"
|
|
dolt config --global --add user.name "CI Bot"
|
|
dolt config --global --add user.email "ci@beads.test"
|
|
|
|
- name: Build
|
|
env:
|
|
GOCACHE: ${{ runner.temp }}/go-cache/non-race
|
|
run: go build -v -tags gms_pure_go ./cmd/bd
|
|
|
|
- name: Test
|
|
env:
|
|
BEADS_TEST_BD_BINARY: ${{ github.workspace }}/bd
|
|
GOCACHE: ${{ runner.temp }}/go-cache/race
|
|
run: go test -tags gms_pure_go -v -race -short -skip '^TestEmbedded' ./...
|
|
|
|
# Producer-side guard for the Beads<->consumer CLI contract. Runs the whole
|
|
# cmd/bd/protocol package: the golden corpus (regenerated from this branch's
|
|
# bd and byte-compared to the committed testdata/corpus/, so an unreviewed
|
|
# wire change is a hard failure — run `make corpus-regen`), the double-run
|
|
# determinism check, and the TestProtocol_/TestJSONContract_ behavioral
|
|
# conformance suite that pins the CLI's JSON payloads and semantics.
|
|
#
|
|
# Run the PACKAGE, never a -run subset: a filter here is what let the
|
|
# conformance tests sit red on main for ~3 months while every CI run was
|
|
# green (they matched no job's -run, and every broad ./... job skips them
|
|
# for want of a Dolt store). Package scope means a newly added protocol test
|
|
# is gated the moment it lands.
|
|
#
|
|
# Needs the Dolt sql-server image (the protocol harness spins a container).
|
|
# ~10 min: each test builds an isolated Dolt-backed workspace. If that ever
|
|
# becomes unacceptable on PRs, shard this job by an exhaustive `go test
|
|
# -list` partition — do not reintroduce a hand-written -run regex.
|
|
contract-corpus:
|
|
name: Contract corpus (golden + determinism + conformance)
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Install Dolt CLI
|
|
run: curl -fsSL https://github.com/dolthub/dolt/releases/latest/download/install.sh | sudo bash
|
|
|
|
- name: Configure Git and Dolt identity
|
|
run: |
|
|
git config --global user.name "CI Bot"
|
|
git config --global user.email "ci@beads.test"
|
|
dolt config --global --add user.name "CI Bot"
|
|
dolt config --global --add user.email "ci@beads.test"
|
|
|
|
- name: Pull Dolt sql-server image
|
|
# Keep tag in sync with internal/testutil/testdoltcommon.go:DoltDockerImage.
|
|
run: ./scripts/ci/pull-dolt-image.sh
|
|
|
|
- name: Protocol conformance + corpus golden + determinism
|
|
# Require a live Dolt store here: this is the gate that must exercise the
|
|
# conformance, golden and double-run checks, so a failed container is a
|
|
# hard failure, not a silent skip (see requireDoltStore in the
|
|
# cmd/bd/protocol tests).
|
|
#
|
|
# -timeout is explicit because the package runs well past `go test`'s
|
|
# 10m default; without it a slow runner reports a panic, not a verdict.
|
|
env:
|
|
BEADS_PROTOCOL_REQUIRE_DOLT: "1"
|
|
run: go test -tags gms_pure_go -count=1 -timeout 30m ./cmd/bd/protocol
|
|
|
|
fmt-check:
|
|
name: Check formatting
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: Check gofmt
|
|
run: make fmt-check
|
|
|
|
# Lint lanes are split deliberately: the PR lane reports only the issues a PR
|
|
# introduces, and main.yml's identical job sweeps the whole tree on every
|
|
# push. The tradeoff is that a pre-existing issue in untouched code no longer
|
|
# blocks a PR — but a lint word that lands on main now reds main's own run,
|
|
# where it belongs, instead of reddening every open PR for a change it did
|
|
# not make.
|
|
#
|
|
# "New" is measured off the diff, so MOVED CODE READS AS NEW: a pre-existing
|
|
# violation carried into a PR by a move or a rename is reported against that
|
|
# PR and blocks it. Fix it or //nolint it there — that is the accepted cost of
|
|
# the trade above.
|
|
lint:
|
|
name: Lint
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
# only-new-issues reads the PR patch from the API.
|
|
pull-requests: read
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
with:
|
|
# On merge_group there is no PR patch, so the action falls back to
|
|
# --new-from-rev and needs real history.
|
|
fetch-depth: 0
|
|
|
|
- name: Set up Go
|
|
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: 'go.mod'
|
|
cache: false
|
|
|
|
- name: golangci-lint
|
|
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9
|
|
env:
|
|
GOWORK: "off"
|
|
with:
|
|
version: v2.10.1
|
|
only-new-issues: true
|
|
args: --config=.golangci.yml --modules-download-mode=readonly --timeout=5m --build-tags=gms_pure_go
|
|
|
|
windows-make-shell:
|
|
name: Windows Make shell (${{ matrix.host }})
|
|
runs-on: windows-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
host:
|
|
- native
|
|
- msys2
|
|
- cygwin
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Install native GNU Make
|
|
if: matrix.host == 'native'
|
|
shell: pwsh
|
|
run: choco install make --version=4.4.1 --yes --no-progress
|
|
|
|
- name: Set up MSYS2 GNU Make
|
|
if: matrix.host == 'msys2'
|
|
uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0
|
|
with:
|
|
msystem: MSYS
|
|
install: git make
|
|
path-type: minimal
|
|
|
|
- name: Set up Cygwin GNU Make
|
|
if: matrix.host == 'cygwin'
|
|
id: cygwin
|
|
# cygwin-install-action downloads setup-x86_64.exe from cygwin.com. That
|
|
# download times out often enough to red the required check for a reason
|
|
# unrelated to the change under test. Treat a setup failure as a
|
|
# (non-blocking) warning: the smoke step below is gated on this step
|
|
# succeeding, so a genuine Cygwin Make regression still fails loudly,
|
|
# while a flaky installer download only skips the leg with a warning.
|
|
continue-on-error: true
|
|
uses: cygwin/cygwin-install-action@3f0a3f9f988f7e96b8c18098ae05eaec175f5b52 # v6
|
|
with:
|
|
packages: git make
|
|
add-to-path: 'false'
|
|
|
|
- name: Warn when Cygwin setup was skipped by a download failure
|
|
if: matrix.host == 'cygwin' && steps.cygwin.outcome == 'failure'
|
|
shell: bash
|
|
run: |
|
|
echo "::warning title=Cygwin Make-shell leg skipped::cygwin-install-action could not download the Cygwin installer (network flake); skipping the Cygwin-hosted Make smoke test. This is an infrastructure failure, not a code failure."
|
|
|
|
- name: Exercise native Windows Make
|
|
if: matrix.host == 'native'
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$make = (Get-Command make.exe -ErrorAction Stop).Source
|
|
$hostOutput = & $make --no-print-directory -f NUL --eval '$(info MAKE_HOST=$(MAKE_HOST))' --eval 'noop:;' noop
|
|
$makeHost = (($hostOutput | Where-Object { $_ -like 'MAKE_HOST=*' }) -replace '^MAKE_HOST=', '').Trim()
|
|
if ($LASTEXITCODE -ne 0 -or ($makeHost -ne 'Windows32' -and $makeHost -notmatch '-mingw32$')) {
|
|
throw "Expected native Windows GNU Make, found '$makeHost' at '$make'"
|
|
}
|
|
|
|
$git = (Get-Command git.exe -ErrorAction Stop).Source
|
|
if ($git -notmatch ' ') {
|
|
throw "Expected the hosted Git for Windows path to contain a space, found '$git'"
|
|
}
|
|
|
|
$profile = Join-Path $env:RUNNER_TEMP 'profile with spaces'
|
|
New-Item -ItemType Directory -Force -Path $profile | Out-Null
|
|
$poison = Join-Path $profile 'poison bash env.sh'
|
|
Set-Content -LiteralPath $poison -Encoding utf8 -Value 'exit 97'
|
|
|
|
$env:USERPROFILE = $profile
|
|
$env:BASH_ENV = $poison
|
|
$env:BASHOPTS = 'failglob'
|
|
$env:SHELLOPTS = 'nounset'
|
|
$env:GIT_EXEC_PATH = Join-Path $profile 'missing git exec path'
|
|
$env:PATH = "$(Split-Path $git);$env:SystemRoot\System32"
|
|
|
|
& $make --no-print-directory help | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Native Make failed while parsing or running help'
|
|
}
|
|
|
|
@'
|
|
include Makefile
|
|
.RECIPEPREFIX := >
|
|
.PHONY: windows-make-shell-smoke
|
|
windows-make-shell-smoke:
|
|
>@case "$(SHELL)" in */bin/bash.exe) ;; *) exit 1;; esac
|
|
>@test -n "$$BASH_VERSION"
|
|
>@test "$$(command -v sed)" = /usr/bin/sed
|
|
>@test "$$(command -v env)" = /usr/bin/env
|
|
>@test -z "$${BASH_ENV+x}"
|
|
>@case "$$-" in *u*) exit 1;; esac
|
|
>@shopt -q failglob && exit 1 || :
|
|
>@test -z "$${GIT_EXEC_PATH+x}"
|
|
>@env printf '%s\n' 'native Windows Make shell smoke passed'
|
|
'@ | & $make --no-print-directory -f - windows-make-shell-smoke
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Native Make shell smoke failed'
|
|
}
|
|
|
|
function Get-TreeManifest {
|
|
param([Parameter(Mandatory)][string]$Root)
|
|
|
|
@(
|
|
Get-ChildItem -LiteralPath $Root -Recurse -Force | ForEach-Object {
|
|
$relative = [IO.Path]::GetRelativePath($Root, $_.FullName).Replace('\', '/')
|
|
if ($_.PSIsContainer) {
|
|
"D $relative"
|
|
} else {
|
|
$hash = (Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash
|
|
"F $relative $hash"
|
|
}
|
|
}
|
|
) | Sort-Object
|
|
}
|
|
|
|
$proofRoot = Join-Path $env:RUNNER_TEMP ("make install proof " + [guid]::NewGuid().ToString('N'))
|
|
$fixtureRepo = Join-Path $proofRoot 'fixture repo'
|
|
$buildDir = Join-Path $fixtureRepo 'build output'
|
|
$installRoot = Join-Path $proofRoot 'install sandbox'
|
|
$installProfile = Join-Path $installRoot 'profile with spaces'
|
|
New-Item -ItemType Directory -Force -Path $buildDir, $installProfile | Out-Null
|
|
Copy-Item -LiteralPath (Join-Path $env:GITHUB_WORKSPACE 'Makefile') -Destination $fixtureRepo
|
|
Copy-Item -LiteralPath (Join-Path $env:GITHUB_WORKSPACE 'go.mod') -Destination $fixtureRepo
|
|
|
|
$sentinel = Join-Path $buildDir 'bd.exe'
|
|
Set-Content -LiteralPath $sentinel -Encoding ascii -NoNewline -Value 'native-install-sentinel'
|
|
$sentinelHash = (Get-FileHash -LiteralPath $sentinel -Algorithm SHA256).Hash
|
|
|
|
& $git -C $fixtureRepo init --quiet
|
|
& $git -C $fixtureRepo config core.hooksPath .githooks
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Could not initialize the isolated install fixture repository'
|
|
}
|
|
& $git -C $fixtureRepo -c user.name=install-proof -c user.email=install-proof@example.invalid `
|
|
-c commit.gpgsign=false commit --allow-empty --quiet -m 'Initialize install proof'
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Could not commit the isolated install fixture repository'
|
|
}
|
|
$fixtureBefore = @(Get-TreeManifest -Root $fixtureRepo)
|
|
|
|
$env:USERPROFILE = $installProfile
|
|
Push-Location $fixtureRepo
|
|
try {
|
|
& $make --no-print-directory -o build "BUILD_DIR=$buildDir" GIT_BUILD=install-proof install-force
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Native Make install-force failed for a spaced USERPROFILE'
|
|
}
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
|
|
$installed = Join-Path $installProfile '.local\bin\bd.exe'
|
|
if (-not (Test-Path -LiteralPath $installed -PathType Leaf)) {
|
|
throw "Native Make did not install bd.exe at the exact destination '$installed'"
|
|
}
|
|
if ((Get-FileHash -LiteralPath $installed -Algorithm SHA256).Hash -ne $sentinelHash) {
|
|
throw 'Native Make installed bd.exe with unexpected contents'
|
|
}
|
|
|
|
$expectedInstall = @(
|
|
'D profile with spaces'
|
|
'D profile with spaces/.local'
|
|
'D profile with spaces/.local/bin'
|
|
"F profile with spaces/.local/bin/bd.exe $sentinelHash"
|
|
) | Sort-Object
|
|
$actualInstall = @(Get-TreeManifest -Root $installRoot)
|
|
if (Compare-Object -ReferenceObject $expectedInstall -DifferenceObject $actualInstall) {
|
|
throw "Native Make changed paths outside the exact install destination:`n$($actualInstall -join "`n")"
|
|
}
|
|
|
|
$fixtureAfter = @(Get-TreeManifest -Root $fixtureRepo)
|
|
if (Compare-Object -ReferenceObject $fixtureBefore -DifferenceObject $fixtureAfter) {
|
|
throw 'Native Make split the spaced install path or otherwise mutated the fixture repository'
|
|
}
|
|
|
|
- name: Exercise MSYS2-hosted Make
|
|
if: matrix.host == 'msys2'
|
|
shell: msys2 {0}
|
|
run: |
|
|
set -euo pipefail
|
|
make_host="$(
|
|
make --no-print-directory -f /dev/null \
|
|
--eval '$(info $(MAKE_HOST))' \
|
|
--eval 'noop:;' noop |
|
|
sed -n '1p'
|
|
)"
|
|
case "$make_host" in
|
|
*-msys|*-cygwin) ;;
|
|
*) echo "Expected a POSIX-hosted MSYS2 GNU Make, found '$make_host'" >&2; exit 1 ;;
|
|
esac
|
|
|
|
profile="$(cygpath -u "$RUNNER_TEMP")/profile with spaces"
|
|
mkdir -p "$profile"
|
|
bash_env="$profile/compat bash env.sh"
|
|
printf '%s\n' 'exit 97' > "$bash_env"
|
|
export BASH_ENV="$bash_env"
|
|
export GIT_EXEC_PATH="$profile/missing git exec path"
|
|
export PATH=/usr/bin
|
|
|
|
make --no-print-directory help >/dev/null
|
|
cat > "$profile/smoke.mk" <<'MAKE_EOF'
|
|
include Makefile
|
|
.RECIPEPREFIX := >
|
|
.PHONY: windows-make-shell-smoke
|
|
windows-make-shell-smoke:
|
|
>@case "$(SHELL)" in */sh) ;; *) exit 1;; esac
|
|
>@test -n "$$BASH_VERSION"
|
|
>@test "$$(command -v sed)" = /usr/bin/sed
|
|
>@test "$$(command -v env)" = /usr/bin/env
|
|
>@test -f "$$BASH_ENV"
|
|
>@test -n "$$GIT_EXEC_PATH"
|
|
>@case "$$PATH" in *';'*) exit 1;; esac
|
|
>@env printf '%s\n' 'MSYS2 Make shell smoke passed'
|
|
MAKE_EOF
|
|
make --no-print-directory -f "$profile/smoke.mk" windows-make-shell-smoke
|
|
|
|
- name: Exercise Cygwin-hosted Make
|
|
# Only run when the Cygwin toolchain actually installed; a skipped install
|
|
# (download flake) leaves this leg un-exercised rather than failing on a
|
|
# missing bash. A real install success followed by a Make regression here
|
|
# still fails the job as before.
|
|
if: matrix.host == 'cygwin' && steps.cygwin.outcome == 'success'
|
|
shell: pwsh
|
|
env:
|
|
CYGWIN_ROOT: ${{ steps.cygwin.outputs.root }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$bash = Join-Path $env:CYGWIN_ROOT 'bin\bash.exe'
|
|
$script = @'
|
|
set -euo pipefail
|
|
export PATH=/usr/bin
|
|
cd "$(cygpath -u "$GITHUB_WORKSPACE")"
|
|
|
|
make_host="$(
|
|
make --no-print-directory -f /dev/null \
|
|
--eval '$(info $(MAKE_HOST))' \
|
|
--eval 'noop:;' noop |
|
|
sed -n '1p'
|
|
)"
|
|
case "$make_host" in
|
|
*-cygwin) ;;
|
|
*) echo "Expected Cygwin GNU Make, found '$make_host'" >&2; exit 1 ;;
|
|
esac
|
|
|
|
profile="$(mktemp -d)"
|
|
trap 'rm -rf -- "$profile"' EXIT
|
|
bash_env="$profile/cygwin bash env.sh"
|
|
printf '%s\n' 'exit 97' > "$bash_env"
|
|
export BASH_ENV="$bash_env"
|
|
export GIT_EXEC_PATH="$profile/missing git exec path"
|
|
|
|
make --no-print-directory help >/dev/null
|
|
cat > "$profile/smoke.mk" <<'MAKE_EOF'
|
|
include Makefile
|
|
.RECIPEPREFIX := >
|
|
.PHONY: windows-make-shell-smoke
|
|
windows-make-shell-smoke:
|
|
>@case "$(SHELL)" in */sh) ;; *) exit 1;; esac
|
|
>@test -n "$$BASH_VERSION"
|
|
>@test "$$(command -v sed)" = /usr/bin/sed
|
|
>@test "$$(command -v env)" = /usr/bin/env
|
|
>@test -f "$$BASH_ENV"
|
|
>@test -n "$$GIT_EXEC_PATH"
|
|
>@case "$$PATH" in *';'*) exit 1;; esac
|
|
>@env printf '%s\n' 'Cygwin Make shell smoke passed'
|
|
MAKE_EOF
|
|
make --no-print-directory -f "$profile/smoke.mk" windows-make-shell-smoke
|
|
'@
|
|
$script = $script.Replace("`r`n", "`n")
|
|
& $bash --noprofile --norc -c $script
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw 'Cygwin Make shell smoke failed'
|
|
}
|
|
|
|
ci-gate:
|
|
name: CI Gate / Required
|
|
runs-on: ubuntu-latest
|
|
needs:
|
|
- build-artifacts
|
|
- check-build-tags
|
|
- check-cmd-bd-puregeo-tests
|
|
- test-windows-liveness
|
|
- worktree-remove-windows
|
|
- check-version-consistency
|
|
- check-migration-hygiene
|
|
- check-doc-flags
|
|
- check-doc-freshness-platforms
|
|
- pr-preflight-platforms
|
|
- check-no-beads-changes
|
|
- detect-package-gates
|
|
- package-mcp
|
|
- package-npm
|
|
- pr-policy-wrapper
|
|
- pr-core-wrapper
|
|
- pr-lint-wrapper
|
|
- test-domain-uow
|
|
- contract-corpus
|
|
- fmt-check
|
|
- lint
|
|
- windows-make-shell
|
|
if: ${{ always() }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
|
|
|
|
- name: Evaluate CI gate
|
|
env:
|
|
CI_GATE_NAME: PR baseline gate
|
|
CI_GATE_REQUIRED: >-
|
|
BUILD_ARTIFACTS
|
|
CHECK_BUILD_TAGS
|
|
CHECK_CMD_BD_PUREGEO_TESTS
|
|
TEST_WINDOWS_LIVENESS
|
|
WORKTREE_REMOVE_WINDOWS
|
|
CHECK_VERSION_CONSISTENCY
|
|
CHECK_MIGRATION_HYGIENE
|
|
CHECK_DOC_FLAGS
|
|
CHECK_DOC_FRESHNESS_PLATFORMS
|
|
PR_PREFLIGHT_PLATFORMS
|
|
CHECK_NO_BEADS_CHANGES
|
|
DETECT_PACKAGE_GATES
|
|
PACKAGE_MCP
|
|
PACKAGE_NPM
|
|
PR_POLICY_WRAPPER
|
|
PR_CORE_WRAPPER
|
|
PR_LINT_WRAPPER
|
|
TEST_DOMAIN_UOW
|
|
CONTRACT_CORPUS
|
|
FMT_CHECK
|
|
LINT
|
|
WINDOWS_MAKE_SHELL
|
|
BUILD_ARTIFACTS: ${{ needs.build-artifacts.result }}
|
|
CHECK_BUILD_TAGS: ${{ needs.check-build-tags.result }}
|
|
CHECK_CMD_BD_PUREGEO_TESTS: ${{ needs.check-cmd-bd-puregeo-tests.result }}
|
|
TEST_WINDOWS_LIVENESS: ${{ needs.test-windows-liveness.result }}
|
|
WORKTREE_REMOVE_WINDOWS: ${{ needs.worktree-remove-windows.result }}
|
|
CHECK_VERSION_CONSISTENCY: ${{ needs.check-version-consistency.result }}
|
|
CHECK_MIGRATION_HYGIENE: ${{ needs.check-migration-hygiene.result }}
|
|
CHECK_DOC_FLAGS: ${{ needs.check-doc-flags.result }}
|
|
CHECK_DOC_FRESHNESS_PLATFORMS: ${{ needs.check-doc-freshness-platforms.result }}
|
|
PR_PREFLIGHT_PLATFORMS: ${{ needs.pr-preflight-platforms.result }}
|
|
CHECK_NO_BEADS_CHANGES: ${{ needs.check-no-beads-changes.result }}
|
|
DETECT_PACKAGE_GATES: ${{ needs.detect-package-gates.result }}
|
|
PACKAGE_MCP: ${{ needs.package-mcp.result }}
|
|
PACKAGE_NPM: ${{ needs.package-npm.result }}
|
|
PR_POLICY_WRAPPER: ${{ needs.pr-policy-wrapper.result }}
|
|
PR_CORE_WRAPPER: ${{ needs.pr-core-wrapper.result }}
|
|
PR_LINT_WRAPPER: ${{ needs.pr-lint-wrapper.result }}
|
|
TEST_DOMAIN_UOW: ${{ needs.test-domain-uow.result }}
|
|
CONTRACT_CORPUS: ${{ needs.contract-corpus.result }}
|
|
FMT_CHECK: ${{ needs.fmt-check.result }}
|
|
LINT: ${{ needs.lint.result }}
|
|
WINDOWS_MAKE_SHELL: ${{ needs.windows-make-shell.result }}
|
|
run: |
|
|
skipped_ok=""
|
|
if [[ "$GITHUB_EVENT_NAME" == "merge_group" ]]; then
|
|
skipped_ok="CHECK_NO_BEADS_CHANGES"
|
|
fi
|
|
export CI_GATE_SKIPPED_OK="$skipped_ok"
|
|
bash .github/scripts/ci-gate.sh
|