Repository navigation
190 lines (175 loc) · 7.78 KB
/
Copy pathbuild.yml
File metadata and controls
190 lines (175 loc) · 7.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
name: build
# ONE BUILD OF THIS COMMIT'S MCPP PER HOST (rule R1 of
# .agents/docs/2026-10-02-pr-ci-acceleration-and-the-toolchain-specification-design.md).
#
# Called by ci.yml once per host. The binary is uploaded as the artifact
# `mcpp-built-<host>`, and every job of the commit that needs this commit's mcpp
# takes it with .github/actions/use-built-mcpp instead of building its own.
# Measured before this workflow existed (2026-10-01): thirty to thirty-seven
# jobs per commit built mcpp from source, which was 44 to 49 percent of the
# commit's runner minutes, and none of those builds was incremental.
#
# This job is also the ONE WRITER of the host's sandbox and xlings caches (rule
# R3), and it writes them only on a push to main. Before it saves, it installs
# the toolchains its consumers need, so that the cache a pull request restores
# already holds them.
on:
workflow_call:
inputs:
host:
description: linux-x86_64, linux-aarch64, macos-arm64 or windows-x86_64
type: string
required: true
runs-on:
description: the runner label
type: string
required: true
prewarm:
description: >
Toolchains installed before the caches are saved on main, separated
by ';', each as `mcpp toolchain install` takes it (`gcc 16.1.0-musl`).
type: string
required: false
default: ''
gate:
description: >
The tests that must pass before this host's jobs start (design
2026-11-12 §5.11): run with `mcpp test` once the build is uploaded;
a failure fails this job, whose dependants then do not start, and
cancels the run.
type: string
required: false
default: e2e/basics
tests:
description: >
The tests written as the artifact `mcpp-tests-<host>` (`mcpp test <tests>
--no-run --archive`, docs/08), for the jobs that run cases on a host
that cannot build them (.github/actions/e2e-cases).
type: string
required: false
default: ''
jobs:
build:
name: build mcpp (${{ inputs.host }})
runs-on: ${{ inputs.runs-on }}
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
- id: boot
if: ${{ !startsWith(inputs.host, 'macos-') }}
uses: ./.github/actions/bootstrap-mcpp
- id: mac
if: ${{ startsWith(inputs.host, 'macos-') }}
uses: ./.github/actions/setup-macos-llvm
with:
image: ${{ inputs.runs-on }}
- name: Build mcpp from source (self-host)
shell: bash
run: |
set -euo pipefail
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
"$XLINGS_BIN" config --mirror GLOBAL 2>/dev/null || true
"$MCPP" self config --mirror GLOBAL 2>/dev/null || true
# --strict: a key this bootstrap mcpp does not know is an error, not
# a warning. A bootstrap older than the manifest used to drop such a
# key and build something else, and still exit 0 (2026.9.24.1 and
# `[test] windows_code_page`): the moment `.xlings.json` must move is
# the moment this fails.
"$MCPP" build --strict
# target/ is not restored from a cache, so the tree holds exactly the
# binary this build linked.
case "${{ inputs.host }}" in windows-*) exe=mcpp.exe ;; *) exe=mcpp ;; esac
built=$(find target -type f -name "$exe" -path '*/bin/*' | grep -v '/dist/' || true)
[ "$(printf '%s\n' "$built" | grep -c .)" = 1 ] || {
echo "::error::expected one $exe under target/, found: ${built:-none}"; exit 1; }
mkdir -p dist
cp "$built" "dist/$exe"
"dist/$exe" --version
- name: Upload this commit's mcpp
timeout-minutes: 5
uses: actions/upload-artifact@v4
with:
name: mcpp-built-${{ inputs.host }}
path: dist/${{ startsWith(inputs.host, 'windows-') && 'mcpp.exe' || 'mcpp' }}
if-no-files-found: error
retention-days: 3
# THE HOST'S GATE: a new program scaffolded, built and run by this
# commit's mcpp (MCPP_BIN_MCPP), seconds of running. A red commit stops
# here, before the shards and the jobs that need several builds start.
- name: The host's gate
id: gate
if: ${{ inputs.gate != '' }}
shell: bash
run: |
set -euo pipefail
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
# shellcheck disable=SC2086 -- the input is a list of test paths
"$MCPP" test ${{ inputs.gate }}
- name: A failed gate cancels the run
if: ${{ failure() && steps.gate.outcome == 'failure' }}
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
echo "::error::the gate of ${{ inputs.host }} failed: the run is cancelled"
gh run cancel "$GITHUB_RUN_ID" -R "$GITHUB_REPOSITORY" \
|| echo "::warning::the run could not be cancelled (the token's actions permission)"
# The tests a host without a compiler runs (a Windows with Visual Studio
# masked, a job with only a cross toolchain, the released mcpp of
# ci-fresh-install): built here, where the package's programs already
# are, and run elsewhere from the archive with no build. The archive
# holds this build's mcpp, which its cases test (MCPP_BIN_MCPP).
- name: Write the tests other jobs run
if: ${{ inputs.tests != '' }}
shell: bash
run: |
set -euo pipefail
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
# shellcheck disable=SC2086 -- the input is a list of test paths
"$MCPP" test ${{ inputs.tests }} --no-run --archive "dist/mcpp-tests.tar.gz"
- name: Upload the tests other jobs run
if: ${{ inputs.tests != '' }}
timeout-minutes: 5
uses: actions/upload-artifact@v4
with:
name: mcpp-tests-${{ inputs.host }}
path: dist/mcpp-tests.tar.gz
if-no-files-found: error
retention-days: 7
# Only on main, and only for the caches this job restored: a pull request
# reads the main lineage and adds nothing to the store.
- name: Install the toolchains the consumers use
if: ${{ github.event_name == 'push' && inputs.prewarm != '' }}
shell: bash
run: |
set -euo pipefail
IFS=';' read -ra specs <<< "${{ inputs.prewarm }}"
for spec in "${specs[@]}"; do
spec="$(echo "$spec" | xargs)"
[ -n "$spec" ] || continue
echo "::group::mcpp toolchain install $spec"
# shellcheck disable=SC2086 -- a spec is `<name> <version>`
"$MCPP" toolchain install $spec
echo "::endgroup::"
done
- name: Save the sandbox cache
if: ${{ github.event_name == 'push' && steps.boot.outcome == 'success' && steps.boot.outputs.sandbox-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: ~/.mcpp
key: ${{ steps.boot.outputs.sandbox-key }}
- name: Save the xlings cache
if: ${{ github.event_name == 'push' && steps.boot.outcome == 'success' && steps.boot.outputs.xlings-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: ~/.xlings
key: ${{ steps.boot.outputs.xlings-key }}
# macOS keeps no sandbox cache: setup-macos-llvm builds the sandbox from
# the freshly resolved LLVM on every run, which is what the macOS jobs
# exist to prove. Its xlings cache has this job as its writer.
- name: Save the xlings cache (macOS)
if: ${{ github.event_name == 'push' && steps.mac.outcome == 'success' && steps.mac.outputs.xlings-hit != 'true' }}
uses: actions/cache/save@v4
with:
path: ~/.xlings
key: ${{ steps.mac.outputs.xlings-key }}