upload: bypass branch editor with explicit branch and -y

When uploading across multiple projects with --yes and an explicit
branch specified (via --current-branch / -c or --branch / --br),
repo previously still opened the interactive branch selection editor.

If an explicit branch and --yes are provided, bypass the interactive
editor and upload all matching pending branches directly.

Bug: 553024110
Test: python3 -m pytest tests/
Test: flake8 subcmds/upload.py tests/test_subcmds_upload.py
Test: isort --check subcmds/upload.py tests/test_subcmds_upload.py
Change-Id: I104619603f6e0539d05b01d3eb0292a9145d58db
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/622661
Tested-by: Arif Kasim <arifkasim@google.com>
Reviewed-by: Gavin Mak <gavinmak@google.com>
diff --git a/subcmds/upload.py b/subcmds/upload.py
index 79924fc..2215f9e 100644
--- a/subcmds/upload.py
+++ b/subcmds/upload.py
@@ -435,6 +435,18 @@
         self._UploadAndReport(opt, [branch], people)
 
     def _MultipleBranches(self, opt, pending, people):
+        if opt.yes and (opt.current_branch or opt.branch):
+            todo = [
+                branch
+                for _, avail in pending
+                for branch in avail
+                if branch is not None
+            ]
+            if not todo:
+                _die("nothing ready for upload")
+            self._UploadAndReport(opt, todo, people)
+            return
+
         projects = {}
         branches = {}
 
diff --git a/tests/test_subcmds_upload.py b/tests/test_subcmds_upload.py
index 06a0c9f..53666fe 100644
--- a/tests/test_subcmds_upload.py
+++ b/tests/test_subcmds_upload.py
@@ -14,6 +14,7 @@
 
 """Unittests for the subcmds/upload.py module."""
 
+from typing import List, Optional
 from unittest import mock
 
 import pytest
@@ -117,3 +118,118 @@
     assert upload.Upload._GatherOne(opt, 0) == (0, [branch], "topic")
 
     project.GetUploadableBranch.assert_called_once_with("topic")
+
+
+def _create_mock_branch(
+    name: str = "main",
+    commits: Optional[List[str]] = None,
+    project_relpath: str = "project-a",
+) -> mock.MagicMock:
+    """Helper to construct a mock ReviewableBranch."""
+    branch = mock.MagicMock()
+    branch.name = name
+    branch.commits = commits if commits is not None else ["commit1"]
+
+    project = mock.MagicMock()
+    project.RelPath.return_value = project_relpath
+    branch.project = project
+    return branch
+
+
+def test_MultipleBranches_yes_with_current_branch_flag_bypasses_editor(
+    cmd: upload.Upload,
+) -> None:
+    """_MultipleBranches with --yes and -c flag bypasses editor."""
+    opt, _ = cmd.OptionParser.parse_args(["-c", "-y"])
+    branch1 = _create_mock_branch("b1", project_relpath="p1")
+    branch2 = _create_mock_branch("b2", project_relpath="p2")
+    pending = [(branch1.project, [branch1]), (branch2.project, [branch2])]
+
+    with mock.patch.object(cmd, "_UploadAndReport") as mock_upload, mock.patch(
+        "editor.Editor.EditString"
+    ) as mock_edit:
+        cmd._MultipleBranches(opt, pending, _STUB_PEOPLE)
+        mock_edit.assert_not_called()
+        mock_upload.assert_called_once_with(
+            opt, [branch1, branch2], _STUB_PEOPLE
+        )
+
+
+def test_MultipleBranches_yes_with_cbr_flag_bypasses_editor(
+    cmd: upload.Upload,
+) -> None:
+    """_MultipleBranches with --yes and --cbr flag bypasses editor."""
+    opt, _ = cmd.OptionParser.parse_args(["--cbr", "--yes"])
+    branch1 = _create_mock_branch("b1", project_relpath="p1")
+    branch2 = _create_mock_branch("b2", project_relpath="p2")
+    pending = [(branch1.project, [branch1]), (branch2.project, [branch2])]
+
+    with mock.patch.object(cmd, "_UploadAndReport") as mock_upload, mock.patch(
+        "editor.Editor.EditString"
+    ) as mock_edit:
+        cmd._MultipleBranches(opt, pending, _STUB_PEOPLE)
+        mock_edit.assert_not_called()
+        mock_upload.assert_called_once_with(
+            opt, [branch1, branch2], _STUB_PEOPLE
+        )
+
+
+def test_MultipleBranches_yes_with_branch_flag_bypasses_editor(
+    cmd: upload.Upload,
+) -> None:
+    """_MultipleBranches with --yes and --br flag bypasses editor."""
+    opt, _ = cmd.OptionParser.parse_args(["--br", "feature", "-y"])
+    branch1 = _create_mock_branch("feature", project_relpath="p1")
+    branch2 = _create_mock_branch("feature", project_relpath="p2")
+    pending = [(branch1.project, [branch1]), (branch2.project, [branch2])]
+
+    with mock.patch.object(cmd, "_UploadAndReport") as mock_upload, mock.patch(
+        "editor.Editor.EditString"
+    ) as mock_edit:
+        cmd._MultipleBranches(opt, pending, _STUB_PEOPLE)
+        mock_edit.assert_not_called()
+        mock_upload.assert_called_once_with(
+            opt, [branch1, branch2], _STUB_PEOPLE
+        )
+
+
+def test_MultipleBranches_yes_with_branch_flag_empty_pending_dies(
+    cmd: upload.Upload,
+) -> None:
+    """_MultipleBranches with --yes and empty pending branches dies."""
+    opt, _ = cmd.OptionParser.parse_args(["--br", "feature", "-y"])
+    mock_project = mock.MagicMock()
+    pending = [(mock_project, [])]
+
+    with pytest.raises(
+        upload.UploadExitError, match="nothing ready for upload"
+    ):
+        cmd._MultipleBranches(opt, pending, _STUB_PEOPLE)
+
+
+def test_MultipleBranches_yes_without_branch_or_cbr_uses_editor(
+    cmd: upload.Upload,
+) -> None:
+    """_MultipleBranches with -y but no -c/--br falls back to editor."""
+    opt, _ = cmd.OptionParser.parse_args(["-y"])
+    branch1 = _create_mock_branch("b1", project_relpath="p1")
+    branch1.date = "2026-08-26"
+    mock_remote = mock.MagicMock()
+    branch1.project.dest_branch = None
+    branch1.project.revisionExpr = "refs/heads/main"
+    branch_config = mock.MagicMock()
+    branch_config.remote = mock_remote
+    branch1.project.GetBranch.return_value = branch_config
+    pending = [(branch1.project, [branch1])]
+
+    edited_script = (
+        "project p1/:\n"
+        "  branch b1 ( 1 commit, 2026-08-26) to remote branch "
+        "refs/heads/main:\n"
+    )
+    with mock.patch.object(cmd, "_UploadAndReport") as mock_upload, mock.patch(
+        "editor.Editor.EditString", return_value=edited_script
+    ) as mock_edit:
+        cmd._MultipleBranches(opt, pending, _STUB_PEOPLE)
+        mock_edit.assert_called_once()
+        mock_upload.assert_called_once_with(opt, [branch1], _STUB_PEOPLE)