Coverage for src / rhiza_hooks / check_workflow_names.py: 100%
45 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 08:53 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-08 08:53 +0000
1#!/usr/bin/env python3
2"""Script to ensure GitHub Actions workflows have the (RHIZA) prefix.
4This hook checks that all rhiza workflow files have their 'name' field
5properly formatted with the (RHIZA) prefix in uppercase. If not, it
6automatically updates the file.
8Migrated from: https://github.com/Jebel-Quant/rhiza/.rhiza/scripts/check_workflow_names.py
9"""
11from __future__ import annotations
13import sys
15import yaml
18def check_file(filepath: str) -> bool:
19 """Check if the workflow file has the correct name prefix and update if needed.
21 Args:
22 filepath: Path to the workflow file.
24 Returns:
25 bool: True if file is correct, False if it was updated or has errors.
26 """
27 with open(filepath) as f:
28 try:
29 content = yaml.safe_load(f)
30 except yaml.YAMLError as exc:
31 print(f"Error parsing YAML {filepath}: {exc}")
32 return False
34 if not isinstance(content, dict):
35 # Empty file or not a dict
36 return True
38 name = content.get("name")
39 if not name:
40 print(f"Error: {filepath} missing 'name' field.")
41 return False
43 prefix = "(RHIZA) "
44 # Remove prefix if present to verify the rest of the string
45 if name.startswith(prefix):
46 clean_name = name[len(prefix) :]
47 else:
48 clean_name = name
50 expected_name = f"{prefix}{clean_name.upper()}"
52 if name != expected_name:
53 print(f"Updating {filepath}: name '{name}' -> '{expected_name}'")
55 # Read file lines to perform replacement while preserving comments
56 with open(filepath) as f_read:
57 lines = f_read.readlines()
59 with open(filepath, "w") as f_write:
60 replaced = False
61 for line in lines:
62 # Replace only the top-level name field (assumes it starts at beginning of line)
63 if not replaced and line.startswith("name:"):
64 # Check if this line corresponds to the extracted name.
65 # Simple check: does it contain reasonable parts of the name?
66 # Or just blinding replace top-level name:
67 # We'll use quotes to be safe
68 f_write.write(f'name: "{expected_name}"\n')
69 replaced = True
70 else:
71 f_write.write(line)
73 return False # Fail so pre-commit knows files were modified
75 return True
78def main(argv: list[str] | None = None) -> int:
79 """Execute the script."""
80 files = argv if argv is not None else sys.argv[1:]
81 failed = False
82 for f in files:
83 if not check_file(f):
84 failed = True
86 if failed:
87 sys.exit(1)
88 return 0
91if __name__ == "__main__":
92 main()