Skip to content

Commit 216549b

Browse files
committed
ci: add generate-matrix-summary.py for GITHUB_STEP_SUMMARY
Add a new script that reads the build matrix JSON and produces a Markdown summary written to GITHUB_STEP_SUMMARY in the generate-matrix job of each workflow. Columns show toolchain, C++ standard, formatting (std::format / fmtlib), contracts, build type, and emoji flags for cxx_modules, import_std, no_crtp, and freestanding. A collapsible statistics block lists per-value counts for all relevant fields. Also fix generate-job-matrix.py to write both 'matrix' and 'seed' to GITHUB_OUTPUT (in append mode with trailing newlines, as required), and expose 'seed' as a job output in all four workflow generate-matrix jobs.
1 parent 7787522 commit 216549b

File tree

7 files changed

+143
-2
lines changed

7 files changed

+143
-2
lines changed

.github/generate-job-matrix.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -267,8 +267,9 @@ def main():
267267
if not args.suppress_output:
268268
if output_file:
269269
print(f"Writing outputs to {output_file}")
270-
with open(output_file, "wt") as fh:
271-
fh.write(f"matrix={json.dumps(json_data)}")
270+
with open(output_file, "at") as fh:
271+
fh.write(f"matrix={json.dumps(json_data)}\n")
272+
fh.write(f"seed={args.seed}\n")
272273
else:
273274
print("No output file received!")
274275

.github/generate-matrix-summary.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/usr/bin/env python3
2+
"""Generate GitHub Actions step summary for the CI build matrix.
3+
4+
Reads the matrix JSON from the MATRIX_JSON environment variable (or stdin as
5+
fallback) and the random seed from MATRIX_SEED, then writes a Markdown summary
6+
suitable for appending to $GITHUB_STEP_SUMMARY.
7+
"""
8+
9+
import json
10+
import os
11+
import sys
12+
13+
14+
def yn(val: str) -> str:
15+
return "✅" if val == "True" else "—"
16+
17+
18+
def generate_matrix_summary(matrix: list[dict], seed: int | str | None = None) -> str:
19+
lines = []
20+
21+
lines.append("## 🎯 Build Matrix")
22+
lines.append("")
23+
24+
meta = []
25+
if seed is not None:
26+
meta.append(f"**Random seed:** `{seed}`")
27+
meta.append(f"**Total jobs:** {len(matrix)}")
28+
lines.extend(meta)
29+
lines.append("")
30+
31+
# Main combinations table
32+
lines.append(
33+
"| Toolchain | C++ | Formatting | Contracts | Build"
34+
" | Modules | import_std | no_crtp | freestanding |"
35+
)
36+
lines.append(
37+
"|-----------|-----|------------|-----------|-------|"
38+
":-------:|:----------:|:-------:|:------------:|"
39+
)
40+
for entry in sorted(matrix, key=lambda e: e["config-summary-str"]):
41+
t = entry["toolchain"]
42+
lines.append(
43+
f"| {t['name']}"
44+
f" | {entry['std']}"
45+
f" | {entry['formatting']}"
46+
f" | {entry['contracts']}"
47+
f" | {entry['build_type']}"
48+
f" | {yn(entry['cxx_modules'])}"
49+
f" | {yn(entry['import_std'])}"
50+
f" | {yn(entry['no_crtp'])}"
51+
f" | {yn(entry['freestanding'])} |"
52+
)
53+
54+
lines.append("")
55+
56+
# Per-value coverage statistics in a collapsible block
57+
lines.append("<details><summary>📊 Coverage statistics</summary>")
58+
lines.append("")
59+
lines.append("```")
60+
61+
field_getters: list[tuple[str, object]] = [
62+
("toolchain", lambda e: e["toolchain"]["name"]),
63+
("std", lambda e: str(e["std"])),
64+
("build_type", lambda e: e["build_type"]),
65+
("contracts", lambda e: e["contracts"]),
66+
("cxx_modules", lambda e: e["cxx_modules"]),
67+
("std_format", lambda e: e["std_format"]),
68+
("import_std", lambda e: e["import_std"]),
69+
("no_crtp", lambda e: e["no_crtp"]),
70+
("freestanding", lambda e: e["freestanding"]),
71+
]
72+
for key, getter in field_getters:
73+
counts: dict[str, int] = {}
74+
for entry in matrix:
75+
v = getter(entry)
76+
counts[v] = counts.get(v, 0) + 1
77+
for v, n in sorted(counts.items()):
78+
lines.append(f" {key}={v}: {n}")
79+
80+
lines.append("```")
81+
lines.append("</details>")
82+
83+
return "\n".join(lines)
84+
85+
86+
def main():
87+
matrix_json = os.environ.get("MATRIX_JSON") or sys.stdin.read().strip()
88+
seed = os.environ.get("MATRIX_SEED")
89+
90+
if not matrix_json:
91+
print(
92+
"Error: No matrix JSON provided (set MATRIX_JSON env var or pipe to stdin)",
93+
file=sys.stderr,
94+
)
95+
sys.exit(1)
96+
97+
try:
98+
matrix = json.loads(matrix_json)
99+
print(generate_matrix_summary(matrix, seed=seed))
100+
except json.JSONDecodeError as e:
101+
print(f"Error: Invalid JSON: {e}", file=sys.stderr)
102+
sys.exit(1)
103+
104+
105+
if __name__ == "__main__":
106+
main()

