Skip to content

Commit 2bf99ee

Browse files
authored
bootstrap from 2026.10.10.2; CI builds the tree with the pinned mcpp as a developer does, and with the newest release (#796)
* bootstrap from 2026.10.10.2 The post-release pin (docs/92-release.md §4): the index pointer serves xim-pkgindex d6f6fd5 (#950). A developer's `xlings install` in this tree and every CI bootstrap take the newest release, whose archives bundle xlings 2026.10.10.2. * ci: the pinned mcpp builds the tree with --strict, as a developer's clone does, and so does the newest release while the pin lags it .xlings.json names the mcpp a clone builds with: inside the checkout the shim runs no other. A pinned mcpp older than the manifest warned about a key it did not know, dropped it and exited 0 (2026.9.24.1 against [test] windows_code_page), so no job failed when the pin had to move. - build.yml: the self-host build runs `mcpp build --strict`. - ci-bootstrap.yml developer (Linux, macOS, Windows, no cache): `xlings install` in the checkout, the shim's version equals the pin, `mcpp build --strict`, the binary reports mcpp.toml's version. - ci-bootstrap.yml latest (Linux): the newest release builds the tree with --strict while the pin lags it; skipped when they are equal. - docs/92 §4 (en, zh): the pin moves when the tree needs it, and these jobs say when.
1 parent dd53e6d commit 2bf99ee

7 files changed

Lines changed: 200 additions & 17 deletions

File tree

‎.github/tools/check_version_pins.sh‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,11 +157,11 @@ fi
157157
# full index, and the mechanism is not yet understood; what is established
158158
# is the pattern and its fix.
159159
#
160-
# The operational rule that satisfies both directions: after publishing
161-
# release N, the post-release commit sets this pin to N. Never ahead
162-
# (check (c) enforces that), and in practice never behind either. This is
163-
# not checkable here — it needs the index — so it surfaces as the error
164-
# above, and this note is where to look when it does.
160+
# That job now checks the repository out last, so the pin no longer
161+
# reaches it. The rule that stands: never ahead (check (c) enforces it),
162+
# and behind for as long as the pinned mcpp builds the tree, which
163+
# ci-bootstrap.yml and build.yml measure with `mcpp build --strict`
164+
# (docs/92-release.md §4).
165165

166166
# (c) …and the bootstrap pin must never run AHEAD of the version being built.
167167
# Four-key numeric sort, so the date scheme orders correctly (a plain

‎.github/workflows/build.yml‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,12 @@ jobs:
5959
export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
6060
"$XLINGS_BIN" config --mirror GLOBAL 2>/dev/null || true
6161
"$MCPP" self config --mirror GLOBAL 2>/dev/null || true
62-
"$MCPP" build
62+
# --strict: a key this bootstrap mcpp does not know is an error, not
63+
# a warning. A bootstrap older than the manifest used to drop such a
64+
# key and build something else, and still exit 0 (2026.9.24.1 and
65+
# `[test] windows_code_page`): the moment `.xlings.json` must move is
66+
# the moment this fails.
67+
"$MCPP" build --strict
6368
# target/ is not restored from a cache, so the tree holds exactly the
6469
# binary this build linked.
6570
case "${{ inputs.host }}" in windows-*) exe=mcpp.exe ;; *) exe=mcpp ;; esac

