ci(install-e2e): plan chart on the run summary - combination x tag markdown table

generate-e2e-matrix.mjs grows --format markdown: one row per
{os, install -> update} combination, one column per starting tag,
appended to GITHUB_STEP_SUMMARY by the expand job. Cells mark
dispatched legs; run-vs-grey stays the run workflows' call, so the
only special cell is pre-desktop (the one annotation the plan owns).
JSON mode unchanged.
This commit is contained in:
ethernet
2026-08-11 23:06:42 -04:00
parent cde3b4ff09
commit 80a0a198dd
2 changed files with 57 additions and 1 deletions
+5
View File
@@ -134,6 +134,11 @@ jobs:
for key in linux windows macos; do
echo "$key=$(echo "$matrices" | node -e 'let d="";process.stdin.on("data",c=>d+=c).on("end",()=>console.log(JSON.stringify(JSON.parse(d)[process.argv[1]])))' "$key")" >> "$GITHUB_OUTPUT"
done
# The plan, human-readable: a combination x starting-tag chart on
# the run's summary page.
node scripts/sandbox/generate-e2e-matrix.mjs \
--tags '${{ needs.pick-releases.outputs.tags }}' \
--format markdown >> "$GITHUB_STEP_SUMMARY"
linux:
name: ${{ matrix.name }}
+52 -1
View File
@@ -165,14 +165,65 @@ export function buildMatrices(envs, tags) {
return byOs;
}
/**
* Render the plan as a markdown cross-table for $GITHUB_STEP_SUMMARY:
* one row per {os, install -> update} combination, one column per
* starting tag. Every cell is dispatched; whether it RUNS or greys out
* is the run workflow's call (capability lives there, not here), so the
* chart only distinguishes the one thing the plan itself knows: windows
* desktop-surface legs from tags that predate the desktop app.
*
* @param {{os: Os, install: string, update: string}[]} envs
* @param {TagAnnotation[]} tags
* @returns {string}
*/
export function renderMarkdownPlan(envs, tags) {
const needsDesktop = (/** @type {string} */ m) =>
m.startsWith('desktop-installer') || m === 'app-update';
const lines = [
'### Install & Update E2E plan',
'',
`${envs.length} combinations x ${tags.length} starting tags = ${envs.length * tags.length} legs`,
'',
`| combination | ${tags.map((t) => t.ref).join(' | ')} |`,
`|---|${tags.map(() => '---').join('|')}|`,
];
for (const env of envs) {
const cells = tags.map((tag) => {
if (
env.os === 'windows' && !tag.desktop &&
(needsDesktop(env.install) || needsDesktop(env.update))
) {
return 'pre-desktop';
}
return '✅';
});
lines.push(`| \`${env.os}: ${env.install} -> ${env.update}\` | ${cells.join(' | ')} |`);
}
lines.push(
'',
'✅ dispatched -- the OS run workflow decides run vs native skip',
'(unimplemented method pairs grey out there). `pre-desktop`: the tag',
"ships no desktop app, so desktop-surface legs grey out regardless.",
'',
);
return lines.join('\n');
}
function main() {
const { values } = parseArgs({
options: {
tags: { type: 'string', default: '[]' },
format: { type: 'string', default: 'json' },
},
});
const tags = /** @type {TagAnnotation[]} */ (JSON.parse(values.tags));
const matrices = buildMatrices(generateEnvironments(SPEC), tags);
const envs = generateEnvironments(SPEC);
if (values.format === 'markdown') {
process.stdout.write(renderMarkdownPlan(envs, tags));
return;
}
const matrices = buildMatrices(envs, tags);
process.stdout.write(`${JSON.stringify(matrices, null, 2)}\n`);
}