-
Notifications
You must be signed in to change notification settings - Fork 0
193 lines (176 loc) · 9.78 KB
/
Copy pathtest.yml
File metadata and controls
193 lines (176 loc) · 9.78 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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
name: Test
# Runs the full per-port CI gate set via scripts/run-ci.sh:
# TEST → SIGNATURES → DRIFT → SURFACE-FRESH → NO-CHEAT → EMISSION
# Mirrors `bash scripts/run-ci.sh` exactly so there's no drift between local
# and CI behavior. Until now the C++ port had no Test workflow — run_tests and
# the EMISSION / NO-CHEAT gates ran nowhere in CI (only surface-audit.yml /
# doc-audit.yml ran, covering surface + docs). This closes that hole: a
# behavioral-emission regression (wrong to_value() shape from tools/emit_corpus)
# can no longer land green.
#
# run-ci.sh routes the C++ build to OpenSSL >= 3.0 (ubuntu-latest's system
# OpenSSL is 3.x, so it builds on the host — no container path needed here).
# Gate 2 (SIGNATURES) uses libclang via the `clang`/`libclang` pip packages.
env:
# Opt into Node.js 24 ahead of GitHub's 2026-06-02 default switch.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout signalwire-cpp
uses: actions/checkout@v7
with:
path: signalwire-cpp
- name: Checkout porting-sdk (mock servers + audit scripts + EMISSION corpus)
uses: actions/checkout@v7
with:
repository: signalwire/porting-sdk
path: porting-sdk
# Coordinated-pass pin: 'main' normally; set the PORTING_SDK_REF repo variable
# to a wave branch to test a coordinated porting-sdk change, declared on the PR
# (see porting-sdk/COORDINATED_PASS.md). No revert commit.
ref: ${{ vars.PORTING_SDK_REF || 'main' }}
token: ${{ secrets.PORTING_SDK_TOKEN }}
# The EMISSION gate compares this port's to_value() output
# (tools/emit_corpus) against the signalwire-python oracle (FunctionResult),
# which pulls fastapi via signalwire/__init__. Check it out as a sibling so
# the gate has its reference.
- name: Checkout signalwire-python (EMISSION oracle)
uses: actions/checkout@v7
with:
repository: signalwire/signalwire-python
path: signalwire-python
ref: ${{ vars.PORTING_SDK_REF || 'main' }}
- name: Setup Python (audit scripts + mock servers + libclang)
uses: actions/setup-python@v6
with:
python-version: '3.14'
- name: Install build deps (cmake + g++ + OpenSSL 3 headers)
run: |
sudo apt-get update
sudo apt-get install -y cmake g++ libssl-dev
# clang-tidy result cache (vendored ctcache, scripts/clang_tidy_cache.py).
# The LINT gate — clang-tidy over 65 TUs — is cpp's CI wall-clock driver
# (~824s serial, ~252s after the xargs fan-out). ccache does NOT help it
# (that's compilation; this is static analysis), which is why the old ccache
# cache-persistence here was dead weight — removed. Instead persist ctcache's
# per-TU result cache: an UNCHANGED TU (source, its headers, checks, config
# all identical) returns the cached result without running clang-tidy.
# Stable key + run_id suffix so each run restores the most recent cache and
# saves an updated one; source-hashing the key would defeat the point (we
# WANT it to persist across source changes and only miss on the changed TUs).
# Split restore/save (not actions/cache) so the cache SAVES even when the
# gate job fails: the combined action's post-save is SKIPPED on a failed
# prior step, and every cpp run is currently red on the pre-existing
# spec-coupling — so a combined cache would never populate. The separate
# save step below runs with if: always().
- name: Restore clang-tidy cache (ctcache)
id: ctcache_restore
uses: actions/cache/restore@v6
with:
path: ~/.cache/ctcache
key: ctcache-cpp-${{ runner.os }}-${{ github.run_id }}
restore-keys: |
ctcache-cpp-${{ runner.os }}-
# The FMT (clang-format) + LINT (clang-tidy) gates need the gate tools
# PINNED to the EXACT patch the rollout was burned to zero against (18.1.8).
# clang-format formatting differs at PATCH level (ubuntu's 18.1.3 rejects
# code that 18.1.8 produced → spurious -Wclang-format-violations), so we
# install the version-exact pip distributions of clang-format + clang-tidy
# (same self-contained binaries on macOS + Linux → zero local/CI drift; a
# contributor reproduces with `pip install clang-format==18.1.8
# clang-tidy==18.1.8`). We ALSO apt-install the clang-18 COMPILER, because
# the LINT gate generates build-tidy's compile_commands with clang (run-ci
# never reuses the g++ build/ for clang-tidy — that made clang-tidy
# mis-parse the C++17 stdlib). pip's clang-format/clang-tidy land on PATH
# ahead of any apt copy.
- name: Install pinned clang-format + clang-tidy 18.1.8 + clang-18 compiler
run: |
pip install "clang-format==18.1.8" "clang-tidy==18.1.8"
sudo apt-get install -y clang-18
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-18 100
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-18 100
clang-format --version
clang-tidy --version
clang++ --version | head -1
# The SIGNATURES gate enumerates the C++ surface with libclang via Python.
# The `clang` package provides the `clang.cindex` bindings; the `libclang`
# package bundles the native libclang.so. These MUST be version-matched:
# the `clang` package's OWN bundled .so is too old and lacks
# clang_getOffsetOfBase (LibclangError at Index.create()), so we pin both
# to a matching 18.x and point _find_libclang() at the `libclang`
# package's .so explicitly via SW_LIBCLANG_PATH (its priority-0 override).
# clang==18.1.8 provides the cindex bindings; libclang's newest is 18.1.1
# and its native .so HAS clang_getOffsetOfBase (the symbol the `clang`
# package's own older bundled .so is missing). Same 18.1.x line → compatible.
- name: Install libclang Python bindings (SIGNATURES gate)
run: pip install "clang==18.1.8" "libclang==18.1.1"
# Point _find_libclang() at the resolved native libclang via its priority-0
# SW_LIBCLANG_PATH override. The `libclang` pip package installs its native
# lib into the `clang/native/` dir (it does NOT create a separate
# `libclang/native/`), so resolve the path off the importable `clang`
# package — with libclang==18.1.1 pinned, that .so HAS clang_getOffsetOfBase
# (the symbol the unpinned/older `clang`-package .so was missing in CI).
- name: Resolve the matching libclang native lib (SW_LIBCLANG_PATH)
run: |
SO="$(python -c 'import os, glob, clang; d=os.path.join(os.path.dirname(clang.__file__), "native"); hits=[h for pat in ("libclang.so","libclang.dylib") for h in glob.glob(os.path.join(d, pat))]; print(hits[0] if hits else "")')"
echo "Resolved libclang native lib: $SO"
test -f "$SO"
echo "SW_LIBCLANG_PATH=$SO" >> "$GITHUB_ENV"
- name: Install Python test harnesses (mock_relay + mock_signalwire)
run: |
pip install -e porting-sdk/test_harness/mock_relay
pip install -e porting-sdk/test_harness/mock_signalwire
- name: Install signalwire-python (EMISSION oracle) if not importable
run: |
if python -c "import signalwire.core.function_result" 2>/dev/null; then
echo "signalwire-python already importable; skipping install"
else
pip install ./signalwire-python
fi
- name: Select gate tier (promote to nightly if PR touches docs/examples)
id: tier
working-directory: signalwire-cpp
run: |
tier=pr
if [ "${{ github.event_name }}" = "pull_request" ]; then
base="${{ github.event.pull_request.base.sha }}"
if git fetch --no-tags --depth=1 origin "$base" 2>/dev/null \
&& git diff --name-only "$base"...HEAD 2>/dev/null \
| grep -qE '^(docs/|examples/|README|.*\.md$)'; then
tier=nightly
echo "PR touches docs/examples -> running heavy doc gates (tier=nightly)"
fi
fi
echo "tier=$tier" >> "$GITHUB_OUTPUT"
- name: Run CI gate script (TEST → SIGNATURES → DRIFT → SURFACE-FRESH → NO-CHEAT → EMISSION)
working-directory: signalwire-cpp
env:
PORTING_SDK: ${{ github.workspace }}/porting-sdk
SW_CI_TIER: ${{ steps.tier.outputs.tier }}
# COORDINATED-PASS reads the live PR body/labels via 'gh api' to see a
# 'Coordinated-With:' declaration edited after the triggering push.
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Enables the vendored clang-tidy result cache in the LINT gate
# (run-lint.sh routes clang-tidy through scripts/clang_tidy_cache.py when
# CTCACHE_DIR is set + the wrapper exists). Persisted across runs by the
# cache step above; unset => plain clang-tidy (no behavior change). Set
# here (not in env:) so $HOME expands to an ABSOLUTE path — ctcache does
# NOT expanduser CTCACHE_DIR, so a literal "~" would create a bogus dir.
export CTCACHE_DIR="$HOME/.cache/ctcache"
bash scripts/run-ci.sh
# Save the ctcache store even if the gate failed (the LINT gate still ran +
# populated it). Unique run_id key so every run persists an updated cache;
# the next run's restore-keys prefix picks up the most recent.
- name: Save clang-tidy cache (ctcache)
if: always()
uses: actions/cache/save@v6
with:
path: ~/.cache/ctcache
key: ctcache-cpp-${{ runner.os }}-${{ github.run_id }}