hooks: pass yes flag when available Pass the -y flag as a keyword argument "yes" to the hook main function. This allows upload hooks (such as auto-fixers) to automatically apply fixes when the -y flag is passed, rather than prompting the user. Bug: 498893733 Change-Id: I12096029aa3af471ba9175314d749deb0ebd1007 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/605261 Commit-Queue: Rahul Yadav <yadavrah@google.com> Reviewed-by: Mike Frysinger <vapier@google.com> Tested-by: Rahul Yadav <yadavrah@google.com>
diff --git a/docs/repo-hooks.md b/docs/repo-hooks.md index 696ad5a..c3adee8 100644 --- a/docs/repo-hooks.md +++ b/docs/repo-hooks.md
@@ -83,6 +83,13 @@ the user. Although user interaction is discouraged in the common case, it can be useful when deploying automatic fixes. +### Safe Prompts + +If the repo command that triggered the hook supports a "yes" option (e.g., +`repo upload --yes`), this option is propagated to the hook's `main` function +as `yes` parameter (defaulting to `False`). Hooks can use this to bypass +interactive confirmation prompts when they can automatically fix issues. + ### Shebang Handling *** note @@ -119,7 +126,7 @@ The `pre-upload.py` file should be defined like: ```py -def main(project_list, worktree_list=None, **kwargs): +def main(project_list, worktree_list=None, yes=False, **kwargs): """Main function invoked directly by repo. We must use the name "main" as that is what repo requires. @@ -130,6 +137,8 @@ project_list, so that each entry in project_list matches with a directory in worktree_list. If None, we will attempt to calculate the directories automatically. + yes: Whether to answer yes to all safe prompts (see + [Safe Prompts](#safe-prompts)). kwargs: Leave this here for forward-compatibility. """ ```
diff --git a/hooks.py b/hooks.py index 0637dce..5c763db 100644 --- a/hooks.py +++ b/hooks.py
@@ -68,6 +68,7 @@ allow_all_hooks=False, ignore_hooks=False, abort_if_user_denies=False, + yes=False, ): """RepoHook constructor. @@ -89,6 +90,7 @@ ignore_hooks: If True, then 'Do not abort action if hooks fail'. abort_if_user_denies: If True, we'll abort running the hook if the user doesn't allow us to run the hook. + yes: If True, then 'Yes' is assumed for any prompts. """ self._hook_type = hook_type self._hooks_project = hooks_project @@ -99,6 +101,7 @@ self._allow_all_hooks = allow_all_hooks self._ignore_hooks = ignore_hooks self._abort_if_user_denies = abort_if_user_denies + self._yes = yes # Store the full path to the script for convenience. self._script_fullpath = None @@ -374,8 +377,11 @@ # def main(project_list, **kwargs): # # This allows us to later expand the API without breaking old hooks. - kwargs = kwargs.copy() - kwargs["hook_should_take_kwargs"] = True + kwargs = { + **kwargs, + "hook_should_take_kwargs": True, + "yes": self._yes, + } # See what version of python the hook has been written against. data = open(self._script_fullpath).read() @@ -497,6 +503,7 @@ "origin" ).url, "bug_url": manifest.contactinfo.bugurl, + "yes": getattr(opt, "yes", False), } ) return cls(*args, **kwargs)
diff --git a/tests/test_hooks.py b/tests/test_hooks.py index 14c226c..33ccba7 100644 --- a/tests/test_hooks.py +++ b/tests/test_hooks.py
@@ -105,3 +105,37 @@ finally: sys.stderr = old_stderr + + +@pytest.mark.parametrize("yes_val", (True, False)) +def test_repo_upload_yes_arg(tmp_path, yes_val: bool) -> None: + """Test that yes is passed in kwargs during hook execution.""" + + class FakeProject: + def __init__(self, worktree): + self.worktree = worktree + self.enabled_repo_hooks = ["pre-upload"] + self.config = None + + hook_file = tmp_path / "pre-upload.py" + + hook_content = """ +def main(project_list, **kwargs): + project_list.append(kwargs.get("yes")) +""" + hook_file.write_text(hook_content) + + hook = hooks.RepoHook( + hook_type="pre-upload", + hooks_project=FakeProject(str(tmp_path)), + repo_topdir=str(tmp_path), + manifest_url="https://gerrit", + allow_all_hooks=True, + yes=yes_val, + ) + + project_list = [] + res = hook.Run(project_list=project_list, worktree_list=[]) + + assert res is True + assert project_list == [yes_val]