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

1#!/usr/bin/env python3 

2"""Script to ensure GitHub Actions workflows have the (RHIZA) prefix. 

3 

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. 

7 

8Migrated from: https://github.com/Jebel-Quant/rhiza/.rhiza/scripts/check_workflow_names.py 

9""" 

10 

11from __future__ import annotations 

12 

13import sys 

14 

15import yaml 

16 

17 

18def check_file(filepath: str) -> bool: 

19 """Check if the workflow file has the correct name prefix and update if needed. 

20 

21 Args: 

22 filepath: Path to the workflow file. 

23 

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 

33 

34 if not isinstance(content, dict): 

35 # Empty file or not a dict 

36 return True 

37 

38 name = content.get("name") 

39 if not name: 

40 print(f"Error: {filepath} missing 'name' field.") 

41 return False 

42 

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 

49 

50 expected_name = f"{prefix}{clean_name.upper()}" 

51 

52 if name != expected_name: 

53 print(f"Updating {filepath}: name '{name}' -> '{expected_name}'") 

54 

55 # Read file lines to perform replacement while preserving comments 

56 with open(filepath) as f_read: 

57 lines = f_read.readlines() 

58 

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) 

72 

73 return False # Fail so pre-commit knows files were modified 

74 

75 return True 

76 

77 

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 

85 

86 if failed: 

87 sys.exit(1) 

88 return 0 

89 

90 

91if __name__ == "__main__": 

92 main()