Files
gastownhall__beads/.github/workflows/pr.yml
T
ecuthiell 8137ed4092 test(preflight): inject fake gh in Bash (#4967) (#4968)
Execute the production script as a real Bash process whose controlled BASH_ENV defines the fake gh function. Curate shell, Git, GitHub, and path state; poison inherited startup/configuration in the fixture; and require the process boundary on Linux, macOS, and Windows.

Agent-Signature: codex-tui-gpt-5.6-sol-ultra on behalf of Ewen Cuthiell
2026-07-25 16:14:33 -07:00

815 lines
30 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
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
- name: Run policy checks
run: make ci-pr-policy
- name: Run lint checks
run: make ci-pr-lint
- name: Build reusable Linux artifacts
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
# 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 the cgo-test-contamination fix (mybd-ycx / GH#3683 follow-up).
# cmd/bd carries a mix of cgo-only test helpers (embedded Dolt, sql.DB) and
# pure-Go tests. Untagged test files that reach for cgo-only helpers break
# the entire package's CGO_ENABLED=0 compile, silently neutering pure-Go
# tests (the original symptom in PR #3704). This job compiles the cmd/bd
# test binary with CGO_ENABLED=0 and runs the pure-Go subset, so a
# regression that re-introduces cgo coupling fails fast.
check-cmd-bd-puregeo-tests:
name: Check cmd/bd pure-Go tests compile (CGO_ENABLED=0)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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
# 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@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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
pr-preflight-platforms:
name: PR preflight process (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v6
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- name: Exercise the real Bash process boundary
shell: bash
run: go test '-tags=integration,gms_pure_go' -count=1 -run '^TestPRPreflight' ./scripts
# 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@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6
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@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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
run: make ci-pr-core
pr-lint-wrapper:
name: PR Lint (wrapper timing)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- name: Install golangci-lint
run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.10.1
- name: Run PR lint wrapper
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
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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: docker pull dolthub/dolt-sql-server:2.2.0
- 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 -v ./internal/storage/domain/... ./internal/storage/uow/... ./internal/tracker/...
# 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@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- 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: docker pull dolthub/dolt-sql-server:2.2.0
- 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@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- name: Check gofmt
run: make fmt-check
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
- name: Set up Go
uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
with:
go-version-file: 'go.mod'
- name: golangci-lint
uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9
with:
version: latest
args: --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
uses: cygwin/cygwin-install-action@3f0a3f9f988f7e96b8c18098ae05eaec175f5b52 # v6
with:
packages: git make
add-to-path: 'false'
- 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'
}
- 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
if: matrix.host == 'cygwin'
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
- check-version-consistency
- check-migration-hygiene
- check-doc-flags
- 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
CHECK_VERSION_CONSISTENCY
CHECK_MIGRATION_HYGIENE
CHECK_DOC_FLAGS
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 }}
CHECK_VERSION_CONSISTENCY: ${{ needs.check-version-consistency.result }}
CHECK_MIGRATION_HYGIENE: ${{ needs.check-migration-hygiene.result }}
CHECK_DOC_FLAGS: ${{ needs.check-doc-flags.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