Skip to content

feat: per-OS multi-select version matrix + versioned tag namespace (PARKED) - #37

Draft
jclaveau wants to merge 2 commits into
mainfrom
feat/per-os-version-matrix
Draft

feat: per-OS multi-select version matrix + versioned tag namespace (PARKED)#37
jclaveau wants to merge 2 commits into
mainfrom
feat/per-os-version-matrix

Conversation

@jclaveau

@jclaveau jclaveau commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Status: PARKED — do not merge yet

This branch holds the work I tried to ship to main as d8d250c + ed44dc4 (then reverted via eb8067b + 080d8ce because the workflow file was rejected by GitHub Actions at run-start). The commits below are cherry-picks of the reverted pair so the work isn't lost.

Local yaml.safe_load parses the workflow fine; only GH's stricter parser objects. The signal is the run's name becoming the file path instead of Test and Publish, with 0 jobs queued and no useful error in the API.

What's in here

  • .github/ISSUE_TEMPLATE/build-request.ymlubuntu_version + alpine_version multi-select dropdowns with _extra free-text companions for unlisted versions.
  • .github/workflows/on-demand-build.yml — parses the four new fields, merges per-OS dropdown + extra CSV, forwards ubuntu_version / alpine_version to test-and-publish.yml.
  • .github/workflows/test-and-publish.ymlos_version input replaced by ubuntu_version + alpine_version. os_matrix becomes a {os, os_version} tuple list; five pre-computed Cartesians (hardened_matrix, test_gha_matrix, test_mode_matrix, test_pw_matrix, promote_matrix) feed the 27 matrix-using jobs. versions rewritten as matrix-per-tuple with a new versions-aggregate collator. promote indexes the versions_map via format(). changes detection iterates tuples and emits <os>-<os_version>-<suffix> keys.
  • .github/workflows/refresh-os-version-options.yml (new) — weekly cron pulling endoflife.date (Ubuntu LTS + non-EOL Alpine) → yq patches the dropdown options → direct push on drift, no-op on fetch failure.
  • README.md — top-of-file migration banner + versioned naming throughout.

What broke

Both attempted matrix shapes were rejected:

  1. d8d250c used matrix: { include: ${{ fromJSON(...) }} }.
  2. ed44dc4 switched to matrix: ${{ fromJSON(...) }} with the JSON wrapped as {"include": [...]} per the documented dynamic-matrix pattern.

Both produced the same instant rejection.

Suspects to bisect

  • Matrix shape. Maybe GH wants the synthetic-axis form matrix:\n tuple: ${{ fromJSON(...) }} with downstream access via matrix.tuple.os.
  • fromJSON(...)[format('{0}-{1}', matrix.os, matrix.os_version)].os in promote.pin.env — function-call inside the bracket indexer may not be supported.
  • versions-aggregate depending on a matrix versions job via plain needs: versions — the aggregator is not itself a matrix; this combo could be the trigger.
  • workflow_call input rename — dropping os_version while another workflow ref might still expect it.

Suggested next attempt

Don't push to main again until the root cause is found. Branch off main, apply changes in this order, push each, watch the workflow's name in gh run list — the moment it flips from Test and Publish to the file path, the commit just pushed is the culprit:

  1. Form + parse + workflow_call input rename ONLY (no matrix changes).
  2. Add ONE matrix job at a time, simplest shape first (build-gha-tools).
  3. Once a working dynamic-matrix shape is established, propagate to the rest.

Failed runs (for evidence)

jclaveau added 2 commits June 2, 2026 12:17
The on-demand build form gains `ubuntu_version` + `alpine_version`
multi-select dropdowns (each with a `_extra` free-text companion for
unlisted versions). Each (os, os_version) becomes its own matrix
cell; tags now include the OS version, e.g.
`jclaveau/ubuntu-24.04-gha-tools:latest`.

Internals:
- github-context emits `os_matrix` as a tuple list plus five
  pre-computed Cartesians (hardened, test_gha, test_mode, test_pw,
  promote) so each downstream job can `include:` a flat list — GH
  Actions can't express Cartesian-of-include at job level.
- All 25+ build/test/promote matrix jobs switch to `matrix:
  include:` and reference `matrix.os_version` alongside `matrix.os`.
- `versions` becomes a matrix-per-tuple job; a new
  `versions-aggregate` job collates per-cell artifacts into a single
  `versions_map` keyed by `<os>-<os_version>`. `promote`'s pin step
  indexes this map via `format()`.
- The `changes` detection script iterates os_matrix tuples and
  emits keys like `ubuntu-24.04-gha-tools` matching the new
  build-layer `image:` input.
- OS defaults come from each Dockerfile's `ARG OS_VERSION=` —
  bumping the ARG is the deliberate maintainer step.

New `refresh-os-version-options.yml` keeps the dropdown lists in
sync with upstream supported releases (endoflife.date; Ubuntu LTS
+ non-EOL only). Runs weekly + manual; commits directly to main on
drift; no-op on fetch failure (never empties the dropdown).

Breaking: old `jclaveau/<os>-<image>:*` tags are now frozen.
Consumers must migrate to `jclaveau/<os>-<os_version>-<image>:*`.
README updated with a top-of-file migration banner.

Assisted-by: Claude:claude-opus-4-7
The previous shape

    matrix:
      include: ${{ fromJSON(needs.github-context.outputs.X) }}

is YAML-valid but GH Actions rejects it at run-start (workflow-file
error, 0 jobs queued). The documented dynamic-matrix pattern is

    matrix: ${{ fromJSON(needs.github-context.outputs.X) }}

where the JSON itself is `{"include":[...]}`. Updated github-context
to emit each per-shape matrix wrapped, switched all 27 matrix-using
jobs to the unindented form, and updated the changes-detection
Python to read `["include"]` off the wrapped os_matrix env var.
Internal cartesian shell vars stay bare arrays so downstream
cartesians compose cleanly; only the GITHUB_OUTPUT emits are wrapped.

Assisted-by: Claude:claude-opus-4-7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant