Skip to content

docs: link subpackages to architecture map #383

docs: link subpackages to architecture map

docs: link subpackages to architecture map #383

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "0 3 * * *"
workflow_dispatch:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
# Least privilege by default; jobs that need more (nightly alert issue,
# coverage-badge push) declare their own elevated permissions.
permissions:
contents: read
jobs:
quality-fast:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
# mypy targets Python 3.10; NumPy 2.5+ stubs require Python 3.12.
pip install -e ".[dev,ml]" "numpy<2.5"
- name: Lint
run: ruff check .
- name: Typecheck
run: mypy src/freshdata
- name: Test (required fast lane)
run: pytest -m "not online and not large"
truthbench:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,ml]"
- name: TruthBench PR ratchet
# PRs must not regress any gate that passes in the committed
# baseline.json; the known-red gates are release blockers and are
# enforced absolutely by the release workflow (make truthbench-release),
# so they are reported here as KNOWN-RED without failing every
# unrelated PR. Infrastructure errors and partial runs still fail.
run: make truthbench-pr
- name: Upload run artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: truthbench-results
path: benchmarks/truthbench/results/
test-matrix:
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
include:
- python-version: "3.9"
pandas: "pandas>=1.5,<2"
numpy: "numpy<2"
- python-version: "3.13"
pandas: "pandas"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,ml]"
if [ -n "${{ matrix.pandas }}" ]; then pip install "${{ matrix.pandas }}"; fi
if [ -n "${{ matrix.numpy }}" ]; then pip install "${{ matrix.numpy }}"; fi
- name: Test (fast marker set)
run: pytest -m "not online and not large"
nightly-online-large:
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
timeout-minutes: 45
# NO continue-on-error here: when this lane runs, a failure is a real
# failure. Visibility is guaranteed by the alert step below (a pinned
# issue), so a red nightly can't scroll by unnoticed.
permissions:
issues: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,ml]"
- name: Nightly online/large drift checks
# --no-cov: this lane deliberately runs ~20 tests, so the repo-wide
# --cov-fail-under=93 inherited from addopts can never be met here.
# The coverage gate is enforced by the full fast lane (quality-fast).
run: pytest -m "online or large or tier1" --no-cov
- name: Open/refresh alert issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const title = "nightly large-data lane failing";
const body = `The scheduled online/large test lane failed.\n\n` +
`Run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}` +
`/actions/runs/${context.runId}\n\n` +
`This lane does not run on push/PR — a failure here is only ` +
`visible through this issue and the Actions tab.`;
const open = await github.rest.issues.listForRepo({
...context.repo, state: "open", labels: "nightly-failure",
});
const existing = open.data.find(i => i.title === title);
if (existing) {
await github.rest.issues.createComment({
...context.repo, issue_number: existing.number, body,
});
} else {
await github.rest.issues.create({
...context.repo, title, body, labels: ["nightly-failure"],
});
}
# Runs on every push/PR: makes the *existence and status* of the large-data
# lane visible where a green checkmark would otherwise hide it. Fails if the
# large/online markers stop collecting any tests (a silently-rotted lane).
large-data-status:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,ml]"
- name: Assert the large/online lane still collects tests
run: |
N=$(pytest -m "online or large or tier1" --collect-only -q -o addopts="" \
2>/dev/null | grep -c "::" || true)
echo "large/online/tier1 tests collected: $N"
if [ "$N" -eq 0 ]; then
echo "::error::the large/online test lane collects zero tests — it has rotted"
exit 1
fi
{
echo "## Large-data test lane"
echo ""
echo "**$N** large/online/tier1 test(s) exist. They do **not** run on this"
echo "push/PR — they run on the nightly schedule (see the *nightly-online-large*"
echo "job in scheduled runs; failures open a pinned \`nightly-failure\` issue)."
} >> "$GITHUB_STEP_SUMMARY"
build:
needs: quality-fast
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Build distributions
run: |
python -m pip install build twine
python -m build
twine check dist/*
coverage-badge:
# Publish a self-hosted shields endpoint badge to the `badges` branch
# (no third-party account needed). Runs only on main.
if: github.ref == 'refs/heads/main'
needs: quality-fast
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip
- name: Install
run: |
python -m pip install --upgrade pip
pip install -e ".[dev,ml]"
- name: Compute coverage and write badge JSON
run: |
pytest -m "not online and not large and not tier1" \
--cov=freshdata --cov-report=json -o addopts=""
python - <<'PY'
import json
pct = round(json.load(open("coverage.json"))["totals"]["percent_covered"])
color = ("brightgreen" if pct >= 90 else "green" if pct >= 80
else "yellow" if pct >= 70 else "orange" if pct >= 60 else "red")
json.dump(
{"schemaVersion": 1, "label": "coverage", "message": f"{pct}%", "color": color},
open("coverage.json", "w"),
)
print("coverage badge:", pct, "%", color)
PY
- name: Push badge to `badges` branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
mkdir -p /tmp/badges && cp coverage.json /tmp/badges/coverage.json
cd /tmp/badges
git init -q
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git checkout -q -b badges
git add coverage.json
git commit -q -m "Update coverage badge"
git push -q --force \
"https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" badges