Repository navigation
154 lines (140 loc) · 6.68 KB
/
Copy pathci.yml
File metadata and controls
154 lines (140 loc) · 6.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# CI — the host-local gate on the supported OSes (macOS arm64 + Linux x86_64),
# mirroring the local gate. Each matrix leg runs `scripts/ci_gate.sh`, so CI
# verifies exactly what the maintainer runs per host (single source of truth).
#
# Triggers: pull_request (any target) + push to `main` + manual dispatch.
# The gate has no external runtime dependency beyond Zig 0.16.0 and python3
# (preinstalled on GitHub runners); `zig build -Dwasm` fetches the embedded
# zwasm engine + the zlinter dev-dep from git over the network.
#
# ONE configuration, everywhere (2026-08-12). PR, push, dispatch and the local
# `scripts/run_gate.sh` all run the identical full gate, so "green" means the
# same run wherever it was said. The tiers this used to have (PR → smoke,
# nightly → full + a tree_walk sweep) were the drift they were meant to catch:
# the last nightly failed on a wall-clock bound in a config nothing else ran,
# which is a finding about the runner, not about cljw.
# `scripts/check_gate_parity.sh` enforces the single configuration mechanically.
# The Zig toolchain, the fetched deps (zwasm/zlinter), and the build cache are
# all preserved across runs (actions/cache), so a warm run rebuilds only what
# changed instead of three cold ReleaseSafe builds — the dominant cost.
name: ci
on:
# Skip CI on doc/scaffolding-only pushes (markdown, .dev/ ledger + ADRs + notes):
# they cannot change build/test outcome, so a ~15-min gate on them is pure waste.
# A commit that also touches src / scripts / build.zig* / flake.nix / .github /
# a root data-yaml still runs (paths-ignore skips only when ALL changed files match).
pull_request:
paths-ignore: ['**/*.md', '.dev/**']
push:
branches: [main]
paths-ignore: ['**/*.md', '.dev/**']
workflow_dispatch:
permissions:
contents: read
env:
# Homebrew 6.0 (2026-05-30) enforces tap-trust: the macos-15 image ships a
# pre-tapped third-party `aws/tap`, so every `brew` invocation (auto-update
# included) spews a "not trusted / ignoring formulae" block and any future
# third-party formula install would be rejected outright. Our own installs
# are homebrew/core (official) so they still work, but this keeps the log
# clean and future-proofs a third-party dep. Harmless on Linux (no brew).
HOMEBREW_NO_REQUIRE_TAP_TRUST: 1
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
gate:
name: gate (${{ matrix.name }})
runs-on: ${{ matrix.runs-on }}
timeout-minutes: 75
strategy:
fail-fast: false
matrix:
include:
- name: aarch64-macos
runs-on: macos-15
zig-dir: zig-aarch64-macos-0.16.0
- name: x86_64-linux
runs-on: ubuntu-22.04
zig-dir: zig-x86_64-linux-0.16.0
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.sha }}
- name: Cache Zig 0.16.0
id: cache-zig
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: ~/.local/zig-0.16.0
key: zig-0.16.0-${{ matrix.name }}
- name: Install Zig 0.16.0
if: steps.cache-zig.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
source .github/versions.lock
mkdir -p ~/.local
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/${{ matrix.zig-dir }}.tar.xz" -o /tmp/zig.tar.xz
# Clear both paths first so a re-run is idempotent: tar refuses to
# overwrite existing entries ("Cannot open: File exists"), and `mv` into
# an EXISTING directory nests instead of replacing, which would put the
# toolchain at zig-0.16.0/<zig-dir>/ and leave `zig` off PATH.
rm -rf "$HOME/.local/${{ matrix.zig-dir }}" "$HOME/.local/zig-0.16.0"
tar -xJf /tmp/zig.tar.xz -C ~/.local
mv "$HOME/.local/${{ matrix.zig-dir }}" "$HOME/.local/zig-0.16.0"
- name: Add Zig to PATH
shell: bash
run: echo "$HOME/.local/zig-0.16.0" >> "$GITHUB_PATH"
- name: Pin Zig global cache dir
shell: bash
run: echo "ZIG_GLOBAL_CACHE_DIR=$HOME/.cache/zig" >> "$GITHUB_ENV"
# Cache the fetched deps (zwasm git dep + zlinter, under the global cache's
# p/) AND the build artifacts (global cache + the repo-local .zig-cache),
# keyed on the manifests. A same-manifest run restores everything; a
# manifest change falls back via restore-keys to the newest prior cache and
# rebuilds incrementally (Zig's cache is content-addressed, so a stale
# restore is safe — it only ever causes a rebuild, never a wrong build).
- name: Cache Zig deps + build
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
~/.cache/zig
.zig-cache
key: ${{ matrix.name }}-zigbuild-${{ hashFiles('build.zig.zon', 'build.zig') }}
restore-keys: |
${{ matrix.name }}-zigbuild-
# Gate deps not universally preinstalled: ripgrep (check_debt_id_refs.sh)
# and, on macOS, bash >= 4 — the macos-15 runner resolves `bash` to the
# system 3.2, which cannot parse the e2e harness idioms (heredoc inside
# `$()`, `case` inside `$()`, `declare -A`); 43 gate scripts fail under it
# (first exposed by the 2026-07-02 nightly, the first FULL run on the
# hosted mac runner). Every script is invoked as `bash foo.sh` or via
# `#!/usr/bin/env bash`, so a brew bash 5 on PATH fixes all of them.
# Install only what is absent (fast no-op when the image ships it).
- name: Install gate deps if missing (ripgrep; bash>=4 on macOS)
shell: bash
run: |
if [ "$RUNNER_OS" = "Linux" ]; then
command -v rg >/dev/null 2>&1 || { sudo apt-get update -qq && sudo apt-get install -y -qq ripgrep; }
else
command -v rg >/dev/null 2>&1 || brew install ripgrep
if [ "$(bash -c 'echo "${BASH_VERSINFO[0]}"')" -lt 4 ]; then
brew install bash
fi
fi
- name: Verify toolchain
shell: bash
run: |
zig version
python3 --version
rg --version | head -1
# Check the PATH-resolved bash (what `bash foo.sh` + env-shebang
# scripts actually get), not this step's own shell.
bash --version | head -1
if [ "$(bash -c 'echo "${BASH_VERSINFO[0]}"')" -lt 4 ]; then
echo "::error::gate requires bash >= 4 on PATH (PATH bash is $(bash -c 'echo "$BASH_VERSION"'))"; exit 1
fi
- name: ci_gate.sh
shell: bash
run: bash scripts/ci_gate.sh