.github/workflows/ci-clang-tidy.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
name: "Generate build matrix for ${{ github.workflow }}"
5151
outputs:
5252
matrix: ${{ steps.set-matrix.outputs.matrix }}
53+
seed: ${{ steps.set-matrix.outputs.seed }}
5354
runs-on: ubuntu-24.04
5455
steps:
5556
- uses: actions/checkout@v4
@@ -59,6 +60,12 @@ jobs:
5960
python-version: 3.x
6061
- id: set-matrix
6162
run: python .github/generate-job-matrix.py --preset clang-tidy --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts
63+
- name: Generate job summary
64+
if: always()
65+
env:
66+
MATRIX_JSON: ${{ steps.set-matrix.outputs.matrix }}
67+
MATRIX_SEED: ${{ steps.set-matrix.outputs.seed }}
68+
run: python .github/generate-matrix-summary.py >> $GITHUB_STEP_SUMMARY
6269
build:
6370
name: "${{ matrix.config-summary-str }}"
6471
runs-on: ${{ matrix.toolchain.os }}

.github/workflows/ci-conan.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ jobs:
5252
name: "Generate build matrix for ${{ github.workflow }}"
5353
outputs:
5454
matrix: ${{ steps.set-matrix.outputs.matrix }}
55+
seed: ${{ steps.set-matrix.outputs.seed }}
5556
runs-on: ubuntu-24.04
5657
steps:
5758
- uses: actions/checkout@v4
@@ -61,6 +62,12 @@ jobs:
6162
python-version: 3.x
6263
- id: set-matrix
6364
run: python .github/generate-job-matrix.py --preset conan --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts
65+
- name: Generate job summary
66+
if: always()
67+
env:
68+
MATRIX_JSON: ${{ steps.set-matrix.outputs.matrix }}
69+
MATRIX_SEED: ${{ steps.set-matrix.outputs.seed }}
70+
run: python .github/generate-matrix-summary.py >> $GITHUB_STEP_SUMMARY
6471
build:
6572
name: "${{ matrix.config-summary-str }}"
6673
runs-on: ${{ matrix.toolchain.os }}

.github/workflows/ci-freestanding.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ jobs:
5050
name: "Generate build matrix for ${{ github.workflow }}"
5151
outputs:
5252
matrix: ${{ steps.set-matrix.outputs.matrix }}
53+
seed: ${{ steps.set-matrix.outputs.seed }}
5354
runs-on: ubuntu-24.04
5455
steps:
5556
- uses: actions/checkout@v4
@@ -59,6 +60,12 @@ jobs:
5960
python-version: 3.x
6061
- id: set-matrix
6162
run: python .github/generate-job-matrix.py --preset freestanding --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts
63+
- name: Generate job summary
64+
if: always()
65+
env:
66+
MATRIX_JSON: ${{ steps.set-matrix.outputs.matrix }}
67+
MATRIX_SEED: ${{ steps.set-matrix.outputs.seed }}
68+
run: python .github/generate-matrix-summary.py >> $GITHUB_STEP_SUMMARY
6269
build:
6370
name: "${{ matrix.config-summary-str }}"
6471
runs-on: ${{ matrix.toolchain.os }}

.github/workflows/ci-test-package-cmake.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
name: "Generate build matrix for ${{ github.workflow }}"
5555
outputs:
5656
matrix: ${{ steps.set-matrix.outputs.matrix }}
57+
seed: ${{ steps.set-matrix.outputs.seed }}
5758
runs-on: ubuntu-24.04
5859
steps:
5960
- uses: actions/checkout@v4
@@ -63,6 +64,12 @@ jobs:
6364
python-version: 3.x
6465
- id: set-matrix
6566
run: python .github/generate-job-matrix.py --preset cmake --seed ${{ inputs.matrix-seed || 0 }} --debug combinations counts
67+
- name: Generate job summary
68+
if: always()
69+
env:
70+
MATRIX_JSON: ${{ steps.set-matrix.outputs.matrix }}
71+
MATRIX_SEED: ${{ steps.set-matrix.outputs.seed }}
72+
run: python .github/generate-matrix-summary.py >> $GITHUB_STEP_SUMMARY
6673
test_package:
6774
name: "${{ matrix.config-summary-str }}"
6875
runs-on: ${{ matrix.toolchain.os }}

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ This page documents the version history and changes for the **mp-units** library
5151
- build: deprecation comments added to CMake file for `format.h` and `ostream.h`
5252
- ci: `build_policy` and CI detection support added to `check_all.sh`
5353
- ci: environment tests moved to `validate_environment.sh` script
54+
- ci: CI build matrix generated dynamically from a Python script
55+
(#767, based on original work by [@burnpanck](https://github.com/burnpanck) in #637)
56+
- ci: toolchain feature support thresholds derived from `conanfile.py` via AST to
57+
eliminate duplication between the Python script and the Conan recipe
58+
- ci: `generate-matrix-summary.py` added to write a Markdown build matrix table
59+
and per-value coverage statistics to `GITHUB_STEP_SUMMARY`
5460
- chore: `site/` subdirectory added to `.gitignore`
5561
- chore: persistency for conan and pipx packages added to devcontainer
5662
- docs: systems reference documentation generator added

0 commit comments

Comments
 (0)