‎.github/workflows/ci-bootstrap.yml‎

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
name: ci-bootstrap
2+
3+
# Which released mcpp builds this tree, measured the way a developer builds it.
4+
#
5+
# `.xlings.json` names the mcpp a clone of this repository builds with: inside
6+
# the checkout the `mcpp` shim refuses to run any other version
7+
# ("mcpp@<pin> is the version this project asks for ... set this project up:
8+
# xlings install"). The pin does not move with every release; it moves when the
9+
# tree starts to need something the pinned mcpp does not have. Two jobs answer
10+
# whether that moment has come:
11+
#
12+
# developer the pinned mcpp, installed by `xlings install` in the checkout
13+
# (project scope, no -g) and run through the shim, builds the tree
14+
# with --strict, on Linux, macOS and Windows. build.yml builds with
15+
# the same version but installs it globally and runs it by path; a
16+
# shim or project-scope defect, or a cold runner, is only seen here.
17+
# latest the newest release builds the tree with --strict. It runs only
18+
# while the pin lags the newest release; when they are equal the
19+
# developer job has already answered.
20+
#
21+
# --strict is the assertion. A mcpp older than the manifest warns about a key it
22+
# does not know, drops it and exits 0 (2026.9.24.1 against
23+
# `[test] windows_code_page`); under --strict that is an error.
24+
#
25+
# No cache, on purpose: the subject is a fresh clone.
26+
27+
on:
28+
workflow_call:
29+
30+
permissions:
31+
contents: read
32+
33+
jobs:
34+
developer:
35+
name: the pinned mcpp builds the tree (${{ matrix.os }}, xlings install + mcpp build --strict)
36+
runs-on: ${{ matrix.os }}
37+
timeout-minutes: 45
38+
strategy:
39+
fail-fast: false
40+
matrix:
41+
os: [ubuntu-24.04, macos-15, windows-2025]
42+
env:
43+
XLINGS_NON_INTERACTIVE: '1'
44+
XLINGS_VERSION: '2026.10.10.2'
45+
steps:
46+
- uses: actions/checkout@v4
47+
48+
- name: Install xlings
49+
if: runner.os != 'Windows'
50+
shell: bash
51+
run: |
52+
set -euo pipefail
53+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.10.10.2
54+
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
55+
echo "$HOME/.xlings/bin" >> "$GITHUB_PATH"
56+
57+
- name: Install xlings
58+
if: runner.os == 'Windows'
59+
shell: pwsh
60+
run: |
61+
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
62+
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
63+
64+
- name: Install the mcpp .xlings.json names, in this project
65+
shell: bash
66+
run: |
67+
set -euo pipefail
68+
xlings install -y
69+
pin=$(grep -oE '"mcpp"[[:space:]]*:[[:space:]]*"[^"]+"' .xlings.json \
70+
| grep -oE '[0-9]+(\.[0-9]+)+' | head -1)
71+
got=$(mcpp --version | head -1 | awk '{print $2}' | tr -d '\r')
72+
[ -n "$pin" ] && [ "$got" = "$pin" ] || {
73+
echo "::error::.xlings.json names mcpp ${pin:-?}; the shim in this checkout runs ${got:-nothing}"; exit 1; }
74+
echo "the shim runs mcpp $got, the version .xlings.json names"
75+
76+
- name: Build the tree with it (mcpp build --strict)
77+
shell: bash
78+
run: |
79+
set -euo pipefail
80+
mcpp self config --mirror GLOBAL
81+
mcpp build --strict
82+
case "$RUNNER_OS" in Windows) exe=mcpp.exe ;; *) exe=mcpp ;; esac
83+
built=$(find target -type f -name "$exe" -path '*/bin/*' | grep -v '/dist/' || true)
84+
[ "$(printf '%s\n' "$built" | grep -c .)" = 1 ] || {
85+
echo "::error::expected one $exe under target/, found: ${built:-none}"; exit 1; }
86+
want=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml)
87+
got=$("$built" --version | head -1 | tr -d '\r')
88+
[ "$got" = "mcpp $want" ] || {
89+
echo "::error::the built binary says '$got', mcpp.toml says $want"; exit 1; }
90+
echo "built $got"
91+
92+
latest:
93+
name: the newest release builds the tree (linux, when the pin lags it)
94+
runs-on: ubuntu-24.04
95+
timeout-minutes: 45
96+
env:
97+
XLINGS_NON_INTERACTIVE: '1'
98+
steps:
99+
- uses: actions/checkout@v4
100+
101+
- name: Compare the pin with the newest release
102+
id: cmp
103+
shell: bash
104+
env:
105+
GH_TOKEN: ${{ github.token }}
106+
run: |
107+
set -euo pipefail
108+
pin=$(grep -oE '"mcpp"[[:space:]]*:[[:space:]]*"[^"]+"' .xlings.json \
109+
| grep -oE '[0-9]+(\.[0-9]+)+' | head -1)
110+
latest=$(gh api "repos/${{ github.repository }}/releases/latest" --jq .tag_name | sed 's/^v//')
111+
[ -n "$pin" ] && [ -n "$latest" ] || {
112+
echo "::error::could not read the pin (${pin:-?}) or the newest release (${latest:-?})"; exit 1; }
113+
echo "pin=$pin latest=$latest"
114+
echo "latest=$latest" >> "$GITHUB_OUTPUT"
115+
if [ "$pin" = "$latest" ]; then
116+
echo "run=false" >> "$GITHUB_OUTPUT"
117+
echo "::notice::.xlings.json names the newest release ($latest); the developer job covers it"
118+
else
119+
echo "run=true" >> "$GITHUB_OUTPUT"
120+
fi
121+
122+
- name: Install xlings
123+
if: steps.cmp.outputs.run == 'true'
124+
shell: bash
125+
run: |
126+
set -euo pipefail
127+
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.10.10.2
128+
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
129+
130+
- name: Install the newest release and build the tree with it (mcpp build --strict)
131+
if: steps.cmp.outputs.run == 'true'
132+
shell: bash
133+
run: |
134+
set -euo pipefail
135+
# Makes the released version the one the shim runs here, over the
136+
# checkout's own pin, and asserts it.
137+
bash .github/tools/install_released_mcpp.sh "${{ steps.cmp.outputs.latest }}" "$(pwd)"
138+
mcpp self config --mirror GLOBAL
139+
mcpp build --strict
140+
built=$(find target -type f -name mcpp -path '*/bin/*' | grep -v '/dist/' || true)
141+
[ "$(printf '%s\n' "$built" | grep -c .)" = 1 ] || {
142+
echo "::error::expected one mcpp under target/, found: ${built:-none}"; exit 1; }
143+
"$built" --version

