Skip to content

Cross-platform self-CI matrix (3 OS x 3 versions) - #51

Merged
djankov merged 11 commits into
mainfrom
chore/cross-platform-self-ci-matrix
May 1, 2026
Merged

djankov merged 11 commits into
mainfrom
chore/cross-platform-self-ci-matrix

Conversation

@djankov

@djankov djankov commented May 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR delivers issue #40 — full cross-platform self-CI for setup-gmat — and along the way picks up the source bugs that the new matrix surfaced.

Self-CI matrix

  • Expand the self-test job from a single ubuntu-latest × R2026a cell to a 3×3 OS × version matrix, minus the one combo NASA's upstream artifact does not support (macos-latest × R2022a, x86_64-only DMG vs Apple Silicon runner). 8 cells, fail-fast: false. Per-cell cache-equivalence assertion (run 1 cache-miss → snapshot → reset → run 2 cache-hit → snapshot → byte-identical manifests).
  • New .github/snapshot-install.py does the snapshot/reset logic in one cross-platform algorithm — no GNU vs BSD coreutils divergence, no Git-Bash-on-Windows assumptions, runs identically on all three OSes.
  • Snapshot exclusion list extended with OS-injected metadata: .DS_Store, Thumbs.db, desktop.ini, on top of the existing api_startup_file.txt / __pycache__ / *.pyc.
  • Cache-hit Install GMAT (run 2) step capped at timeout-minutes: 1 as a regression guard. Job-level 25-minute ceiling covers cache-miss.
  • Per-version Python pin via matrix include: R2022a → 3.9 (lowest gmatpy ABI common to all OSes), R2025a/R2026a → 3.12.

Source fixes (uncovered by the matrix)

  • download.ts: per-version macOS DMG filename map. The R2026a-only gmat-mac-x64-${version}-signed.dmg template 404s for older releases (R2022a is unsigned/no -x64, R2025a is signed/no -x64).
  • extract.ts: Windows locateGmatRoot probes the staging tree for api/BuildApiStartupFile.py instead of assuming the layout. R2026a is wrapper-less; R2022a/R2025a wrap in GMAT/<version>/ — the action used to fail with "Did the upstream archive layout change?" on the older zips.

Documentation

  • README supported-versions matrix is a runner × version grid with macOS R2022a marked unsupported and the reason inlined.
  • New "Python ABI per GMAT release" table mapping each release to its shipped gmatpy bindings.
  • Drop the "only ubuntu-latest is exercised" hedges in README and getting-started.md — every cell is now in CI.
  • Drop the "runs under Rosetta" claim — R2025a/R2026a load arm64 natively and R2022a fails outright.
  • Generalize the troubleshooting Python ABI section to cover all three releases.
  • Update troubleshooting "Archive layout drift" with the new Windows probe error message.
  • New troubleshooting section for the macOS x86_64-vs-arm64 dlopen failure.

Test plan

  • All 8 self-test cells green.
  • Cache-equivalence assertion passes on every cell.
  • Cache-hit run-2 step finishes inside the 1-minute step ceiling on every cell.
  • npm run all (format:check + lint + typecheck + build) green locally; dist/ rebuilt and committed.

Closes #40

djankov added 11 commits April 30, 2026 20:51
The existing self-test job hashes $GMAT_ROOT with find/sort/sha256sum,
which breaks on Windows (no sha256sum) and macOS (BSD coreutils have
different flags). Replace it with a small Python helper that runs the
same way on all three runner OSes, so the cache-equivalence assertion
can be exercised cross-platform without per-OS shell branches.

Excludes runtime-generated files (api_startup_file.txt, .pyc,
__pycache__) plus OS-injected metadata (.DS_Store, Thumbs.db,
desktop.ini). The reset mode replaces 'rm -rf', which Git Bash on
Windows-hosted runners handles unevenly with native paths.

