mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-06 17:49:47 +00:00
GitHub retires the macos-14 runner image on 2026-11-02, and its brownouts already cancel our macos-14 jobs. Move every macos-14 runner reference to macos-15 (arm64): the release darwin-arm64 build, the unix-macos14 and tsan-mac test legs, the smoke-mac PR leg (its two matrix.os guards move in lockstep), the release smoke, both soak legs, the memwaste event lane, the bug-repro board, the cache warmer and the all-platform smoke. Lane names stay unchanged: select-lanes.sh, ci-ok and the lane contracts key on them, never on the runner label. Two broad legs already ran on macos-15 (_test.yml BROAD_UNIX, _smoke.yml BROAD_UNIX) and smoke.yml listed both images, so the moved legs would have duplicated them. Those duplicates are dropped; PR CI keeps exactly the same legs. Without an explicit minimum, clang stamps the binary with the SDK's default (LC_BUILD_VERSION minos), so a release built on macos-15 would refuse to start on macOS 14. Makefile.cbm now folds -mmacosx-version-min=14.0 into CC/CXX next to ARCHFLAGS for Apple targets (detected from the compiler's target, not the host), so it reaches every compile and link, vendored objects included, on every build path. Proof on macOS 26.6 / SDK 26.5: the production binary built from origin/main reports minos 26.0; with this change it reports minos 14.0, with zero warnings under -Werror, no weak imports and an identical undefined-symbol set. The test runner (direct make, no env.sh) is minos 14.0 too; platform and daemon_ipc suites pass. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
417 lines
20 KiB
YAML
417 lines
20 KiB
YAML
# PR validation: security gates + lint + the test legs this PR's changes need.
|
|
# `changes` runs scripts/ci/select-lanes.sh on the PR's file list; every lane
|
|
# job below runs only when selected (unknown paths, workflows, the harness,
|
|
# Makefile.cbm and vendored code select everything). Builds, smoke and soak at
|
|
# full breadth stay maintainer-driven via the dry-run workflow_dispatch. Branch
|
|
# protection requires `dco` + `ci-ok` — a single stable summary context that
|
|
# fails unless every PR stage succeeded and every selected lane ran green.
|
|
name: PR
|
|
|
|
on:
|
|
pull_request:
|
|
branches: [main]
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
|
|
# A new push to the PR supersedes the running validation — cancel it
|
|
# instead of stacking zombie pipelines.
|
|
concurrency:
|
|
group: pr-${{ github.event.pull_request.number }}
|
|
cancel-in-progress: true
|
|
|
|
|
|
jobs:
|
|
security:
|
|
needs: [changes]
|
|
uses: ./.github/workflows/_security.yml
|
|
# No job in _security.yml reads code scanning or the Actions API any more
|
|
# (the CodeQL gate moved to codeql.yml), so the token stays read-only.
|
|
permissions:
|
|
contents: read
|
|
secrets: inherit
|
|
with:
|
|
lanes: ${{ needs.changes.outputs.lanes }}
|
|
|
|
lint:
|
|
needs: [changes]
|
|
if: ${{ contains(fromJSON(needs.changes.outputs.lanes), 'lint') || contains(fromJSON(needs.changes.outputs.lanes), 'lint-mem') }}
|
|
uses: ./.github/workflows/_lint.yml
|
|
with:
|
|
lanes: ${{ needs.changes.outputs.lanes }}
|
|
|
|
# ── Smart CI, PR CI only: run only the tests this change can reach.
|
|
# Active only while the repository variable TEST_IMPACT_MODE is `gate`;
|
|
# unset (shadow) every test runs and test-impact-shadow only reports.
|
|
# test-impact-select.sh --gate narrows only on a well-formed answer: a
|
|
# failure of this job, a run-all answer or a lane that selects nothing
|
|
# leaves `test` without a selection, and every test runs. ci-ok does not
|
|
# need this job: when it breaks, PRs cost more minutes, never coverage.
|
|
# Dry runs and releases never pass a selection.
|
|
select-tests:
|
|
needs: [changes]
|
|
if: ${{ vars.TEST_IMPACT_MODE == 'gate' }}
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 30
|
|
permissions:
|
|
contents: read
|
|
actions: read # the merge base's team-artifact bundle (test-impact-artifact.yml)
|
|
outputs:
|
|
selection: ${{ steps.select.outputs.selection }}
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
# Full history: the engine certifies the history it diffs and refuses
|
|
# a shallow clone, so a depth-2 checkout always answered `all`.
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: Build this checkout's engine
|
|
run: |
|
|
sudo apt-get update && sudo apt-get install -y zlib1g-dev
|
|
scripts/build.sh CC=gcc CXX=g++
|
|
- name: Select the tests
|
|
id: select
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: scripts/ci/test-impact-select.sh --binary build/c/codebase-memory-mcp --out "$RUNNER_TEMP/test-impact" --gate "$RUNNER_TEMP/test-selection"
|
|
- name: Upload the selection
|
|
if: ${{ steps.select.outputs.selection == 'narrowed' }}
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: test-selection
|
|
path: ${{ runner.temp }}/test-selection
|
|
if-no-files-found: error
|
|
overwrite: true
|
|
# The selection a veto discarded (written only when one did): evidence
|
|
# for the vetoes, never read by a test leg.
|
|
- name: Upload the vetoed selection
|
|
if: ${{ !cancelled() && steps.select.outcome != 'skipped' }}
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: test-selection-vetoed
|
|
path: ${{ runner.temp }}/test-impact/selection-vetoed.json
|
|
if-no-files-found: ignore
|
|
overwrite: true
|
|
|
|
test:
|
|
needs: [changes, lint, select-tests]
|
|
if: ${{ !cancelled() && needs.lint.result == 'success' }}
|
|
uses: ./.github/workflows/_test.yml
|
|
with:
|
|
lanes: ${{ needs.changes.outputs.lanes }}
|
|
# Smart CI: only a successful select-tests run that narrowed passes a
|
|
# selection; skipped (shadow), failed, run-all and nothing-selected
|
|
# answers all run every test.
|
|
test_selection: ${{ needs.select-tests.result == 'success' && needs.select-tests.outputs.selection == 'narrowed' && 'test-selection' || '' }}
|
|
# Perf assertions are timing-sensitive on shared runners; they stay in
|
|
# dry runs and releases where a flaky red does not block a merge.
|
|
skip_perf: true
|
|
# Iteration speed: split C-suite legs across parallel shard jobs
|
|
# (coverage re-proven every run by the shard-completeness job). The PR
|
|
# profile shards only arm64 (x2); x86 and Windows run whole, since each
|
|
# shard re-pays its setup. Dry runs and releases keep x3 / x2.
|
|
shard_suites: true
|
|
shard_profile: pr
|
|
|
|
# ── Which lanes does this PR need? The changed files go through
|
|
# scripts/ci/select-lanes.sh (tier, lanes, full, reasons); docs / CI /
|
|
# test-only PRs stay fast, anything it cannot place runs everything. ──
|
|
changes:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
outputs:
|
|
tier: ${{ steps.select.outputs.tier }}
|
|
full: ${{ steps.select.outputs.full }}
|
|
lanes: ${{ steps.select.outputs.lanes }}
|
|
smoke: ${{ steps.select.outputs.smoke }}
|
|
codeql: ${{ steps.select.outputs.codeql }}
|
|
steps:
|
|
- name: List the changed files
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
PR: ${{ github.event.pull_request.number }}
|
|
REPO: ${{ github.repository }}
|
|
run: |
|
|
# The full .diff endpoint rejects large-but-valid PRs at 20k lines.
|
|
# The paginated files endpoint remains filename-only for this gate.
|
|
# A rename lists its old path too, as the fallback's --no-renames
|
|
# diff does: moving a file away is a change to where it was.
|
|
if FILES=$(gh api --paginate "repos/$REPO/pulls/$PR/files?per_page=100" --jq '.[] | .filename, (.previous_filename // empty)'); then
|
|
echo "file list: pulls/files API"
|
|
else
|
|
# The files endpoint renders the diff server-side too, and answers
|
|
# 422 "this diff is taking too long to generate" for a PR that
|
|
# regenerates a vendored parser (#2246: a 42 MB sql/parser.c) --
|
|
# so does the compare endpoint. The PR merge ref's first parent is
|
|
# the base, so a name-only diff across it is the same file list.
|
|
# depth 2 + blob:none fetches commits and trees only (well under
|
|
# 1 MB, under a second); nothing from the PR is checked out or run.
|
|
echo "::notice::pulls/files API failed; file list taken from refs/pull/$PR/merge"
|
|
CHANGES_GIT="$RUNNER_TEMP/changes.git"
|
|
git init -q --bare "$CHANGES_GIT"
|
|
git --git-dir="$CHANGES_GIT" fetch -q --depth=2 --filter=blob:none \
|
|
"https://github.com/$REPO" "refs/pull/$PR/merge"
|
|
FILES=$(git --git-dir="$CHANGES_GIT" diff --name-only --no-renames FETCH_HEAD^1 FETCH_HEAD)
|
|
fi
|
|
printf '%s\n' "$FILES" > "$RUNNER_TEMP/changed-files.txt"
|
|
cat "$RUNNER_TEMP/changed-files.txt"
|
|
|
|
# The selector is PR code: it runs in its own step, after the
|
|
# token-bearing one, from a checkout that keeps no credentials.
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
persist-credentials: false
|
|
|
|
# The pulls/files API lists at most 3000 files: the PR's own count lets
|
|
# the selector notice a cut list and select everything instead.
|
|
- name: Select lanes
|
|
id: select
|
|
env:
|
|
CHANGED_FILES: ${{ github.event.pull_request.changed_files }}
|
|
run: |
|
|
scripts/ci/select-lanes.sh --format github-output --expect-files "$CHANGED_FILES" "$RUNNER_TEMP/changed-files.txt" > "$RUNNER_TEMP/selection.txt"
|
|
cat "$RUNNER_TEMP/selection.txt"
|
|
cat "$RUNNER_TEMP/selection.txt" >> "$GITHUB_OUTPUT"
|
|
# pr-smoke's legs, each tagged with its lane (kept in the job name,
|
|
# where ci-ok reads it back); the job gets the selected ones.
|
|
SMOKE='[{"os":"ubuntu-latest","lane":"smoke-ubuntu"},{"os":"macos-15","lane":"smoke-mac"},{"os":"windows-latest","lane":"smoke-win"}]'
|
|
LANES=$(sed -n 's/^lanes=//p' "$RUNNER_TEMP/selection.txt")
|
|
echo "smoke={\"include\":$(jq -c --argjson sel "$LANES" 'map(select(.lane | IN($sel[])))' <<< "$SMOKE")}" >> "$GITHUB_OUTPUT"
|
|
# The CodeQL legs, tagged the same way (codeql.yml's full matrix has
|
|
# the same entries, so PR and main share a configuration).
|
|
CODEQL='[{"language":"c-cpp","build-mode":"manual","lane":"codeql-cpp"},{"language":"javascript-typescript","build-mode":"none","lane":"codeql-js"},{"language":"python","build-mode":"none","lane":"codeql-py"},{"language":"actions","build-mode":"none","lane":"codeql-actions"}]'
|
|
echo "codeql={\"include\":$(jq -c --argjson sel "$LANES" 'map(select(.lane | IN($sel[])))' <<< "$CODEQL")}" >> "$GITHUB_OUTPUT"
|
|
|
|
# ── Light smoke: build the PRODUCTION binary and run the core smoke on the
|
|
# three RELIABLE NATIVE platforms. Catches built-binary regressions at PR
|
|
# time (e.g. the Windows CreateProcess argv-quoting class that previously
|
|
# only surfaced in the release dry run). The full broad/emulated smoke stays
|
|
# in the dry run. Only the selected legs run (ubuntu from the extraction
|
|
# tier up, all three for platform/packaging changes); every leg gates.
|
|
# The maintained local wrappers add a race-free release fixture so the
|
|
# download/checksum/install/update phases run here as well. ──
|
|
pr-smoke:
|
|
needs: [changes]
|
|
if: ${{ !cancelled() && needs.changes.result == 'success' && (contains(fromJSON(needs.changes.outputs.lanes), 'smoke-ubuntu') || contains(fromJSON(needs.changes.outputs.lanes), 'smoke-mac') || contains(fromJSON(needs.changes.outputs.lanes), 'smoke-win')) }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJSON(needs.changes.outputs.smoke) }}
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 30
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
|
|
# SMOKE_REQUIRE_WRAPPERS=1 needs a Go toolchain for the Go wrapper; the
|
|
# macOS runner images have none on PATH.
|
|
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
|
|
with:
|
|
go-version-file: pkg/go/go.mod
|
|
cache: false
|
|
|
|
- name: Install deps (Ubuntu)
|
|
if: matrix.os == 'ubuntu-latest'
|
|
run: sudo apt-get update && sudo apt-get install -y zlib1g-dev ccache
|
|
|
|
- name: Install ccache (macOS)
|
|
if: matrix.os == 'macos-15'
|
|
run: command -v ccache >/dev/null 2>&1 || brew install ccache
|
|
|
|
- uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2
|
|
if: matrix.os == 'windows-latest'
|
|
with:
|
|
msystem: CLANG64
|
|
path-type: inherit
|
|
install: >-
|
|
mingw-w64-clang-x86_64-clang
|
|
mingw-w64-clang-x86_64-zlib
|
|
mingw-w64-clang-x86_64-python3
|
|
mingw-w64-clang-x86_64-ccache
|
|
make
|
|
coreutils
|
|
curl
|
|
zip
|
|
unzip
|
|
|
|
# Verified compiler cache — content-keyed, stale hits impossible by
|
|
# construction (see scripts/env.sh).
|
|
- name: Compiler cache (content-verified)
|
|
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
|
with:
|
|
path: ${{ github.workspace }}/.ccache
|
|
key: ccache-smoke-${{ matrix.os }}-${{ github.ref }}-${{ github.sha }}
|
|
restore-keys: |
|
|
ccache-smoke-${{ matrix.os }}-${{ github.ref }}-
|
|
|
|
- name: Build prod + smoke (Ubuntu)
|
|
if: matrix.os == 'ubuntu-latest'
|
|
run: |
|
|
scripts/build.sh CC=gcc CXX=g++
|
|
scripts/smoke-local.sh "$(pwd)/build/c/codebase-memory-mcp"
|
|
env:
|
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
|
CCACHE_MAXSIZE: 1000M
|
|
SMOKE_REQUIRE_WRAPPERS: "1"
|
|
|
|
- name: Build prod + smoke (macOS)
|
|
if: matrix.os == 'macos-15'
|
|
run: |
|
|
scripts/build.sh CC=cc CXX=c++
|
|
codesign --sign - --force build/c/codebase-memory-mcp
|
|
scripts/smoke-local.sh "$(pwd)/build/c/codebase-memory-mcp"
|
|
env:
|
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
|
CCACHE_MAXSIZE: 1000M
|
|
SMOKE_REQUIRE_WRAPPERS: "1"
|
|
|
|
- name: Build prod + smoke (Windows)
|
|
if: matrix.os == 'windows-latest'
|
|
shell: msys2 {0}
|
|
run: |
|
|
scripts/build.sh CC=clang CXX=clang++
|
|
SMOKE_ARCH=amd64 bash test-infrastructure/vm/vm-smoke.sh
|
|
env:
|
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
|
CCACHE_MAXSIZE: 1000M
|
|
SMOKE_REQUIRE_WRAPPERS: "1"
|
|
|
|
# ── Waste sanitizer, REPORT-ONLY: memory + CPU waste on this repository and
|
|
# the per-function scaling lane (Linux). Deliberately NOT in ci-ok's needs:
|
|
# it uploads evidence and prints the ratchet, it never blocks a merge. Only
|
|
# PRs whose selection holds the memwaste lane (memory core, memwaste
|
|
# tooling, full runs) pay for it. ──
|
|
memwaste:
|
|
needs: [changes]
|
|
if: ${{ !cancelled() && needs.changes.result == 'success' && contains(fromJSON(needs.changes.outputs.lanes), 'memwaste') }}
|
|
uses: ./.github/workflows/_memwaste.yml
|
|
with:
|
|
mode: pr
|
|
|
|
# ── Test-impact SHADOW, REPORT-ONLY: predicts from the code graph which C
|
|
# suites this change can affect (the latest released binary indexes the
|
|
# PR checkout; detect_changes at depth 15 against the base, mapped to
|
|
# suites, with the selector's run-all triggers) and uploads the
|
|
# prediction, so graph-based selection can be judged against what really
|
|
# failed before anything gates on it. continue-on-error and NOT in
|
|
# ci-ok's needs: it can never block or pass a merge. ──
|
|
test-impact-shadow:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
continue-on-error: true
|
|
permissions:
|
|
contents: read
|
|
actions: read # the merge base's team-artifact bundle (test-impact-artifact.yml)
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
# Full history: the engine (test-impact select) certifies the history
|
|
# it diffs and refuses a shallow clone ("Graft or shallow state
|
|
# prevents history certification"), which made every shadow answer
|
|
# run_all (GIT_UNAVAILABLE). About 400 MiB, this job only.
|
|
fetch-depth: 0
|
|
persist-credentials: false
|
|
- name: Fetch the latest released binary
|
|
id: release
|
|
continue-on-error: true
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: scripts/ci/test-impact-shadow.sh --fetch-release "$RUNNER_TEMP/cbm-bin"
|
|
- name: Build the binary from this checkout (download failed)
|
|
if: ${{ steps.release.outcome == 'failure' }}
|
|
run: |
|
|
sudo apt-get update && sudo apt-get install -y zlib1g-dev
|
|
scripts/build.sh CC=gcc CXX=g++
|
|
mkdir -p "$RUNNER_TEMP/cbm-bin"
|
|
cp build/c/codebase-memory-mcp "$RUNNER_TEMP/cbm-bin/"
|
|
- name: Predict the impacted suites
|
|
run: scripts/ci/test-impact-shadow.sh --binary "$RUNNER_TEMP/cbm-bin/codebase-memory-mcp" --out "$RUNNER_TEMP/test-impact"
|
|
# The engine (test-impact select) is this checkout's own code: the
|
|
# released binary predates it, so the checkout is built either way.
|
|
- name: Build this checkout's engine
|
|
if: ${{ steps.release.outcome != 'failure' }}
|
|
run: |
|
|
sudo apt-get update && sudo apt-get install -y zlib1g-dev
|
|
scripts/build.sh CC=gcc CXX=g++
|
|
- name: Select with the team artifact (engine shadow)
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: scripts/ci/test-impact-select.sh --binary build/c/codebase-memory-mcp --out "$RUNNER_TEMP/test-impact"
|
|
- name: Upload the prediction
|
|
if: ${{ always() }}
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: test-impact-prediction
|
|
path: |
|
|
${{ runner.temp }}/test-impact/prediction.json
|
|
${{ runner.temp }}/test-impact/selection.json
|
|
${{ runner.temp }}/test-impact/changed-files.txt
|
|
${{ runner.temp }}/test-impact/selection-engine.json
|
|
${{ runner.temp }}/test-impact/summary-engine.md
|
|
if-no-files-found: warn
|
|
|
|
# ── Docs-only and non-product PRs (tiers T0a, T0b) run the static contract
|
|
# steps of the canonical test leg on their own: they police docs
|
|
# surfaces (language counts, version metadata), test-infrastructure/ and
|
|
# lint config too. Every test leg runs the same steps. ──
|
|
contracts:
|
|
needs: [changes]
|
|
if: ${{ !cancelled() && needs.changes.result == 'success' && contains(fromJSON(needs.changes.outputs.lanes), 'contracts') }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 20
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
- name: Contract steps only
|
|
run: scripts/test.sh --contracts-only
|
|
|
|
# ── CodeQL PR scan (lanes codeql-cpp / -js / -py / -actions): one leg per
|
|
# language whose first-party scope this PR changes; each analyses that
|
|
# language's whole first-party scope, c-cpp with the vendored objects
|
|
# compiled before tracing (except vendored files the PR changes), and
|
|
# reports alerts on the changed lines (diff-informed). A job of this run,
|
|
# needed by ci-ok -- nothing waits for a separate CodeQL run. Push to
|
|
# main, dry run and release run the full scan (codeql.yml). ──
|
|
codeql:
|
|
needs: [changes]
|
|
if: ${{ !cancelled() && needs.changes.result == 'success' && (contains(fromJSON(needs.changes.outputs.lanes), 'codeql-cpp') || contains(fromJSON(needs.changes.outputs.lanes), 'codeql-js') || contains(fromJSON(needs.changes.outputs.lanes), 'codeql-py') || contains(fromJSON(needs.changes.outputs.lanes), 'codeql-actions')) }}
|
|
uses: ./.github/workflows/codeql.yml
|
|
# codeql.yml uploads results and reads alerts: a called workflow cannot
|
|
# request more than its caller grants (startup failure otherwise).
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
actions: read
|
|
with:
|
|
light: true
|
|
matrix: ${{ needs.changes.outputs.codeql }}
|
|
|
|
ci-ok:
|
|
# The one required context (besides dco) — fails unless every PR stage
|
|
# succeeded, so matrix renames can never silently deadlock merges, and
|
|
# every lane the selector chose ran green: `skipped` is OK only for a lane
|
|
# nobody selected (a selected lane that skipped is a silent gate loss).
|
|
# memwaste and the test-impact shadow are report-only and not needed here.
|
|
needs: [changes, security, lint, test, pr-smoke, contracts, codeql]
|
|
if: ${{ always() }}
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 5
|
|
# actions:read lists this run's jobs, the lane-level truth behind `needs`.
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
steps:
|
|
# Needs a checkout (unlike before): the gate logic lives in the canonical
|
|
# scripts/ci entry, not inline YAML (venue-parity contract).
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
- name: List this run's jobs
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
gh api --paginate "repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/jobs?filter=latest&per_page=100" \
|
|
--jq '.jobs[] | {name, status, conclusion}' > "$RUNNER_TEMP/jobs.jsonl"
|
|
- name: All PR stages and every selected lane must have succeeded
|
|
env:
|
|
RESULTS: ${{ toJSON(needs) }}
|
|
LANES: ${{ needs.changes.outputs.lanes }}
|
|
JOBS: ${{ runner.temp }}/jobs.jsonl
|
|
run: scripts/ci/require-all-green.sh
|