‎.github/workflows/ci.yml‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,13 @@ jobs:
186186
# The MinGW payload every Windows e2e shard installs.
187187
prewarm: mingw 16.1.0
188188

189+
# The mcpp .xlings.json names builds the tree as a developer's clone does,
190+
# and so does the newest release while the pin lags it (ci-bootstrap.yml).
191+
bootstrap:
192+
needs: changes
193+
if: needs.changes.outputs.code == 'true'
194+
uses: ./.github/workflows/ci-bootstrap.yml
195+
189196
linux:
190197
needs: build-linux
191198
uses: ./.github/workflows/ci-linux.yml

‎.xlings.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"workspace": {
3-
"mcpp": "2026.10.8.1"
3+
"mcpp": "2026.10.10.2"
44
}
55
}

‎docs/92-release.md‎

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,17 +189,33 @@ up. `ci-fresh-install`'s `wait-index` job encodes exactly this with a bounded
189189
## 4. The bootstrap pin: its definition and its update conditions
190190

191191
`.xlings.json`'s `[workspace].mcpp` is the **starting point of self-hosting** —
192-
the released mcpp that `xlings install mcpp` puts in the workspace so CI can build
193-
mcpp from source. Its only requirement is that it can build the **current** tree.
192+
the released mcpp that `xlings install` puts in the workspace so CI can build
193+
mcpp from source. It is also what a developer builds with: inside a clone, the
194+
`mcpp` shim runs this version and no other, and refuses to run until
195+
`xlings install` has installed it. Its only requirement is that it can build the
196+
**current** tree.
194197

195198
**It does not have to move with every release.** The index retains every
196199
published version (105 entries at the time of writing, back to the 0.0.x series),
197200
so an older pin keeps resolving indefinitely — verified by installing a
198201
two-releases-old version against the current index.
199202

