The Test Suite job failed on every push since the black check was added because the tree had never been formatted, and pre-commit said 120 columns while CI ran black's default 88. pyproject.toml now carries [tool.black] / [tool.isort] (88, black profile) as the single source; pre-commit reads it; `make format` applied it (13 files, whitespace only, 146 insertions / 128 deletions, tests unchanged at 146 passed). ci.yml: lint (black, isort, flake8 hard errors) + pytest. The Docker registry push, VictoriaMetrics integration test, staging/production deploy and Apache-Bench jobs were template scaffolding for hosts and registries that do not exist; production is a systemd unit updated by git pull. Removed rather than left permanently skipped. docs.yml: the "Check markdown links" step curl'd every URL in every .md and failed on localhost examples and the Tailscale IP, and the Sphinx jobs built artifacts nobody read. Replaced by two checks that mean something: relative links/images in README, CONTRIBUTING and docs/ resolve inside the repo, and the FastAPI OpenAPI schema exports with the documented endpoints present (uploaded as an artifact).
100 lines
3.4 KiB
YAML
100 lines
3.4 KiB
YAML
name: Docs
|
|
|
|
# Checks that the documentation the project actually ships stays consistent:
|
|
# - every relative link / image path in docs/*.md and README.md resolves
|
|
# inside the repo (external URLs are NOT fetched: localhost examples,
|
|
# rate-limited hosts and the Tailscale-era links made that gate permanently
|
|
# red, and a 200 on a curl --head proves nothing about a doc anyway)
|
|
# - the FastAPI app imports and its OpenAPI schema is exportable (that is
|
|
# the reference at https://water.buildfor.life/docs)
|
|
# The previous Sphinx/apidoc jobs produced artifacts nobody read and were
|
|
# removed. Reference docs live in docs/*.md; the public overview is at
|
|
# https://buildfor.life/docs/tooling/ping-river-monitor/.
|
|
|
|
on:
|
|
push:
|
|
branches: [master, develop]
|
|
paths:
|
|
- "docs/**"
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
- "src/web_api.py"
|
|
- "src/schemas.py"
|
|
- ".gitea/workflows/docs.yml"
|
|
pull_request:
|
|
paths:
|
|
- "docs/**"
|
|
- "README.md"
|
|
- "CONTRIBUTING.md"
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
PYTHON_VERSION: "3.11"
|
|
|
|
jobs:
|
|
docs:
|
|
name: Validate documentation
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Relative links and images resolve
|
|
run: |
|
|
python3 - <<'PY'
|
|
import re, sys, pathlib
|
|
root = pathlib.Path(".")
|
|
files = [root / "README.md", root / "CONTRIBUTING.md", *root.glob("docs/**/*.md")]
|
|
link = re.compile(r"!?\[[^\]]*\]\(([^)\s]+)(?:\s+\"[^\"]*\")?\)")
|
|
bad = []
|
|
for md in files:
|
|
if not md.exists():
|
|
continue
|
|
for m in link.finditer(md.read_text(encoding="utf-8")):
|
|
target = m.group(1)
|
|
if target.startswith(("http://", "https://", "mailto:", "#")):
|
|
continue
|
|
path = target.split("#", 1)[0]
|
|
if not path:
|
|
continue
|
|
resolved = (md.parent / path).resolve()
|
|
if not resolved.exists():
|
|
bad.append(f"{md}: {target}")
|
|
if bad:
|
|
print("Broken relative links:")
|
|
print("\n".join(" " + b for b in bad))
|
|
sys.exit(1)
|
|
print(f"checked {len(files)} files, all relative links resolve")
|
|
PY
|
|
|
|
- uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
cache: pip
|
|
cache-dependency-path: requirements.txt
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip --root-user-action=ignore
|
|
pip install --root-user-action=ignore -r requirements.txt
|
|
|
|
- name: OpenAPI schema exports
|
|
env:
|
|
DB_TYPE: sqlite
|
|
run: |
|
|
python - <<'PY'
|
|
import json
|
|
from src.web_api import app
|
|
spec = app.openapi()
|
|
paths = sorted(spec["paths"])
|
|
required = {"/forecast", "/measurements/latest", "/measurements/history/{station_code}", "/stations", "/api/stats", "/health"}
|
|
missing = required - set(paths)
|
|
assert not missing, f"documented endpoints missing from the app: {missing}"
|
|
json.dump(spec, open("openapi.json", "w"), indent=1)
|
|
print(f"{len(paths)} paths; schema written to openapi.json")
|
|
PY
|
|
|
|
- uses: actions/upload-artifact@v3
|
|
with:
|
|
name: openapi-${{ github.run_number }}
|
|
path: openapi.json
|