Coverage for src/pytribeam/cicd/badge_lint.py: 83%

53 statements  

« prev     ^ index     » next       coverage.py v7.5.1, created at 2026-07-23 00:29 +0000

1""" 

2Generates the Lint badge (SVG) and metadata (JSON) for CI/CD. 

3""" 

4 

5import argparse 

6import os 

7import re 

8import sys 

9from datetime import datetime, timezone 

10from pathlib import Path 

11 

12from pytribeam.cicd.utilities import ( 

13 add_badge_args, 

14 badge_image_download, 

15 badge_metadata_json_write, 

16 get_score_color_lint, 

17) 

18 

19 

20def extract_score(input_file: str) -> float: 

21 """Extracts the lint score from the output text file.""" 

22 pattern = re.compile(r"Your code has been rated at (\d+\.\d+)/10") 

23 try: 

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

25 content = f.read() 

26 match = pattern.search(content) 

27 if match: 

28 return float(match.group(1)) 

29 except (FileNotFoundError, IOError, ValueError) as e: 

30 print(f"[!] Error reading lint output: {e}") 

31 return 0.0 

32 

33 

34def export_to_github_env(color: str): 

35 """Exports the badge color to GITHUB_ENV if available.""" 

36 env_path = os.environ.get("GITHUB_ENV") 

37 if env_path: 37 ↛ exitline 37 didn't return from function 'export_to_github_env', because the condition on line 37 was always true

38 with open(env_path, "a", encoding="utf-8") as f: 

39 f.write(f"BADGE_COLOR={color}\n") 

40 print(f" [C] Exported BADGE_COLOR={color} to GITHUB_ENV") 

41 

42 

43def main(): 

44 """Main method for creating the badge.""" 

45 parser = argparse.ArgumentParser(description="Generate Lint badge and metadata.") 

46 parser.add_argument("--input_file", help="Lint text output file (to extract score)") 

47 parser.add_argument("--score", type=float, help="Lint score (direct input)") 

48 parser.add_argument( 

49 "--export_env", action="store_true", help="Export color to GITHUB_ENV" 

50 ) 

51 

52 # Add common badge arguments from utilities 

53 add_badge_args(parser) 

54 

55 args = parser.parse_args() 

56 

57 # Determine the score 

58 if args.score is not None: 58 ↛ 59line 58 didn't jump to line 59, because the condition on line 58 was never true

59 score = args.score 

60 elif args.input_file: 60 ↛ 63line 60 didn't jump to line 63, because the condition on line 60 was always true

61 score = extract_score(args.input_file) 

62 else: 

63 print("[X] Error: Must provide either --input_file or --score") 

64 sys.exit(1) 

65 

66 color = get_score_color_lint(str(score)) 

67 

68 # Optional export to GITHUB_ENV 

69 if args.export_env: 69 ↛ 73line 69 didn't jump to line 73, because the condition on line 69 was always true

70 export_to_github_env(color) 

71 

72 # If output_dir is provided, generate SVG and JSON 

73 if args.output_dir: 73 ↛ 101line 73 didn't jump to line 101, because the condition on line 73 was always true

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

75 

76 # Download SVG badge 

77 badge_url = f"https://img.shields.io/badge/lint-{score}-{color}.svg" 

78 output_svg = str(Path(args.output_dir) / "lint.svg") 

79 if badge_image_download(url=badge_url, output_path=output_svg): 79 ↛ 83line 79 didn't jump to line 83, because the condition on line 79 was always true

80 print(f"[OK] Lint SVG badge saved to {args.output_dir}") 

81 

82 # Generate JSON metadata if other required args are present 

83 if all([args.github_repo, args.deploy_subdir, args.run_id]): 83 ↛ 101line 83 didn't jump to line 101, because the condition on line 83 was always true

84 owner, repo = args.github_repo.split("/") 

85 metadata = { 

86 "score": str(score), 

87 "color": color, 

88 "pages_url": f"https://{owner}.github.io/{repo}/{args.deploy_subdir}/reports/lint/", 

89 "workflow_url": ( 

90 f"{args.github_server_url}/{args.github_repo}/" 

91 "actions/workflows/ci.yml" 

92 ), 

93 "run_id": args.run_id, 

94 "timestamp": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), 

95 } 

96 

97 output_json = str(Path(args.output_dir) / "lint-info.json") 

98 badge_metadata_json_write(metadata=metadata, output_path=output_json) 

99 print(f"[OK] Lint JSON metadata saved to {args.output_dir}") 

100 

101 print(f"Lint badge processing complete: Score={score}, Color={color}") 

102 

103 

104if __name__ == "__main__": 

105 main()