name: Siderust CI
on:
push:
branches: [main, master]
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
checks: write
pull-requests: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
SIDERUST_JPL_STUB: all
CARGO_CI_TARGETS: "--lib --bins --tests --examples"
jobs:
check:
name: Check (all features)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- run: cargo check --workspace $CARGO_CI_TARGETS --all-features
check-no-default-features:
name: Check (no_std + alloc)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
targets: thumbv7em-none-eabihf
- run: cargo check -p siderust --lib --no-default-features
- run: cargo check -p siderust --lib --no-default-features --features serde
- run: cargo check -p siderust --lib --target thumbv7em-none-eabihf --no-default-features
- run: cargo check -p siderust --lib --target thumbv7em-none-eabihf --no-default-features --features serde
- run: cargo check -p siderust --lib --no-default-features --features atmosphere
- run: cargo check -p siderust --lib --no-default-features --features atmosphere,serde
- run: cargo check -p siderust --lib --target thumbv7em-none-eabihf --no-default-features --features atmosphere
- run: cargo check -p siderust --lib --target thumbv7em-none-eabihf --no-default-features --features atmosphere,serde
- run: cargo test -p siderust --test observatory_catalog_no_default --no-default-features --features std
release-preflight:
name: Release preflight
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test -p siderust-release
- run: cargo build -p siderust-release
- run: target/debug/siderust-release validate
fmt:
name: Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all -- --check
clippy:
name: Clippy (all features)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- run: cargo clippy --workspace $CARGO_CI_TARGETS --all-features -- -D warnings
test:
name: Test (all features)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --workspace $CARGO_CI_TARGETS --all-features
- run: cargo test --doc --workspace --all-features
test-pod:
name: Test (pod)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --features pod
test-spice:
name: Test (spice)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --features spice
test-runtime-data:
name: Test (runtime-data)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --features runtime-data
test-pod-parquet:
name: Test (pod-parquet)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --features pod-parquet
test-pod-doris:
name: Test (pod-doris)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --features pod-doris
coverage:
name: Test & Coverage
if: ${{ github.event_name == 'push' || github.event.pull_request.draft == false }}
runs-on: ubuntu-latest
env:
SIDERUST_JPL_STUB: all
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Rust (nightly + llvm-tools)
uses: dtolnay/rust-toolchain@v1
with:
toolchain: nightly
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@v2
with:
tool: cargo-llvm-cov
- name: Clean previous coverage data
run: |
cargo +nightly llvm-cov clean --workspace
rm -rf target/llvm-cov-target/*.profraw
- name: Coverage (run, no report)
run: cargo +nightly llvm-cov --workspace --all-features --doctests --no-report
- name: Coverage (Cobertura XML)
run: cargo +nightly llvm-cov report --cobertura --output-path coverage.xml
- name: Coverage (HTML)
run: cargo +nightly llvm-cov report --html --output-dir coverage_html
- name: Build coverage summary (Markdown)
uses: irongut/CodeCoverageSummary@v1.3.0
with:
filename: coverage.xml
badge: true
format: markdown
output: file
- name: Publish to Job Summary
run: cat code-coverage-results.md >> "$GITHUB_STEP_SUMMARY"
- name: Post coverage as PR comment
if: github.event_name == 'pull_request'
uses: mshick/add-pr-comment@v2
with:
message-path: code-coverage-results.md
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Coverage gate (≥90% lines)
run: cargo +nightly llvm-cov --workspace --all-features --doctests --no-run --fail-under-lines 90
- name: Strict phase table coverage (≥95% lines)
run: |
cargo +nightly llvm-cov report --json --output-path phase-coverage.json
python3 - <<'PYCODE'
import json
with open("phase-coverage.json") as report:
files = json.load(report)["data"][0]["files"]
phase = next(f for f in files if f["filename"].endswith("/src/atmosphere/normalized_phase.rs"))
lines = phase["summary"]["lines"]
print(f"Strict phase table line coverage: {lines['percent']:.2f}%")
assert lines["percent"] >= 95, lines
PYCODE
- name: Upload coverage HTML
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-html
path: coverage_html
retention-days: 7
- name: Starlight production coverage (≥90% lines)
run: |
python3 - <<'PYCODE'
import json
with open("phase-coverage.json") as report:
files = json.load(report)["data"][0]["files"]
production = [
entry for entry in files
if "/src/starlight/" in entry["filename"].replace("\\", "/")
and "/src/starlight/tests/" not in entry["filename"].replace("\\", "/")
and not entry["filename"].replace("\\", "/").endswith("/src/starlight/tests.rs")
]
assert production, "No starlight production files found in coverage report"
covered = sum(entry["summary"]["lines"]["covered"] for entry in production)
total = sum(entry["summary"]["lines"]["count"] for entry in production)
assert total, "No instrumented starlight production lines found"
percent = 100 * covered / total
print(f"Starlight production line coverage: {covered}/{total} ({percent:.2f}%)")
assert percent >= 90, f"starlight line coverage {percent:.2f}% is below 90%"
PYCODE