Skip to content

Commit 1a514db

Browse files
authored
feat: add append-only GitHub package updates (#543)
Declare automatic updates for 82 GitHub-direct descriptors and pin the merged xpkgindex-update Action. Validate shared version resources and exact candidate locks while preserving every published version and mirror. All 52 candidate jobs and 13 existing-consumer shards passed. Includes explicit, user-approved reporting for the unavailable MySQL source.
1 parent 981a4f2 commit 1a514db

92 files changed

Lines changed: 1850 additions & 29 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/docs/2026-10-19-xpkgindex-update-design.md‎

Lines changed: 548 additions & 0 deletions
Large diffs are not rendered by default.

‎.github/workflows/validate.yml‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,19 @@ jobs:
14991499
run: |
15001500
"$MCPP" index update
15011501
1502+
- name: Report temporarily untestable consumers of the unavailable MySQL source
1503+
shell: bash
1504+
run: |
1505+
if [[ "$RUNNER_OS" == Windows ]]; then
1506+
python tests/autoupdate/source_outage.py members
1507+
else
1508+
python3 tests/autoupdate/source_outage.py members
1509+
fi
1510+
1511+
- name: Install nanodbc macOS development headers
1512+
if: runner.os == 'macOS' && contains(format(' {0} ', env.MEMBERS), ' nanodbc ')
1513+
run: brew install libiodbc
1514+
15021515
- name: mcpp test (workspace or affected members)
15031516
shell: bash
15041517
env:
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
name: xpkgindex-update
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'pkgs/**/*.lua'
7+
- 'tests/autoupdate/**'
8+
- '.github/xpkgindex-update.yml'
9+
- '.github/workflows/xpkgindex-update.yml'
10+
workflow_dispatch:
11+
inputs:
12+
package:
13+
description: "Optional namespace:name; empty scans all declared packages"
14+
type: string
15+
required: false
16+
17+
permissions:
18+
contents: read
19+
20+
concurrency:
21+
group: xpkgindex-update-${{ github.ref }}
22+
cancel-in-progress: true
23+
24+
env:
25+
PYTHONUTF8: '1'
26+
MCPP_VERSION: '2026.10.1.2'
27+
MCPP_INDEX_MIRROR: GLOBAL
28+
29+
jobs:
30+
scan:
31+
runs-on: ubuntu-latest
32+
timeout-minutes: 45
33+
outputs:
34+
matrix: ${{ steps.matrix.outputs.matrix }}
35+
steps:
36+
- uses: actions/checkout@v4
37+
with:
38+
fetch-depth: 0
39+
persist-credentials: false
40+
- uses: actions/setup-python@v5
41+
with:
42+
python-version: '3.12'
43+
- uses: actions/checkout@v4
44+
with:
45+
repository: openxlings/xpkgindex-update
46+
ref: 23c5e04948c55e606bc56ee2c649ddd4849b7ec6
47+
path: .updater
48+
persist-credentials: false
49+
- name: Use the pinned updater source
50+
run: echo "PYTHONPATH=$PWD/.updater/src" >> "$GITHUB_ENV"
51+
- name: All GitHub-direct descriptors are declared; published versions are unchanged
52+
id: coverage
53+
env:
54+
BASE: ${{ github.event.pull_request.base.sha || 'origin/main' }}
55+
run: |
56+
python -m unittest discover -s tests/autoupdate -p 'test_*.py'
57+
python tests/autoupdate/ci.py audit --base "$BASE" --output coverage.json
58+
python tests/autoupdate/ci.py selection --base "$BASE" --output selected-package.txt
59+
echo "package=$(cat selected-package.txt)" >> "$GITHUB_OUTPUT"
60+
- name: Discover and download real upstream candidates
61+
id: scan
62+
continue-on-error: true # The mandatory gate below accepts only the approved source outage.
63+
uses: openxlings/xpkgindex-update@23c5e04948c55e606bc56ee2c649ddd4849b7ec6
64+
with:
65+
mode: check
66+
token: ${{ github.token }}
67+
package: ${{ inputs.package || steps.coverage.outputs.package }}
68+
- name: Reject all scan failures except the approved unavailable source
69+
if: always()
70+
env:
71+
PLAN: ${{ steps.scan.outputs.plan }}
72+
OUTCOME: ${{ steps.scan.outcome }}
73+
run: python tests/autoupdate/source_outage.py scan-gate --plan "$PLAN" --outcome "$OUTCOME"
74+
- name: Plan actual candidate build/run jobs
75+
id: matrix
76+
if: always() && steps.scan.outputs.plan != ''
77+
env:
78+
PLAN: ${{ steps.scan.outputs.plan }}
79+
BASE: ${{ github.event.pull_request.base.sha || 'origin/main' }}
80+
run: |
81+
python tests/autoupdate/ci.py matrix --plan "$PLAN" --base "$BASE" --output matrix.json
82+
echo "matrix=$(cat matrix.json)" >> "$GITHUB_OUTPUT"
83+
- uses: actions/upload-artifact@v4
84+
if: always()
85+
with:
86+
name: xpkgindex-update-build-plan
87+
path: build-plan.json
88+
- uses: actions/upload-artifact@v4
89+
if: always()
90+
with:
91+
name: xpkgindex-update-coverage
92+
path: |
93+
coverage.json
94+
matrix.json
95+
96+
candidate:
97+
name: candidate (${{ matrix.id }} ${{ matrix.candidate }}, ${{ matrix.platform }}, ${{ matrix.toolchain }})
98+
needs: scan
99+
if: >-
100+
always() && !cancelled() && needs.scan.outputs.matrix != '' && needs.scan.outputs.matrix != '{"include": []}'
101+
strategy:
102+
fail-fast: false
103+
max-parallel: 8
104+
matrix: ${{ fromJSON(needs.scan.outputs.matrix) }}
105+
runs-on: ${{ matrix.os }}
106+
timeout-minutes: 90
107+
steps:
108+
- uses: actions/checkout@v4
109+
with:
110+
fetch-depth: 0
111+
persist-credentials: false
112+
- uses: actions/setup-python@v5
113+
with:
114+
python-version: '3.12'
115+
- uses: actions/checkout@v4
116+
with:
117+
repository: openxlings/xpkgindex-update
118+
ref: 23c5e04948c55e606bc56ee2c649ddd4849b7ec6
119+
path: .updater
120+
persist-credentials: false
121+
- uses: actions/download-artifact@v4
122+
with:
123+
name: xpkgindex-update-build-plan
124+
path: .candidate-plan
125+
- name: Use the pinned updater and a standalone consumer
126+
shell: bash
127+
run: |
128+
if [[ "$RUNNER_OS" == Windows ]]; then
129+
echo "PYTHONPATH=$(cygpath -m "$PWD/.updater/src")" >> "$GITHUB_ENV"
130+
echo "CONSUMER=$(cygpath -m "$RUNNER_TEMP/candidate-consumer")" >> "$GITHUB_ENV"
131+
else
132+
echo "PYTHONPATH=$PWD/.updater/src" >> "$GITHUB_ENV"
133+
echo "CONSUMER=$RUNNER_TEMP/candidate-consumer" >> "$GITHUB_ENV"
134+
fi
135+
- name: Append the candidate and prepare its existing consumer test
136+
shell: bash
137+
env:
138+
GH_TOKEN: ${{ github.token }}
139+
PACKAGE: ${{ matrix.id }}
140+
run: |
141+
python -m xpkgindex_update apply --plan .candidate-plan/build-plan.json --package "$PACKAGE"
142+
python tests/autoupdate/ci.py prepare --plan .candidate-plan/build-plan.json --package "$PACKAGE" --output "$CONSUMER"
143+
git diff -- pkgs
144+
- uses: actions/cache/restore@v4
145+
with:
146+
path: |
147+
~/.mcpp/registry
148+
!~/.mcpp/registry/data/xim-pkgindex
149+
!~/.mcpp/registry/data/mcpplibs
150+
key: candidate-${{ runner.os }}-${{ matrix.toolchain }}-${{ env.MCPP_VERSION }}-${{ github.run_id }}
151+
restore-keys: |
152+
mcpp-registry-${{ runner.os }}-${{ matrix.toolchain }}-${{ env.MCPP_VERSION }}-
153+
- name: Install the same mcpp release as index validation
154+
shell: bash
155+
env:
156+
SUFFIX: ${{ matrix.suffix }}
157+
EXT: ${{ matrix.ext }}
158+
run: |
159+
root="mcpp-${MCPP_VERSION}-${SUFFIX}"
160+
archive="$RUNNER_TEMP/$root.$EXT"
161+
curl -fsSL --retry 2 -o "$archive" "https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/$root.$EXT"
162+
if [[ "$EXT" == zip ]]; then
163+
powershell -NoProfile -Command "Expand-Archive -Force -Path '$archive' -DestinationPath '$RUNNER_TEMP'"
164+
else
165+
tar -xzf "$archive" -C "$RUNNER_TEMP"
166+
fi
167+
root="$RUNNER_TEMP/$root"
168+
mkdir -p "$HOME/.mcpp/registry"
169+
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
170+
echo "MCPP_HOME=$HOME/.mcpp" >> "$GITHUB_ENV"
171+
if [[ "$RUNNER_OS" == Windows ]]; then
172+
echo "MCPP=$(cygpath -m "$root/bin/mcpp.exe")" >> "$GITHUB_ENV"
173+
else
174+
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
175+
fi
176+
- name: Install macOS ODBC development headers
177+
if: runner.os == 'macOS' && matrix.id == 'compat:nanodbc'
178+
run: brew install libiodbc
179+
- name: Resolve, build and run the actual candidate
180+
shell: bash
181+
env:
182+
TOOLCHAIN: ${{ matrix.toolchain }}
183+
PACKAGE: ${{ matrix.id }}
184+
run: |
185+
"$MCPP" index update
186+
if [[ "$TOOLCHAIN" != default ]]; then
187+
"$MCPP" toolchain install "$TOOLCHAIN"
188+
"$MCPP" toolchain default "$TOOLCHAIN"
189+
fi
190+
cd "$CONSUMER"
191+
"$MCPP" test --verbose 2>&1 | tee candidate.log
192+
- name: The lockfile proves the candidate was selected
193+
shell: bash
194+
env:
195+
PACKAGE: ${{ matrix.id }}
196+
run: python tests/autoupdate/ci.py verify --plan .candidate-plan/build-plan.json --package "$PACKAGE" --consumer "$CONSUMER"
197+
- uses: actions/upload-artifact@v4
198+
if: always()
199+
with:
200+
name: candidate-${{ strategy.job-index }}
201+
path: |
202+
${{ env.CONSUMER }}/candidate.log
203+
${{ env.CONSUMER }}/mcpp.lock
204+
${{ env.CONSUMER }}/mcpp.toml
205+
- name: Collect compiler and linker evidence
206+
if: always()
207+
shell: bash
208+
run: python tests/autoupdate/ci.py diagnostics --consumer "$CONSUMER" --output candidate-diagnostics
209+
- uses: actions/upload-artifact@v4
210+
if: always()
211+
with:
212+
name: candidate-diagnostics-${{ strategy.job-index }}
213+
path: candidate-diagnostics
214+
if-no-files-found: ignore

‎.github/xpkgindex-update.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version: 1
2+
adapter: mcpp-index
3+
max_prs: 3

‎pkgs/b/boost-ext.ut.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ package = {
8686
repo = "https://github.com/boost-ext/ut",
8787
type = "package",
8888

89+
extensions = {
90+
autoupdate = {
91+
tag = "v${version}",
92+
url = "https://github.com/boost-ext/ut/archive/refs/tags/${tag}.tar.gz",
93+
},
94+
},
95+
8996
xpm = {
9097
linux = {
9198
["2.3.1"] = {

‎pkgs/c/cmp.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ package = {
99
repo = "https://github.com/mcpplibs/cmp",
1010
type = "package",
1111

12+
extensions = {
13+
autoupdate = {
14+
tag = "v${version}",
15+
url = "https://github.com/mcpplibs/cmp/releases/download/${tag}/cmp-${version}.tar.gz",
16+
},
17+
},
18+
1219
xpm = {
1320
linux = {
1421
["0.1.0"] = {

‎pkgs/c/compat.apriltag.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@ package = {
1616
repo = "https://github.com/AprilRobotics/apriltag",
1717
type = "package",
1818

19+
extensions = {
20+
autoupdate = {
21+
tag = "v${version}",
22+
url = "https://github.com/AprilRobotics/apriltag/archive/refs/tags/${tag}.tar.gz",
23+
},
24+
},
25+
1926
xpm = {
2027
linux = {
2128
["3.4.5"] = {

‎pkgs/c/compat.boost-align.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ package = {
1515
repo = "https://github.com/boostorg/align",
1616
type = "package",
1717

18+
extensions = {
19+
autoupdate = {
20+
tag = "boost-${version}",
21+
url = "https://github.com/boostorg/align/archive/refs/tags/${tag}.tar.gz",
22+
},
23+
},
24+
1825
xpm = {
1926
linux = {
2027
["1.92.0"] = {

‎pkgs/c/compat.boost-any.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ package = {
77
repo = "https://github.com/boostorg/any",
88
type = "package",
99

10+
extensions = {
11+
autoupdate = {
12+
tag = "boost-${version}",
13+
url = "https://github.com/boostorg/any/archive/refs/tags/${tag}.tar.gz",
14+
},
15+
},
16+
1017
xpm = {
1118
linux = {
1219
["1.92.0"] = {

‎pkgs/c/compat.boost-asio.lua‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ package = {
4646
repo = "https://github.com/boostorg/asio",
4747
type = "package",
4848

49+
extensions = {
50+
autoupdate = {
51+
tag = "boost-${version}",
52+
url = "https://github.com/boostorg/asio/archive/refs/tags/${tag}.tar.gz",
53+
},
54+
},
55+
4956
xpm = {
5057
linux = {
5158
["1.92.0"] = {

0 commit comments

Comments
 (0)