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>
This commit is contained in:
Arif Kasim
2026-09-09 12:10:24 -07:00
parent d27d6829a8
commit fe2c23f8e2
2 changed files with 128 additions and 0 deletions
+12
View File
@@ -435,6 +435,18 @@ Gerrit Code Review: https://www.gerritcodereview.com/
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 = {}
+116
View File
@@ -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 @@ def test_GatherOne_returns_resolved_current_branch(
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)