From 5e625a767ec31a530ac6a1e7266f6777f8d10365 Mon Sep 17 00:00:00 2001 From: timlichtenberg Date: Mon, 1 Jun 2026 13:21:10 +0200 Subject: [PATCH 1/2] Publish test-count badges through the documentation site The badge-refresh workflow pushed regenerated counts to main, which the branch ruleset blocks for the Actions token, so the published numbers went stale. Generate the three test-count JSON files during the documentation deploy and serve them from the published site, so refreshing the badges needs no push to a protected branch. The shields.io endpoint URLs point at the site, the standalone publish workflow is removed, and the stale on-main copies are dropped. --- .github/badges/tests-integration.json | 6 -- .github/badges/tests-total.json | 6 -- .github/badges/tests-unit.json | 6 -- .github/workflows/docs.yaml | 4 ++ .github/workflows/publish-test-badges.yml | 74 ----------------------- docs/Explanations/testing.md | 10 +-- docs/How-to/build_tests.md | 2 +- 7 files changed, 10 insertions(+), 98 deletions(-) delete mode 100644 .github/badges/tests-integration.json delete mode 100644 .github/badges/tests-total.json delete mode 100644 .github/badges/tests-unit.json delete mode 100644 .github/workflows/publish-test-badges.yml diff --git a/.github/badges/tests-integration.json b/.github/badges/tests-integration.json deleted file mode 100644 index 3c4dd4a..0000000 --- a/.github/badges/tests-integration.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "schemaVersion": 1, - "label": "integration tests", - "message": "30", - "color": "blue" -} diff --git a/.github/badges/tests-total.json b/.github/badges/tests-total.json deleted file mode 100644 index 44a7425..0000000 --- a/.github/badges/tests-total.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "schemaVersion": 1, - "label": "tests", - "message": "126", - "color": "blue" -} diff --git a/.github/badges/tests-unit.json b/.github/badges/tests-unit.json deleted file mode 100644 index 33a9b0a..0000000 --- a/.github/badges/tests-unit.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "schemaVersion": 1, - "label": "unit tests", - "message": "96", - "color": "blue" -} diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index a2ecd9f..4e1a4ac 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -22,6 +22,10 @@ jobs: python-version: 3.x - run: pip install zensical markdown-include pymdown-extensions mkdocstrings mkdocstrings-python - run: zensical build --clean + - name: Add test-count badges to the site + run: | + pip install ".[develop]" + python tools/generate_test_badges.py --out site/badges/ - uses: actions/upload-pages-artifact@v4 with: path: site diff --git a/.github/workflows/publish-test-badges.yml b/.github/workflows/publish-test-badges.yml deleted file mode 100644 index 678cec9..0000000 --- a/.github/workflows/publish-test-badges.yml +++ /dev/null @@ -1,74 +0,0 @@ -name: Refresh test count badges - -on: - push: - branches: - - main - paths: - - 'tests/**' - - 'src/calliope/**' - - 'pyproject.toml' - - 'tools/generate_test_badges.py' - - '.github/workflows/publish-test-badges.yml' - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: badges-${{ github.ref }} - cancel-in-progress: false - -jobs: - refresh-badges: - name: Regenerate tests-*.json - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v6 - with: - fetch-depth: 0 - - - name: Set up Python 3.12 - uses: actions/setup-python@v6 - with: - python-version: '3.12' - - - name: Install CALLIOPE and pytest - run: | - python -m pip install --upgrade pip - pip install ".[develop]" - - - name: Regenerate badge JSON files - run: | - python tools/generate_test_badges.py --out .github/badges/ - - - name: Commit and push if changed - # Concurrency group ``badges-${{ github.ref }}`` does not - # cancel-in-progress, so two pushes to main within seconds can - # both run this step. The second run rebases its own bot commit - # onto the up-to-date HEAD before pushing to avoid a - # non-fast-forward rejection that would silently lose the badge - # update under ``[skip ci]``. - run: | - set -e - git config user.name 'actions' - git config user.email 'actions@github.com' - git add .github/badges/ - if git diff --cached --quiet; then - echo 'No badge changes to commit.' - exit 0 - fi - git commit -m 'ci: refresh test count badges [skip ci]' - for attempt in 1 2 3; do - git pull --rebase origin "${GITHUB_REF_NAME:-main}" - if git push origin "HEAD:${GITHUB_REF_NAME:-main}"; then - echo "Pushed badge refresh on attempt ${attempt}." - exit 0 - fi - echo "Push rejected on attempt ${attempt}; retrying after rebase." - sleep 2 - done - echo 'Failed to push badge refresh after 3 attempts.' >&2 - exit 1 diff --git a/docs/Explanations/testing.md b/docs/Explanations/testing.md index ad9533c..db5ca92 100644 --- a/docs/Explanations/testing.md +++ b/docs/Explanations/testing.md @@ -3,7 +3,7 @@ [![codecov](https://img.shields.io/codecov/c/github/FormingWorlds/CALLIOPE?label=coverage&logo=codecov&color=brightgreen)](https://app.codecov.io/gh/FormingWorlds/CALLIOPE) [![Unit Tests](https://img.shields.io/github/actions/workflow/status/FormingWorlds/CALLIOPE/tests.yaml?branch=main&label=Unit%20Tests&color=brightgreen)](https://github.com/FormingWorlds/CALLIOPE/actions/workflows/tests.yaml) [![Integration Tests](https://img.shields.io/github/actions/workflow/status/FormingWorlds/CALLIOPE/nightly.yml?branch=main&label=Integration%20Tests&color=brightgreen)](https://github.com/FormingWorlds/CALLIOPE/actions/workflows/nightly.yml) -[![tests](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/FormingWorlds/CALLIOPE/main/.github/badges/tests-total.json)](https://proteus-framework.org/testing) +[![tests](https://img.shields.io/endpoint?url=https://proteus-framework.org/CALLIOPE/badges/tests-total.json)](https://proteus-framework.org/testing) Tests verify that the code does what was written; physical correctness is judged by data, not by tests. The suite catches regressions in equilibrium chemistry, solubility laws, oxygen-fugacity buffers, and the hybrid solver, but it cannot certify that those formulae match nature. @@ -180,13 +180,13 @@ python tools/check_test_quality.py --physics-invariant-status ## Public-facing badges versus internal taxonomy Public-facing badges (README, project website) collapse `smoke + integration + slow` into a single `Integration Tests` category, because a four-way taxonomy is confusing to non-developer readers. -The four-marker internal scheme remains for CI infrastructure granularity: the PR gate runs `(unit or smoke)`, the nightly runs everything, and the test-count badge fetches the JSON files written by the publish-test-badges workflow. +The four-marker internal scheme remains for CI infrastructure granularity: the PR gate runs `(unit or smoke)`, the nightly runs everything, and the test-count badge fetches the JSON files written into the documentation site during the docs deploy. ## Badge system -Three JSON files at `.github/badges/tests-{total,unit,integration}.json` are rewritten by `.github/workflows/publish-test-badges.yml` on every push to `main` (paths-filtered to source, tests, tools, and `pyproject.toml`). -Shields.io fetches them live via the endpoint URL embedded in the test-count badge. -The publish workflow auto-commits the badges with `[skip ci]` and retries the push up to three times to absorb concurrent main-branch updates. +The documentation deploy (`.github/workflows/docs.yaml`) regenerates three JSON files, `tests-{total,unit,integration}.json`, from `pytest --collect-only` and writes them into the published site under `badges/`. +Shields.io fetches them live from the site via the endpoint URL embedded in the test-count badge. +The counts refresh on every documentation build, so they track the suite without running it. ## Coverage gates diff --git a/docs/How-to/build_tests.md b/docs/How-to/build_tests.md index b98d054..19b6c44 100644 --- a/docs/How-to/build_tests.md +++ b/docs/How-to/build_tests.md @@ -3,7 +3,7 @@ [![codecov](https://img.shields.io/codecov/c/github/FormingWorlds/CALLIOPE?label=coverage&logo=codecov)](https://app.codecov.io/gh/FormingWorlds/CALLIOPE) [![Unit Tests](https://img.shields.io/github/actions/workflow/status/FormingWorlds/CALLIOPE/tests.yaml?branch=main&label=Unit%20Tests)](https://github.com/FormingWorlds/CALLIOPE/actions/workflows/tests.yaml) [![Integration Tests](https://img.shields.io/github/actions/workflow/status/FormingWorlds/CALLIOPE/nightly.yml?branch=main&label=Integration%20Tests)](https://github.com/FormingWorlds/CALLIOPE/actions/workflows/nightly.yml) -[![tests](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/FormingWorlds/CALLIOPE/main/.github/badges/tests-total.json)](https://proteus-framework.org/testing) +[![tests](https://img.shields.io/endpoint?url=https://proteus-framework.org/CALLIOPE/badges/tests-total.json)](https://proteus-framework.org/testing) This page is the practical contributor guide for adding or modifying a test in CALLIOPE. The conceptual framing (marker scheme, badge system, coverage gates, AST linter) lives in the [testing suite](../Explanations/testing.md) explainer; read it first if you have not yet. From 3949a11d19da2963a434d747deb0f8af22f77fe6 Mon Sep 17 00:00:00 2001 From: timlichtenberg Date: Mon, 1 Jun 2026 13:33:01 +0200 Subject: [PATCH 2/2] Fetch full history in the docs build so setuptools-scm sees the tags The docs deploy now installs the package to count tests for the badges, and setuptools-scm reads the version from git tags. A shallow checkout has none, so it falls back to a 0.0.post dev version; fetch the full history so the build resolves the real version. --- .github/workflows/docs.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 4e1a4ac..6ee586b 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -17,6 +17,10 @@ jobs: steps: - uses: actions/configure-pages@v5 - uses: actions/checkout@v6 + with: + # setuptools-scm derives the version from git tags; the badge step + # installs the package, so the full tag history must be present. + fetch-depth: 0 - uses: actions/setup-python@v6 with: python-version: 3.x