Coverage for src/pytribeam/cicd/report_badges.py: 49%

53 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2026-06-16 18:30 +0000

1#!/usr/bin/env python3 

2""" 

3Generates SVG badges for Lint and Coverage scores. 

4""" 

5 

6import argparse 

7import os 

8import re 

9import xml.etree.ElementTree as ET 

10 

11from pytribeam.cicd.utilities import ( 

12 get_score_color_coverage, 

13 get_score_color_lint, 

14) 

15 

16 

17def get_pylint_score(input_file: str) -> str: 

18 """Extract score from pylint report text.""" 

19 if not os.path.exists(input_file): 19 ↛ 20line 19 didn't jump to line 20 because the condition on line 19 was never true

20 return "0.00" 

21 with open(input_file, "r", encoding="utf-8") as f: 

22 content = f.read() 

23 match = re.search(r"Your code has been rated at (\d+\.\d+)/10", content) 

24 return match.group(1) if match else "0.00" 

25 

26 

27def get_coverage_score(input_file: str) -> str: 

28 """Extract percentage from coverage XML.""" 

29 if not os.path.exists(input_file): 29 ↛ 30line 29 didn't jump to line 30 because the condition on line 29 was never true

30 return "0.0" 

31 try: 

32 tree = ET.parse(input_file) 

33 root = tree.getroot() 

34 lines_valid = float(root.attrib.get("lines-valid", 0)) 

35 lines_covered = float(root.attrib.get("lines-covered", 0)) 

36 if lines_valid == 0: 36 ↛ 37line 36 didn't jump to line 37 because the condition on line 36 was never true

37 return "0.0" 

38 return f"{(lines_covered / lines_valid * 100):.1f}" 

39 except Exception: 

40 return "0.0" 

41 

42 

43def generate_badge_svg(label: str, value: str, color_key: str) -> str: 

44 """Generate a flat-style SVG badge.""" 

45 # Map color keys to hex 

46 color_map = { 

47 "brightgreen": "#4c1", 

48 "green": "#97ca00", 

49 "yellow": "#dfb317", 

50 "orange": "#fe7d37", 

51 "red": "#e05d44", 

52 "gray": "#9f9f9f", 

53 } 

54 color = color_map.get(color_key, color_map["gray"]) 

55 

56 # Simple width calculation 

57 label_w = len(label) * 7 + 10 

58 value_w = len(value) * 7 + 10 

59 total_w = label_w + value_w 

60 

61 return f"""<svg xmlns="http://www.w3.org/2000/svg" width="{total_w}" height="20" viewBox="0 0 {total_w} 20" preserveAspectRatio="xMidYMid meet"> 

62 <linearGradient id="b" x2="0" y2="100%"> 

63 <stop offset="0" stop-color="#bbb" stop-opacity=".1"/> 

64 <stop offset="1" stop-opacity=".1"/> 

65 </linearGradient> 

66 <mask id="a"> 

67 <rect width="{total_w}" height="20" rx="3" fill="#fff"/> 

68 </mask> 

69 <g mask="url(#a)"> 

70 <path fill="#555" d="M0 0h{label_w}v20H0z"/> 

71 <path fill="{color}" d="M{label_w} 0h{value_w}v20H{label_w}z"/> 

72 <path fill="url(#b)" d="M0 0h{total_w}v20H0z"/> 

73 </g> 

74 <g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" font-size="11"> 

75 <text x="{label_w / 2}" y="15" fill="#010101" fill-opacity=".3">{label}</text> 

76 <text x="{label_w / 2}" y="14">{label}</text> 

77 <text x="{label_w + value_w / 2}" y="15" fill="#010101" fill-opacity=".3">{value}</text> 

78 <text x="{label_w + value_w / 2}" y="14">{value}</text> 

79 </g> 

80 </svg>""" 

81 

82 

83def main(): 

84 parser = argparse.ArgumentParser( 

85 description="Generate SVG badges for CI/CD results." 

86 ) 

87 parser.add_argument("--lint_file", help="Path to pylint report text file") 

88 parser.add_argument("--coverage_file", help="Path to coverage XML file") 

89 parser.add_argument("--output_dir", required=True, help="Directory to save badges") 

90 

91 args = parser.parse_args() 

92 os.makedirs(args.output_dir, exist_ok=True) 

93 

94 if args.lint_file: 

95 score = get_pylint_score(args.lint_file) 

96 color = get_score_color_lint(score) 

97 svg = generate_badge_svg("lint", f"{score}/10", color) 

98 with open(os.path.join(args.output_dir, "lint.svg"), "w") as f: 

99 f.write(svg) 

100 print(f"[OK] Lint badge generated: {score}/10") 

101 

102 if args.coverage_file: 

103 score = get_coverage_score(args.coverage_file) 

104 color = get_score_color_coverage(score) 

105 svg = generate_badge_svg("coverage", f"{score}%", color) 

106 with open(os.path.join(args.output_dir, "coverage.svg"), "w") as f: 

107 f.write(svg) 

108 print(f"[OK] Coverage badge generated: {score}%") 

109 

110 

111if __name__ == "__main__": 

112 main()