Skip to content

Add Yukon max-iteration solver-log golden fixture (#150) #171

Add Yukon max-iteration solver-log golden fixture (#150)

Add Yukon max-iteration solver-log golden fixture (#150) #171

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
test:
name: test (${{ matrix.os }}, py${{ matrix.python-version }}, ${{ matrix.gmat-version }})
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
# Full cross-product: 3 OSes × 3 Python minors × 2 GMAT releases = 18 cells.
# R2026a is the primary target; R2025a is the previous release we still
# support. R2022a–R2024a stay out of CI: R2022a's gmatpy ABI floor is
# Python 3.9, below this project's `python>=3.10` pin (see
# docs/known-limitations.md).
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ['3.10', '3.11', '3.12']
gmat-version: [R2025a, R2026a]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: uv.lock
- uses: astro-tools/setup-gmat@v0
with:
version: ${{ matrix.gmat-version }}
cache: true
- name: Install project
run: uv sync --all-groups
- name: Run pytest
# `-m "integration or not integration"` overrides the default
# marker filter in pyproject.toml so CI runs both unit and
# integration suites in a single invocation.
run: uv run pytest -m "integration or not integration" --cov --cov-report=term-missing
# Threshold gates run on a single matrix combination — the .coverage
# data is identical across runners, so there's no point re-asserting
# it on every cell. Per-package gate (parsers/) matches the v0.1
# charter DoD; overall gate is the project-wide floor.
- name: Enforce overall coverage (>=90%)
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
run: uv run coverage report --fail-under=90
- name: Enforce parsers coverage (>=95%)
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
run: uv run coverage report --include='src/gmat_run/parsers/*' --fail-under=95
# Smoke-execute the example notebook end-to-end. This catches the
# "someone changed Mission/Results and forgot to refresh the committed
# notebook" regression. One matrix combo is enough — the underlying
# script path is covered cross-platform by test_round_trip.
- name: Smoke-execute example notebooks
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12' && matrix.gmat-version == 'R2026a'
run: |
uv sync --all-groups --extra examples
uv run jupyter execute docs/examples/01_load_run_plot.ipynb
uv run jupyter execute docs/examples/02_parameter_sweep.ipynb
uv run jupyter execute docs/examples/03_ground_track.ipynb
uv run jupyter execute docs/examples/04_export_oem.ipynb
uv run jupyter execute docs/examples/05_time_scales.ipynb
uv run jupyter execute docs/examples/06_solver_iterations.ipynb
lint:
name: lint
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: uv.lock
- run: uv sync --all-groups
- run: uv run ruff check
- run: uv run ruff format --check
typecheck:
name: typecheck
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- uses: astral-sh/setup-uv@v4
with:
enable-cache: true
cache-dependency-glob: uv.lock
- run: uv sync --all-groups
- run: uv run mypy
# Smoke-check that `pip install gmat-run` (no extras, no dev group) imports
# cleanly. Catches an extras-only dependency leaking into the default install
# path. The full test job above already exercises every extra via the dev
# group; this is a small canary, not a matrix concern.
minimal-install:
name: minimal install smoke
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install .
- run: python -c "import gmat_run"
# Drift canary for the canonical GMAT image published by setup-gmat. The
# main `test` job runs in action-mode (`setup-gmat@v0`) on bare runners; a
# downstream user running container-mode CI inside `ghcr.io/astro-tools/gmat`
# would never benefit from that signal if the image and the action drifted
# apart. This single cell exercises the load → run → DataFrame round-trip
# inside the image, so a future image rebuild that strips a plugin, mangles
# `gmat_startup_file.txt`, drops a Python ABI from the bundled gmatpy set,
# or silently retags `:R2026a` breaks here before downstream users hit it.
# Tag pinned to R2026a (the test job's primary GMAT version); a R2025a cell
# is a follow-up after the multi-version image axis lands.
canonical-image-smoke:
name: canonical image smoke
runs-on: ubuntu-latest
container: ghcr.io/astro-tools/gmat:R2026a
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- run: pip install .
- run: python tests/canonical_image_smoke.py
# Validate CITATION.cff against the Citation File Format v1.2.0 schema.
# cffconvert is installed standalone (not via uv sync) because it is a
# CI-only schema check, not part of the dev or runtime dependency graph.
citation:
name: citation file (cffconvert)
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install cffconvert==2.0.0
- run: cffconvert --validate -i CITATION.cff