Add .github/*.py to .prettierignore defensively — Prettier doesn't
parse Python, but the explicit ignore keeps format:check clean if the
detection rules ever change.
Run the install + cache-equivalence assertion on every supported
runner OS (ubuntu, windows, macos) and every supported GMAT version
(R2022a, R2025a, R2026a) — 9 cells. fail-fast: false so one broken
combination doesn't mask the others.

Snapshot and reset steps invoke the new Python helper, so the same
algorithm runs on each OS without per-OS shell dispatch. Cache-hit
run-2 step is capped at timeout-minutes: 1 as a regression guard
against a slow restore path; the job-level 25-minute ceiling still
covers the cache-miss path.
The R2026a-only `gmat-mac-x64-${version}-signed.dmg` template 404s
for older releases — R2022a is unsigned and arch-implicit
(`gmat-mac-R2022a.dmg`), R2025a is signed but arch-implicit
(`gmat-mac-R2025a-signed.dmg`). Map each version to its actual
SourceForge filename instead of templating.
The Windows zip layout assumption — that `api/BuildApiStartupFile.py`
sits directly under the staging root — only holds for R2026a.
R2022a/R2025a wrap the install in `GMAT/<version>/`, and the action
fails with "Did the upstream archive layout change?" on those.

Replace the assumption with a BFS through the staging tree for
`api/BuildApiStartupFile.py`; the GMAT root is the parent of the
`api` directory containing it. Mirrors how the macOS DMG path
already locates the root via `find` inside the mount.
R2022a's gmatpy ships bindings for Python 3.6 through 3.10 only —
running the smoke check against Python 3.12 fails with
`ModuleNotFoundError: No module named '_py312'`. R2025a and R2026a
both ship _py312 and stay on 3.12.

Use a matrix `include` block to attach a per-version python-version
without exploding into a third matrix dimension.
Bundles the macOS download URL fix and the Windows extract probe.
Linux R2022a's gmatpy ships _py310, but the Windows zip and macOS DMG
both stop at _py39 — same release, narrower binding set. Pinning 3.10
on Linux worked but 3.10 on Windows/macOS hits the same
`ModuleNotFoundError: No module named '_py310'` we were trying to
escape. Drop to 3.9 so a single pin covers all three OSes.
Path.write_text gained the `newline` keyword in Python 3.10. The
self-test matrix pins R2022a cells to Python 3.9 (lowest gmatpy ABI
supported across all three OSes for that release), so the helper has
to work on 3.9. Replace the write_text+newline call with write_bytes
on a UTF-8 encode of the joined entries — same on-disk result, no
version-conditional code.
R2022a's gmatpy ships x86_64-only .so files (it predates Apple
Silicon entirely). macos-latest is now arm64, so loading
`_py39/_gmat_py.so` fails with "incompatible architecture". Drop
that one cell to macos-13 — the last x86_64 macOS runner — via
matrix exclude+include. R2025a and R2026a ship arm64-compatible
builds and stay on macos-latest.
R2022a's macOS DMG ships x86_64-only .so files and macos-latest is
now Apple Silicon, so the only path to test the combo is macos-13 —
which has 5-30 minute queue times on the free runner pool and is
slated for deprecation. The combo isn't supported by NASA's upstream
artifact on modern macOS hardware in the first place; CI shouldn't
pretend otherwise. Matrix drops from 9 to 8 cells.
Updates to reflect what the new matrix exercises and the limits it
uncovered:

- Supported-versions table in the README is now a runner x version
  grid with macOS R2022a marked unsupported (x86_64-only DMG vs.
  Apple Silicon runner).
- Add a Python ABI table mapping each GMAT release to its shipped
  gmatpy bindings, and call out that R2022a's Linux build extends
  past the cross-OS lowest common denominator.
- Drop the "only ubuntu-latest is exercised" hedges in README and
  getting-started — every supported cell is now in CI.
- Drop the "runs under Rosetta" claim — R2025a/R2026a load arm64
  natively and R2022a fails outright; Rosetta isn't doing what the
  old text implied.
- Generalize the troubleshooting Python ABI section to cover all
  three releases, and update the archive-layout-drift section to
  document the new Windows probe error.
- Add a troubleshooting section for the macOS x86_64 vs arm64 dlopen
  failure that R2022a hits on macos-latest.
@djankov
djankov marked this pull request as ready for review May 1, 2026 01:43
@djankov
djankov merged commit fc0b71f into main May 1, 2026
11 checks passed
@djankov
djankov deleted the chore/cross-platform-self-ci-matrix branch May 1, 2026 01:44
djankov added a commit that referenced this pull request May 1, 2026
- README quick start: matrix is now 3-OS (ubuntu/windows/macos) on a single GMAT version, replacing the single-OS single-version stub. Adds a pointer to the multi-version compatibility recipe for consumers who want to vary GMAT version too.
- README roadmap: drops the now-shipped v0.2 row (scope landed in #48/#49/#50/#51/#52) and relabels the new top row as v0.2 (current).
- docs/inputs-outputs.md: version input description gains a one-line note that R2023a/R2024a were never released, linking to the canonical FAQ entry. gmat-root output description drops the stale "in v0.1" qualifier (the path is the same in v0.2).
- docs/faq.md: download-verification entry drops the "in v0.1" qualifier — the action still does not verify a checksum or signature in v0.2; supply-chain hardening remains on the v0.3 roadmap.

Closes #43
@djankov djankov mentioned this pull request May 1, 2026
2 of 6 tasks
djankov added a commit that referenced this pull request May 1, 2026
- Populate CHANGELOG.md with the [0.2.0] - 2026-05-01 section, aggregated from the 11 merged v0.2 PRs (#47, #48, #49, #50, #51, #52, #53, #55, #56, #57, #58).
- Bump package.json version from 0.1.0 to 0.2.0.

The v0.2 row in the README roadmap was already trimmed-and-relabelled (`v0.2 _(current)_`) by #58 ahead of the cut, mirroring the v0.1 cut precedent (#35), so no README change is needed here.

Closes #46.
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.

Cross-platform self-CI matrix (3 OS × 3 versions)

1 participant