Coverage for src / rhiza_tools / commands / generate_badge.py: 100%
44 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-23 01:10 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-02-23 01:10 +0000
1#!/usr/bin/env python3
2"""Generate a coverage badge endpoint JSON for shields.io.
4This script reads a coverage report JSON file and creates a shields.io endpoint
5JSON file for a coverage badge at a specified output path.
6"""
8import json
9import sys
10from pathlib import Path
12from rhiza_tools import console
15def get_badge_color(coverage: int) -> str:
16 """Determine badge color based on coverage percentage.
18 Colors follow a common convention where higher coverage gets "greener" colors.
20 Args:
21 coverage: Coverage percentage (0-100).
23 Returns:
24 Color name for shields.io badge.
26 Example:
27 >>> color = get_badge_color(95)
28 >>> print(color)
29 brightgreen
31 >>> color = get_badge_color(45)
32 >>> print(color)
33 red
34 """
35 if coverage >= 90:
36 return "brightgreen"
37 elif coverage >= 80:
38 return "green"
39 elif coverage >= 70:
40 return "yellowgreen"
41 elif coverage >= 60:
42 return "yellow"
43 elif coverage >= 50:
44 return "orange"
45 else:
46 return "red"
49def generate_coverage_badge_command(
50 coverage_json_path: Path,
51 output_path: Path,
52) -> None:
53 """Generate coverage badge JSON from coverage report.
55 Reads a pytest-cov generated coverage.json file and creates a shields.io
56 endpoint JSON file with appropriate color coding based on coverage percentage.
58 Args:
59 coverage_json_path: Path to the coverage.json file.
60 output_path: Path where the badge JSON should be written.
62 Raises:
63 SystemExit: If the coverage JSON is invalid or missing required data.
65 Example:
66 Generate badge from coverage report::
68 from pathlib import Path
69 generate_coverage_badge_command(
70 Path("_tests/coverage.json"),
71 Path("_book/tests/coverage-badge.json")
72 )
74 The generated JSON can be used with shields.io::
76 https://img.shields.io/endpoint?url=<url-to-badge-json>
77 """
78 # Check if coverage.json exists
79 if not coverage_json_path.exists():
80 console.warning(
81 f"Coverage JSON file not found at {coverage_json_path}, skipping badge generation",
82 )
83 return
85 console.info(f"Generating coverage badge from {coverage_json_path}...")
87 # Read and parse coverage data
88 try:
89 with coverage_json_path.open("r") as f:
90 data = json.load(f)
91 except json.JSONDecodeError as e:
92 console.error(f"Failed to parse coverage JSON: {e}")
93 sys.exit(1)
95 # Extract coverage percentage
96 try:
97 percent = data["totals"]["percent_covered"]
98 except KeyError as e:
99 console.error(f"Missing expected key in coverage JSON: {e}")
100 sys.exit(1)
102 # Round to nearest integer
103 coverage = round(percent)
105 if not 0 <= coverage <= 100:
106 console.error(f"Coverage percentage {coverage} is out of valid range 0-100")
107 sys.exit(1)
109 console.info(f"Coverage: {coverage}%")
111 # Determine badge color
112 color = get_badge_color(coverage)
114 # Create output directory if it doesn't exist
115 output_path.parent.mkdir(parents=True, exist_ok=True)
117 # Generate shields.io endpoint JSON
118 badge_data = {
119 "schemaVersion": 1,
120 "label": "coverage",
121 "message": f"{coverage}%",
122 "color": color,
123 }
125 with output_path.open("w") as f:
126 json.dump(badge_data, f, indent=2)
127 f.write("\n") # Add trailing newline
129 console.info(f"Coverage badge JSON generated at {output_path}")