mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
Currently, we send all files as a list but it can be problematic with files that can't be evaluated properly. Instead of crashing the entire extraction process, we will send a file at a time for eval so we can just bypass files causing issues. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
113 lines
3.5 KiB
Python
Executable file
113 lines
3.5 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""
|
|
Extract maintainers from changed Home Manager module files.
|
|
|
|
This script extracts the maintainer extraction logic from the tag-maintainers workflow
|
|
for easier testing and validation.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
class NixEvalError(Exception):
|
|
"""Custom exception for errors during Nix evaluation."""
|
|
pass
|
|
|
|
|
|
def run_nix_eval(nix_file: Path, *args: str) -> str:
|
|
"""Run a Nix evaluation expression and return the result as a string."""
|
|
command = [
|
|
"nix-instantiate",
|
|
"--eval",
|
|
"--strict",
|
|
"--json",
|
|
str(nix_file),
|
|
*args,
|
|
]
|
|
logging.debug(f"Running command: {' '.join(command)}")
|
|
try:
|
|
result = subprocess.run(
|
|
command,
|
|
capture_output=True,
|
|
text=True,
|
|
check=True,
|
|
)
|
|
return result.stdout.strip()
|
|
except FileNotFoundError:
|
|
logging.error("'nix-instantiate' command not found. Is Nix installed and in your PATH?")
|
|
raise NixEvalError("'nix-instantiate' not found")
|
|
except subprocess.CalledProcessError as e:
|
|
logging.error(f"Nix evaluation failed with exit code {e.returncode}")
|
|
logging.error(f"Stderr: {e.stderr.strip()}")
|
|
raise NixEvalError("Nix evaluation failed") from e
|
|
|
|
|
|
def extract_maintainers(changed_files: list[str], pr_author: str) -> list[str]:
|
|
"""Extract and filter maintainers from a list of changed module files."""
|
|
if not changed_files:
|
|
logging.info("No module files changed; no maintainers to tag.")
|
|
return []
|
|
|
|
logging.info("Finding maintainers for changed files...")
|
|
nix_file = Path(__file__).parent.parent / "nix" / "extract-maintainers.nix"
|
|
|
|
all_maintainers = set()
|
|
|
|
for file in changed_files:
|
|
try:
|
|
result_json = run_nix_eval(nix_file, "--argstr", "file", file)
|
|
file_maintainers = json.loads(result_json)
|
|
all_maintainers.update(file_maintainers)
|
|
if file_maintainers:
|
|
logging.debug(f"Found maintainers for {file}: {file_maintainers}")
|
|
except NixEvalError:
|
|
# Error is already logged by run_nix_eval, just skip this file
|
|
logging.debug(f"Skipping {file} due to evaluation error")
|
|
continue
|
|
except json.JSONDecodeError as e:
|
|
logging.error(f"Error parsing JSON output from Nix for {file}: {e}")
|
|
continue
|
|
|
|
filtered_maintainers = sorted(list(all_maintainers - {pr_author}))
|
|
|
|
if not filtered_maintainers:
|
|
logging.info("No maintainers found (or only the PR author is a maintainer).")
|
|
return []
|
|
|
|
logging.info(f"Found maintainers to notify: {' '.join(filtered_maintainers)}")
|
|
return filtered_maintainers
|
|
|
|
|
|
def main() -> None:
|
|
"""Parse arguments and run the maintainer extraction."""
|
|
logging.basicConfig(level=logging.INFO, format="%(message)s", stream=sys.stderr)
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Extract maintainers from changed Home Manager module files."
|
|
)
|
|
parser.add_argument(
|
|
"--changed-files",
|
|
help="Newline-separated list of changed files",
|
|
default="",
|
|
)
|
|
parser.add_argument(
|
|
"--pr-author",
|
|
required=True,
|
|
help="GitHub username of the PR author",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
changed_files = [f.strip() for f in args.changed_files.splitlines() if f.strip()]
|
|
|
|
maintainers = extract_maintainers(changed_files, args.pr_author)
|
|
|
|
print(" ".join(maintainers))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|