200-
Bumping it anyway is reasonable and is what this repository does in practice: a
201-
green CI round on the bumped pin is a direct proof that the new release can build
202-
mcpp itself on every platform. Treat it as a *useful check*, not a prerequisite.
203+
**It moves when the tree needs it**: when `mcpp.toml` or the sources use something
204+
the pinned mcpp does not have — a key, a table, a toolchain line. CI tells when
205+
that moment has come, because the pinned mcpp builds the tree with `--strict`,
206+
which makes a key it does not know an error. Without it the pinned mcpp warns,
207+
drops the key, builds something other than the manifest describes, and exits 0
208+
(2026.9.24.1 against the `[test] windows_code_page` of 2026.10.5.2). Three jobs build
209+
the tree on every pull request that changes code:
210+
211+
| Job | mcpp | Installation and build |
212+
| --- | --- | --- |
213+
| `build.yml` (four hosts) | the pin | installed globally by `install_pinned_mcpp.sh`, `mcpp build --strict` |
214+
| `ci-bootstrap.yml` `developer` (Linux, macOS, Windows) | the pin | a cold clone: `xlings install` in the checkout, then `mcpp build --strict` through the shim |
215+
| `ci-bootstrap.yml` `latest` (Linux) | the newest release | only while the pin lags it |
216+
217+
A pull request that needs a newer pin fails there, and moves the pin in the same
218+
pull request.
203219

204220
**The one hard constraint is direction**: the pin must never name a version that
205221
is not yet installable. Bump it only after the release is published, mirrored,

‎docs/zh/92-release.md‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -178,16 +178,28 @@ $(find "$XLINGS_HOME" -name mcpp -type f -path '*/bin/*' | head -1) --version
178178
## 4. 自举 pin 的定义与更新条件
179179

180180
`.xlings.json` 的 `[workspace].mcpp` 是**自举的起点**——那个由
181-
`xlings install mcpp` 装进 workspace、供 CI 从源码构建 mcpp 的已发布
182-
mcpp。它唯一的要求是:能构建**当前**这棵源码树。
181+
`xlings install` 装进 workspace、供 CI 从源码构建 mcpp 的已发布 mcpp。
182+
它也是开发者构建所用的版本:在克隆的仓库里,`mcpp` shim 只运行这个版本,
183+
未经 `xlings install` 安装时拒绝运行。它唯一的要求是:能构建**当前**这棵
184+
源码树。
183185

184186
**它不必每次发布都跟着动。** 索引保留每一个已发布版本(撰写时 105 个
185187
条目,一直回溯到 0.0.x 系列),旧 pin 可以无限期继续解析——这一点用
186188
「在当前索引下安装一个隔了两个版本的旧版」实测验证过。
187189

188-
跟着 bump 仍然是合理的,也是本仓库的实际做法:bump 后 CI 一轮全绿,直接
189-
证明了新发布能在每个平台上构建 mcpp 自己。把它当作**一项有用的检查**,
190-
而不是前置条件。
190+
**树需要时它才动**:`mcpp.toml` 或源码用到了固定版本没有的东西——一个键、
191+
一张表、一条工具链线。何时到了这一刻由 CI 判定:固定版本以 `--strict` 构建
192+
这棵树,它不认识的键是错误。不加 `--strict` 时,固定版本对不认识的键只给
193+
警告、丢弃该键、构建出与清单不同的结果,并以 0 退出(2026.9.24.1 遇到
194+
2026.10.5.2 的 `[test] windows_code_page`)。每个改动代码的 PR 上有三组构建:
195+
196+
| 作业 | mcpp | 方式 |
197+
| --- | --- | --- |
198+
| `build.yml`(四个主机) | 固定版本 | `install_pinned_mcpp.sh` 全局安装,`mcpp build --strict` |
199+
| `ci-bootstrap.yml` `developer`(Linux、macOS、Windows) | 固定版本 | 冷克隆:在仓库内 `xlings install`,经 shim 执行 `mcpp build --strict` |
200+
| `ci-bootstrap.yml` `latest`(Linux) | 最新发布版 | 仅在固定版本落后于最新发布版时运行 |
201+
202+
需要更新固定版本的 PR 在这里失败,并在同一个 PR 中更新它。
191203

192204
**唯一的硬约束是方向**:pin 绝不能指向一个尚不可安装的版本。只在发布
193205
已完成、已镜像、**且已合入 xim-pkgindex 之后**再 bump——否则所有 CI 会

0 commit comments

Comments
 (0)