fix coverage badge: use .woodpecker/ci.yml and stdlib urllib (no curl)

This commit is contained in:
kert
2026-03-13 10:24:01 -04:00
parent fd89a03d5e
commit e949a945d0
2 changed files with 53 additions and 9 deletions

View File

@@ -23,11 +23,17 @@ steps:
environment: environment:
UV_PYTHON_PREFERENCE: only-system UV_PYTHON_PREFERENCE: only-system
UV_LINK_MODE: copy UV_LINK_MODE: copy
GITEA_TOKEN:
from_secret: gitea_token
GITEA_URL:
from_secret: gitea_url
commands: commands:
- uv python pin 3.13.11 - uv python pin 3.13.11
- uv sync --dev - uv sync --dev
- uv pip install -e . - uv pip install -e .
- uv run pytest tests/ --no-cov --tb=short -q - uv run pytest tests/ --cov=src --cov-report=term-missing --cov-fail-under=99 -q 2>&1 | tee pytest.out
- uv run python dev/scripts/coverage_badge.py < pytest.out > coverage.svg
- uv run python dev/scripts/coverage_badge.py --post pytest.out
- name: validate-compose - name: validate-compose
image: docker:cli image: docker:cli

View File

@@ -1,16 +1,21 @@
"""Generate a coverage badge SVG from pytest-cov output. """Generate a coverage badge SVG and optionally post status to Gitea.
Usage: Usage:
uv run python -m pytest --cov=src ... | uv run python dev/scripts/coverage_badge.py # Generate badge SVG to stdout from piped pytest-cov output:
uv run pytest --cov=src ... | uv run python dev/scripts/coverage_badge.py
Reads stdin for a pytest-cov summary line like "TOTAL 1234 56 95%", # Post coverage as a Gitea commit status (reads GITEA_TOKEN, GITEA_URL,
extracts the percentage, writes a badge SVG to stdout. # CI_COMMIT_SHA from environment):
uv run python dev/scripts/coverage_badge.py --post pytest.out
""" """
from __future__ import annotations from __future__ import annotations
import json
import os
import re import re
import sys import sys
import urllib.request
TEMPLATE = """\ TEMPLATE = """\
<svg xmlns="http://www.w3.org/2000/svg" width="116" height="20"> <svg xmlns="http://www.w3.org/2000/svg" width="116" height="20">
@@ -45,14 +50,47 @@ def color_for(pct: int) -> str:
return "#e05d44" return "#e05d44"
def main() -> None: def extract_pct(text: str) -> int:
text = sys.stdin.read()
m = re.search(r"^TOTAL\s+\d+\s+\d+\s+(\d+)%", text, re.MULTILINE) m = re.search(r"^TOTAL\s+\d+\s+\d+\s+(\d+)%", text, re.MULTILINE)
if not m: if not m:
print("ERROR: could not find coverage percentage in input", file=sys.stderr) print("ERROR: could not find coverage percentage in input", file=sys.stderr)
sys.exit(1) sys.exit(1)
pct = int(m.group(1)) return int(m.group(1))
print(TEMPLATE.format(pct=pct, color=color_for(pct)))
def post_status(pct: int) -> None:
token = os.environ["GITEA_TOKEN"]
url = os.environ["GITEA_URL"]
sha = os.environ["CI_COMMIT_SHA"]
endpoint = f"{url}/api/v1/repos/homelab/stack/statuses/{sha}"
body = json.dumps({
"state": "success",
"description": f"{pct}% coverage",
"context": "coverage",
}).encode()
req = urllib.request.Request(
endpoint,
data=body,
headers={
"Authorization": f"token {token}",
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(f"Posted coverage status: {pct}% (HTTP {resp.status})")
def main() -> None:
if "--post" in sys.argv:
path = sys.argv[sys.argv.index("--post") + 1]
text = open(path).read()
pct = extract_pct(text)
post_status(pct)
else:
text = sys.stdin.read()
pct = extract_pct(text)
print(TEMPLATE.format(pct=pct, color=color_for(pct)))
if __name__ == "__main__": if __name__ == "__main__":