diff --git a/subcmds/rebase.py b/subcmds/rebase.py index d7e769cef..af8be4ea2 100644 --- a/subcmds/rebase.py +++ b/subcmds/rebase.py @@ -16,7 +16,9 @@ import sys from color import Coloring from command import Command +from error import GitError from git_command import GitCommand +from project import Project from repo_logging import RepoLogger @@ -30,6 +32,17 @@ class RebaseColoring(Coloring): self.fail = self.printer("fail", fg="red") +def _ResolveOntoManifest(project: Project) -> str: + """Resolve project's revisionExpr to a local tracking branch. + + Falls back to the raw revisionExpr if ToLocal fails or raises GitError. + """ + try: + return project.GetRemote().ToLocal(project.revisionExpr) + except GitError: + return project.revisionExpr + + class Rebase(Command): COMMON = True helpSummary = "Rebase local branches on upstream branch" @@ -162,7 +175,7 @@ branch but need to incorporate new upstream changes "underneath" them. args = common_args[:] if opt.onto_manifest: args.append("--onto") - args.append(project.revisionExpr) + args.append(_ResolveOntoManifest(project)) args.append(upbranch.LocalMerge) diff --git a/tests/test_subcmds_rebase.py b/tests/test_subcmds_rebase.py new file mode 100644 index 000000000..d7e917316 --- /dev/null +++ b/tests/test_subcmds_rebase.py @@ -0,0 +1,50 @@ +# Copyright (C) 2026 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Unittests for the subcmds/rebase.py module.""" + +from unittest import mock + +from error import GitError +from subcmds import rebase + + +def test_resolve_onto_manifest_success() -> None: + """Test _ResolveOntoManifest when ToLocal succeeds.""" + project = mock.MagicMock() + project.revisionExpr = "main" + + remote = mock.MagicMock() + remote.ToLocal.return_value = "refs/remotes/goog/main" + project.GetRemote.return_value = remote + + res = rebase._ResolveOntoManifest(project) + assert res == "refs/remotes/goog/main" + project.GetRemote.assert_called_once() + remote.ToLocal.assert_called_once_with("main") + + +def test_resolve_onto_manifest_fallback() -> None: + """Test _ResolveOntoManifest when ToLocal raises GitError.""" + project = mock.MagicMock() + project.revisionExpr = "main" + + remote = mock.MagicMock() + remote.ToLocal.side_effect = GitError("Failed to resolve") + project.GetRemote.return_value = remote + + res = rebase._ResolveOntoManifest(project) + assert res == "main" + project.GetRemote.assert_called_once() + remote.ToLocal.assert_called_once_with("main")