-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcodeowners_validator.py
More file actions
70 lines (58 loc) · 2.62 KB
/
codeowners_validator.py
File metadata and controls
70 lines (58 loc) · 2.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#
# Max Base
# https://github.com/BaseMax/codeowners-validator
#
import os
import argparse
import logging
from concurrent.futures import ThreadPoolExecutor
def setup_logging(log_file):
"""Configure logging settings."""
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s - %(levelname)s - %(message)s",
)
def get_valid_lines(file_path):
"""Read file and return valid lines (non-empty, non-comment)."""
with open(file_path, "r", encoding="utf-8") as file:
return [line.strip() for line in file if line.strip() and not line.startswith("#")]
def extract_paths(lines):
"""Extract paths from lines by taking text before first '@' and normalizing them."""
return [line.split(" ")[0].lstrip("/") for line in lines]
def check_path_exists(path, base_dir, verbose=False):
"""Check if a given path exists and log the result."""
full_path = os.path.join(base_dir, path)
if os.path.exists(full_path):
if verbose:
logging.info(f"Checked {path}: Exists")
return None
else:
status = f"❌ Missing: {path}"
logging.info(status)
return status
def check_paths_exist(paths, base_dir, exclude_dirs=None, verbose=False):
"""Check all extracted paths in parallel and exclude specific directories."""
with ThreadPoolExecutor() as executor:
results = list(executor.map(lambda path: check_path_exists(path, base_dir, verbose), paths))
for result in results:
if result and (not exclude_dirs or not any(exclude in result for exclude in exclude_dirs)):
print(result)
def main():
"""Main function to execute the script."""
parser = argparse.ArgumentParser(description="Check if CODEOWNERS paths exist.")
parser.add_argument("-f", "--file", default=".github/CODEOWNERS", help="Path to CODEOWNERS file")
parser.add_argument("-d", "--dir", default=os.getcwd(), help="Project root directory")
parser.add_argument("-e", "--exclude", nargs="*", default=[], help="List of directories/files to exclude from the check (e.g., docs/ tests/)")
parser.add_argument("-v", "--verbose", action="store_true", help="Show detailed verbose output")
parser.add_argument("-l", "--log", default="codeowners_check.log", help="Custom log file")
args = parser.parse_args()
setup_logging(args.log)
if not os.path.exists(args.file):
print("CODEOWNERS file not found!")
return
lines = get_valid_lines(args.file)
paths = extract_paths(lines)
check_paths_exist(paths, args.dir, exclude_dirs=args.exclude, verbose=args.verbose)
if __name__ == "__main__":
main()