Repository: python/cherry-picker

Issue:
A way to force cherry_picker to never open a web browser
Cherry picker calls the webbrowser module from open_pr to open a web browser.  I never want this.  My terminal windows are most often not capable of opening a useful web browser and as such may resort to opening dumb terminal browsers like links or lynx that I refuse to tough github with.  Just print the URL (as it already does) and leave it at that.

Some people may want a web browser.  making it an option (I don't care what the default is) is fine by me.

Discussion:

Patch:
diff --git a/cherry_picker/cherry_picker.py b/cherry_picker/cherry_picker.py
index 48baef5..5c6effc 100755
--- a/cherry_picker/cherry_picker.py
+++ b/cherry_picker/cherry_picker.py
@@ -98,6 +98,7 @@ class CherryPicker:
         prefix_commit=True,
         config=DEFAULT_CONFIG,
         chosen_config_path=None,
+        auto_pr=True,
     ):
 
         self.chosen_config_path = chosen_config_path
@@ -125,6 +126,7 @@ class CherryPicker:
         self.branches = branches
         self.dry_run = dry_run
         self.push = push
+        self.auto_pr = auto_pr
         self.prefix_commit = prefix_commit
 
     def set_paused_state(self):
@@ -297,6 +299,8 @@ Co-authored-by: {get_author_info_from_short_sha(self.commit_sha1)}"""
             click.echo(cpe.output)
             set_state(WORKFLOW_STATES.PUSHING_TO_REMOTE_FAILED)
         else:
+            if not self.auto_pr:
+                return
             gh_auth = os.getenv("GH_AUTH")
             if gh_auth:
                 set_state(WORKFLOW_STATES.PR_CREATING)
@@ -526,7 +530,7 @@ To abort the cherry-pick and cleanup:
                 "Valid states are: "
                 f'{", ".join(s.name for s in self.ALLOWED_STATES)}. '
                 "If this looks suspicious, raise an issue at "
-                "https://github.com/python/core-workflow/issues/new.\n"
+                "https://github.com/python/cherry-picker/issues/new.\n"
                 "As the last resort you can reset the runtime state "
                 "stored in Git config using the following command: "
                 "`git config --local --remove-section cherry-picker`"
@@ -577,6 +581,17 @@ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
     default=True,
     help="Changes won't be pushed to remote",
 )
+@click.option(
+    "--auto-pr/--no-auto-pr",
+    "auto_pr",
+    is_flag=True,
+    default=True,
+    help=(
+        "If auto PR is enabled, cherry-picker will automatically open a PR"
+        " through API if GH_AUTH env var is set, or automatically open the PR"
+        " creation page in the web browser otherwise."
+    ),
+)
 @click.option(
     "--config-path",
     "config_path",
@@ -592,7 +607,7 @@ CONTEXT_SETTINGS = dict(help_option_names=["-h", "--help"])
 @click.argument("branches", nargs=-1)
 @click.pass_context
 def cherry_pick_cli(
-    ctx, dry_run, pr_remote, abort, status, push, config_path, commit_sha1, branches
+    ctx, dry_run, pr_remote, abort, status, push, auto_pr, config_path, commit_sha1, branches
 ):
     """cherry-pick COMMIT_SHA1 into target BRANCHES."""
 
@@ -607,6 +622,7 @@ def cherry_pick_cli(
             branches,
             dry_run=dry_run,
             push=push,
+            auto_pr=auto_pr,
             config=config,
             chosen_config_path=chosen_config_path,
         )
diff --git a/readme.rst b/readme.rst
index 9270c1f..2aa63e1 100644
--- a/readme.rst
+++ b/readme.rst
@@ -301,7 +301,7 @@ Install pytest: ``pip install -U pytest``
 
 ::
 
-    $ pytest test.py
+    $ pytest
 
 
 Publishing to PyPI


Test patch:
diff --git a/cherry_picker/test.py b/cherry_picker/test.py
index 5eb271f..c01ba26 100644
--- a/cherry_picker/test.py
+++ b/cherry_picker/test.py
@@ -636,7 +636,7 @@ def test_get_state_and_verify_fail(
         r"Valid states are: "
         r"[\w_\s]+(, [\w_\s]+)*\. "
         r"If this looks suspicious, raise an issue at "
-        r"https://github.com/python/core-workflow/issues/new\."
+        r"https://github.com/python/cherry-picker/issues/new\."
         "\n"
         r"As the last resort you can reset the runtime state "
         r"stored in Git config using the following command: "
@@ -679,6 +679,18 @@ def test_push_to_remote_botflow(tmp_git_repo_dir, monkeypatch):
     assert get_state() == WORKFLOW_STATES.PR_CREATING
 
 
+def test_push_to_remote_no_auto_pr(tmp_git_repo_dir, monkeypatch):
+    monkeypatch.setenv("GH_AUTH", "True")
+    with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True):
+        cherry_picker = CherryPicker("origin", "xxx", [], auto_pr=False)
+
+    with mock.patch.object(cherry_picker, "run_cmd"), mock.patch.object(
+        cherry_picker, "create_gh_pr"
+    ):
+        cherry_picker.push_to_remote("main", "backport-branch-test")
+    assert get_state() == WORKFLOW_STATES.PUSHED_TO_REMOTE
+
+
 def test_backport_no_branch(tmp_git_repo_dir, monkeypatch):
     with mock.patch("cherry_picker.cherry_picker.validate_sha", return_value=True):
         cherry_picker = CherryPicker("origin", "xxx", [])