diff --git a/nixpkgs_review/cli/__init__.py b/nixpkgs_review/cli/__init__.py index 2531267e..3cc92d3c 100644 --- a/nixpkgs_review/cli/__init__.py +++ b/nixpkgs_review/cli/__init__.py @@ -165,6 +165,11 @@ def common_flags() -> list[CommonFlag]: action="store_true", help="Only evaluate and build without executing nix-shell", ), + CommonFlag( + "--approve-pr", + action="store_true", + help="Approve PR on review success", + ), CommonFlag( "-p", "--package", diff --git a/nixpkgs_review/cli/pr.py b/nixpkgs_review/cli/pr.py index 42e90416..15d9eaa3 100644 --- a/nixpkgs_review/cli/pr.py +++ b/nixpkgs_review/cli/pr.py @@ -63,7 +63,7 @@ def pr_command(args: argparse.Namespace) -> str: CheckoutOption.MERGE if args.checkout == "merge" else CheckoutOption.COMMIT ) - if args.post_result: + if args.post_result or args.approve_pr: ensure_github_token(args.token) if args.system: warn("Warning: The `--system` is deprecated. Use `--systems` instead.") @@ -119,7 +119,9 @@ def pr_command(args: argparse.Namespace) -> str: assert review is not None all_succeeded = all( - review.start_review(attrs, path, pr, args.post_result, args.print_result) + review.start_review( + attrs, path, pr, args.post_result, args.print_result, args.approve_pr + ) for pr, path, attrs in contexts ) diff --git a/nixpkgs_review/github.py b/nixpkgs_review/github.py index 1f2305d7..f2e6aaf5 100644 --- a/nixpkgs_review/github.py +++ b/nixpkgs_review/github.py @@ -9,7 +9,7 @@ from pathlib import Path from typing import IO, Any, override -from .utils import System +from .utils import System, warn def pr_url(pr: int) -> str: @@ -80,13 +80,24 @@ def comment_issue(self, pr: int, msg: str) -> Any: f"/repos/NixOS/nixpkgs/issues/{pr}/comments", data={"body": msg} ) - def approve_pr(self, pr: int) -> Any: - "Approve a PR" + def approve_pr(self, pr: int, comment: str = "") -> Any: + "Approve a PR with an optional comment" print(f"Approving {pr_url(pr)}") - return self.post( - f"/repos/NixOS/nixpkgs/pulls/{pr}/reviews", - data={"event": "APPROVE"}, - ) + data = {"event": "APPROVE"} + if comment: + data["body"] = comment + try: + return self.post( + f"/repos/NixOS/nixpkgs/pulls/{pr}/reviews", + data=data, + ) + except urllib.error.HTTPError as e: + if e.code == 422: + warn( + "Sorry, unable to process request. You may have tried to approve your own PR, which is unsupported by GitHub" + ) + else: + raise def merge_pr(self, pr: int) -> Any: "Merge a PR. Requires maintainer access to NixPkgs" diff --git a/nixpkgs_review/review.py b/nixpkgs_review/review.py index 7fa4c636..b3b9aa14 100644 --- a/nixpkgs_review/review.py +++ b/nixpkgs_review/review.py @@ -391,6 +391,7 @@ def start_review( pr: int | None = None, post_result: bool | None = False, print_result: bool = False, + approve_pr: bool = False, ) -> bool: os.environ.pop("NIXPKGS_CONFIG", None) os.environ["NIXPKGS_REVIEW_ROOT"] = str(path) @@ -409,9 +410,17 @@ def start_review( report.print_console(pr) report.write(path, pr) + success = report.succeeded() + if pr and post_result: self.github_client.comment_issue(pr, report.markdown(pr)) + if pr and approve_pr and success: + self.github_client.approve_pr( + pr, + "Approved automatically following the successful run of `nixpkgs-review`.", + ) + if print_result: print(report.markdown(pr)) @@ -428,7 +437,7 @@ def start_review( self.sandbox, ) - return report.succeeded() + return success def review_commit( self, @@ -437,12 +446,14 @@ def review_commit( reviewed_commit: str | None, staged: bool = False, print_result: bool = False, + approve_pr: bool = False, ) -> None: branch_rev = fetch_refs(self.remote, branch)[0] self.start_review( self.build_commit(branch_rev, reviewed_commit, staged), path, print_result=print_result, + approve_pr=approve_pr, )