diff options
| author | Gavin Mak <gavinmak@google.com> | 2026-04-22 00:39:42 +0000 |
|---|---|---|
| committer | gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com> | 2026-05-20 12:28:55 -0700 |
| commit | 2d54384a5e59fddd0626ec091cc0ad11511d834e (patch) | |
| tree | c0a9d642bb4064a23df2044777b6f81f2c047473 | |
| parent | 1b4e7a04be7b49d8c0c5e161d36f209bca4b6498 (diff) | |
| download | git-repo-2.64.tar.gz | |
sync: Add --superproject-rev flag to sync to specific revisionv2.64
Allow syncing the outer manifest to a state defined by a specific
superproject revision. It updates the superproject, reads the manifest
commit from .supermanifest, and checks out the outer manifest project
to that commit.
Submanifests are then processed normally, allowing them to be updated
to the revisions specified in the new outer manifest state.
Bug: 416589884
Change-Id: I304c37a2b8794f9b74cb7e5e209a8a93762bdb52
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/576321
Commit-Queue: Gavin Mak <gavinmak@google.com>
Tested-by: Gavin Mak <gavinmak@google.com>
Reviewed-by: Mike Frysinger <vapier@google.com>
| -rw-r--r-- | git_superproject.py | 16 | ||||
| -rw-r--r-- | man/repo-smartsync.1 | 6 | ||||
| -rw-r--r-- | man/repo-sync.1 | 6 | ||||
| -rw-r--r-- | subcmds/sync.py | 85 | ||||
| -rw-r--r-- | tests/test_subcmds_sync.py | 168 |
5 files changed, 271 insertions, 10 deletions
diff --git a/git_superproject.py b/git_superproject.py index 81a6b2e59..27bc10e10 100644 --- a/git_superproject.py +++ b/git_superproject.py | |||
| @@ -34,6 +34,7 @@ import urllib.parse | |||
| 34 | 34 | ||
| 35 | from git_command import git_require | 35 | from git_command import git_require |
| 36 | from git_command import GitCommand | 36 | from git_command import GitCommand |
| 37 | from git_config import IsId | ||
| 37 | from git_config import RepoConfig | 38 | from git_config import RepoConfig |
| 38 | from git_refs import GitRefs | 39 | from git_refs import GitRefs |
| 39 | import platform_utils | 40 | import platform_utils |
| @@ -132,6 +133,10 @@ class Superproject: | |||
| 132 | """Set the _print_messages attribute.""" | 133 | """Set the _print_messages attribute.""" |
| 133 | self._print_messages = value | 134 | self._print_messages = value |
| 134 | 135 | ||
| 136 | def SetRevisionId(self, revision_id: str) -> None: | ||
| 137 | """Set the revisionId of the superproject to sync to.""" | ||
| 138 | self.revision = revision_id | ||
| 139 | |||
| 135 | @property | 140 | @property |
| 136 | def commit_id(self): | 141 | def commit_id(self): |
| 137 | """Returns the commit ID of the superproject checkout.""" | 142 | """Returns the commit ID of the superproject checkout.""" |
| @@ -314,7 +319,14 @@ class Superproject: | |||
| 314 | cmd.extend(["--negotiation-tip", rev_commit]) | 319 | cmd.extend(["--negotiation-tip", rev_commit]) |
| 315 | 320 | ||
| 316 | if self.revision: | 321 | if self.revision: |
| 317 | cmd += [self.revision + ":" + self.revision] | 322 | # If revision is a commit hash, fetch it directly to avoid |
| 323 | # creating a local branch of the same name. | ||
| 324 | refspec = ( | ||
| 325 | self.revision | ||
| 326 | if IsId(self.revision) | ||
| 327 | else f"{self.revision}:{self.revision}" | ||
| 328 | ) | ||
| 329 | cmd.append(refspec) | ||
| 318 | p = GitCommand( | 330 | p = GitCommand( |
| 319 | None, | 331 | None, |
| 320 | cmd, | 332 | cmd, |
| @@ -401,6 +413,8 @@ class Superproject: | |||
| 401 | 413 | ||
| 402 | if not self._Init(): | 414 | if not self._Init(): |
| 403 | return SyncResult(False, should_exit) | 415 | return SyncResult(False, should_exit) |
| 416 | if IsId(self.revision) and self.commit_id: | ||
| 417 | return SyncResult(True, False) | ||
| 404 | if not self._Fetch(): | 418 | if not self._Fetch(): |
| 405 | return SyncResult(False, should_exit) | 419 | return SyncResult(False, should_exit) |
| 406 | if not self._quiet: | 420 | if not self._quiet: |
diff --git a/man/repo-smartsync.1 b/man/repo-smartsync.1 index 5ea063e6b..25b85f126 100644 --- a/man/repo-smartsync.1 +++ b/man/repo-smartsync.1 | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. | 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. |
| 2 | .TH REPO "1" "August 2025" "repo smartsync" "Repo Manual" | 2 | .TH REPO "1" "May 2026" "repo smartsync" "Repo Manual" |
| 3 | .SH NAME | 3 | .SH NAME |
| 4 | repo \- repo smartsync - manual page for repo smartsync | 4 | repo \- repo smartsync - manual page for repo smartsync |
| 5 | .SH SYNOPSIS | 5 | .SH SYNOPSIS |
| @@ -101,6 +101,10 @@ implies \fB\-c\fR | |||
| 101 | \fB\-\-no\-use\-superproject\fR | 101 | \fB\-\-no\-use\-superproject\fR |
| 102 | disable use of manifest superprojects | 102 | disable use of manifest superprojects |
| 103 | .TP | 103 | .TP |
| 104 | \fB\-\-superproject\-revision\fR=\fI\,SUPERPROJECT_REVISION\/\fR | ||
| 105 | sync to superproject revision (applies to outer | ||
| 106 | manifest) | ||
| 107 | .TP | ||
| 104 | \fB\-\-tags\fR | 108 | \fB\-\-tags\fR |
| 105 | fetch tags | 109 | fetch tags |
| 106 | .TP | 110 | .TP |
diff --git a/man/repo-sync.1 b/man/repo-sync.1 index 8f145a09e..4e115e200 100644 --- a/man/repo-sync.1 +++ b/man/repo-sync.1 | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. | 1 | .\" DO NOT MODIFY THIS FILE! It was generated by help2man. |
| 2 | .TH REPO "1" "August 2025" "repo sync" "Repo Manual" | 2 | .TH REPO "1" "May 2026" "repo sync" "Repo Manual" |
| 3 | .SH NAME | 3 | .SH NAME |
| 4 | repo \- repo sync - manual page for repo sync | 4 | repo \- repo sync - manual page for repo sync |
| 5 | .SH SYNOPSIS | 5 | .SH SYNOPSIS |
| @@ -101,6 +101,10 @@ implies \fB\-c\fR | |||
| 101 | \fB\-\-no\-use\-superproject\fR | 101 | \fB\-\-no\-use\-superproject\fR |
| 102 | disable use of manifest superprojects | 102 | disable use of manifest superprojects |
| 103 | .TP | 103 | .TP |
| 104 | \fB\-\-superproject\-revision\fR=\fI\,SUPERPROJECT_REVISION\/\fR | ||
| 105 | sync to superproject revision (applies to outer | ||
| 106 | manifest) | ||
| 107 | .TP | ||
| 104 | \fB\-\-tags\fR | 108 | \fB\-\-tags\fR |
| 105 | fetch tags | 109 | fetch tags |
| 106 | .TP | 110 | .TP |
diff --git a/subcmds/sync.py b/subcmds/sync.py index 8c2591180..7e0e7418c 100644 --- a/subcmds/sync.py +++ b/subcmds/sync.py | |||
| @@ -64,6 +64,7 @@ from error import SyncError | |||
| 64 | from error import UpdateManifestError | 64 | from error import UpdateManifestError |
| 65 | import event_log | 65 | import event_log |
| 66 | from git_command import git_require | 66 | from git_command import git_require |
| 67 | from git_command import GitCommand | ||
| 67 | from git_config import GetUrlCookieFile | 68 | from git_config import GetUrlCookieFile |
| 68 | from git_refs import HEAD | 69 | from git_refs import HEAD |
| 69 | from git_refs import R_HEADS | 70 | from git_refs import R_HEADS |
| @@ -565,6 +566,11 @@ later is required to fix a server side protocol bug. | |||
| 565 | dest="use_superproject", | 566 | dest="use_superproject", |
| 566 | help="disable use of manifest superprojects", | 567 | help="disable use of manifest superprojects", |
| 567 | ) | 568 | ) |
| 569 | p.add_option( | ||
| 570 | "--superproject-revision", | ||
| 571 | action="store", | ||
| 572 | help="sync to superproject revision (applies to outer manifest)", | ||
| 573 | ) | ||
| 568 | p.add_option("--tags", action="store_true", help="fetch tags") | 574 | p.add_option("--tags", action="store_true", help="fetch tags") |
| 569 | p.add_option( | 575 | p.add_option( |
| 570 | "--no-tags", | 576 | "--no-tags", |
| @@ -668,6 +674,24 @@ later is required to fix a server side protocol bug. | |||
| 668 | or opt.current_branch_only | 674 | or opt.current_branch_only |
| 669 | ) | 675 | ) |
| 670 | 676 | ||
| 677 | def _ConfigureSuperproject( | ||
| 678 | self, | ||
| 679 | opt: optparse.Values, | ||
| 680 | manifest, | ||
| 681 | revision: Optional[str] = None, | ||
| 682 | ) -> bool: | ||
| 683 | """Configure superproject with options.""" | ||
| 684 | if not manifest.superproject: | ||
| 685 | return False | ||
| 686 | manifest.superproject.SetQuiet(not opt.verbose) | ||
| 687 | print_messages = git_superproject.PrintMessages( | ||
| 688 | opt.use_superproject, manifest | ||
| 689 | ) | ||
| 690 | manifest.superproject.SetPrintMessages(print_messages) | ||
| 691 | if revision: | ||
| 692 | manifest.superproject.SetRevisionId(revision) | ||
| 693 | return print_messages | ||
| 694 | |||
| 671 | def _UpdateProjectsRevisionId( | 695 | def _UpdateProjectsRevisionId( |
| 672 | self, opt, args, superproject_logging_data, manifest | 696 | self, opt, args, superproject_logging_data, manifest |
| 673 | ): | 697 | ): |
| @@ -741,11 +765,7 @@ later is required to fix a server side protocol bug. | |||
| 741 | 765 | ||
| 742 | if not use_super: | 766 | if not use_super: |
| 743 | continue | 767 | continue |
| 744 | m.superproject.SetQuiet(not opt.verbose) | 768 | print_messages = self._ConfigureSuperproject(opt, m) |
| 745 | print_messages = git_superproject.PrintMessages( | ||
| 746 | opt.use_superproject, m | ||
| 747 | ) | ||
| 748 | m.superproject.SetPrintMessages(print_messages) | ||
| 749 | update_result = m.superproject.UpdateProjectsRevisionId( | 769 | update_result = m.superproject.UpdateProjectsRevisionId( |
| 750 | per_manifest[m.path_prefix], git_event_log=self.git_event_log | 770 | per_manifest[m.path_prefix], git_event_log=self.git_event_log |
| 751 | ) | 771 | ) |
| @@ -1832,7 +1852,11 @@ later is required to fix a server side protocol bug. | |||
| 1832 | mp: the manifestProject to query. | 1852 | mp: the manifestProject to query. |
| 1833 | manifest_name: Manifest file to be reloaded. | 1853 | manifest_name: Manifest file to be reloaded. |
| 1834 | """ | 1854 | """ |
| 1835 | if not mp.standalone_manifest_url: | 1855 | if opt.superproject_revision and mp.manifest == self.outer_manifest: |
| 1856 | self._SyncToSuperprojectRev( | ||
| 1857 | opt, mp.manifest, mp, manifest_name, errors | ||
| 1858 | ) | ||
| 1859 | elif not mp.standalone_manifest_url: | ||
| 1836 | self._UpdateManifestProject(opt, mp, manifest_name, errors) | 1860 | self._UpdateManifestProject(opt, mp, manifest_name, errors) |
| 1837 | 1861 | ||
| 1838 | if mp.manifest.submanifests: | 1862 | if mp.manifest.submanifests: |
| @@ -2041,6 +2065,53 @@ later is required to fix a server side protocol bug. | |||
| 2041 | if not success: | 2065 | if not success: |
| 2042 | print("Warning: post-sync hook reported failure.") | 2066 | print("Warning: post-sync hook reported failure.") |
| 2043 | 2067 | ||
| 2068 | def _SyncToSuperprojectRev( | ||
| 2069 | self, | ||
| 2070 | opt: optparse.Values, | ||
| 2071 | manifest, | ||
| 2072 | mp: Project, | ||
| 2073 | manifest_name: Optional[str], | ||
| 2074 | errors: List[Exception], | ||
| 2075 | ) -> None: | ||
| 2076 | """Sync to a specific superproject commit.""" | ||
| 2077 | if not manifest.superproject: | ||
| 2078 | raise SyncError("superproject not defined in manifest") | ||
| 2079 | |||
| 2080 | self._ConfigureSuperproject( | ||
| 2081 | opt, manifest, revision=opt.superproject_revision | ||
| 2082 | ) | ||
| 2083 | |||
| 2084 | sync_result = manifest.superproject.Sync(self.git_event_log) | ||
| 2085 | if not sync_result.success: | ||
| 2086 | raise SyncError("failed to sync superproject") | ||
| 2087 | |||
| 2088 | cmd = ["show", f"{opt.superproject_revision}:.supermanifest"] | ||
| 2089 | p = GitCommand( | ||
| 2090 | None, | ||
| 2091 | cmd, | ||
| 2092 | gitdir=manifest.superproject._work_git, | ||
| 2093 | bare=True, | ||
| 2094 | capture_stdout=True, | ||
| 2095 | capture_stderr=True, | ||
| 2096 | ) | ||
| 2097 | if p.Wait() != 0: | ||
| 2098 | raise SyncError( | ||
| 2099 | f"failed to read .supermanifest from superproject: {p.stderr}" | ||
| 2100 | ) | ||
| 2101 | |||
| 2102 | try: | ||
| 2103 | _, _, manifest_commit = p.stdout.strip().split() | ||
| 2104 | except ValueError: | ||
| 2105 | raise SyncError("could not parse .supermanifest") | ||
| 2106 | |||
| 2107 | mp.SetRevision(manifest_commit) | ||
| 2108 | try: | ||
| 2109 | self._UpdateManifestProject(opt, mp, manifest_name, errors) | ||
| 2110 | except UpdateManifestError as e: | ||
| 2111 | raise SyncError( | ||
| 2112 | "failed to sync manifest project", aggregate_errors=[e] | ||
| 2113 | ) | ||
| 2114 | |||
| 2044 | def _ExecuteHelper(self, opt, args, errors): | 2115 | def _ExecuteHelper(self, opt, args, errors): |
| 2045 | manifest = self.outer_manifest | 2116 | manifest = self.outer_manifest |
| 2046 | if not opt.outer_manifest: | 2117 | if not opt.outer_manifest: |
| @@ -2099,7 +2170,7 @@ later is required to fix a server side protocol bug. | |||
| 2099 | ): | 2170 | ): |
| 2100 | mp.ConfigureCloneFilterForDepth("blob:none") | 2171 | mp.ConfigureCloneFilterForDepth("blob:none") |
| 2101 | 2172 | ||
| 2102 | if opt.mp_update: | 2173 | if opt.mp_update or opt.superproject_revision: |
| 2103 | self._UpdateAllManifestProjects(opt, mp, manifest_name, errors) | 2174 | self._UpdateAllManifestProjects(opt, mp, manifest_name, errors) |
| 2104 | else: | 2175 | else: |
| 2105 | print("Skipping update of local manifest project.") | 2176 | print("Skipping update of local manifest project.") |
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py index ef162392b..785c0e629 100644 --- a/tests/test_subcmds_sync.py +++ b/tests/test_subcmds_sync.py | |||
| @@ -1286,3 +1286,171 @@ class UpdateCopyLinkfileListTest(unittest.TestCase): | |||
| 1286 | self.assertFalse(os.path.lexists(os.path.join(llms_dir, "rules"))) | 1286 | self.assertFalse(os.path.lexists(os.path.join(llms_dir, "rules"))) |
| 1287 | self.assertTrue(os.path.exists(os.path.join(llms_dir, "my-notes.txt"))) | 1287 | self.assertTrue(os.path.exists(os.path.join(llms_dir, "my-notes.txt"))) |
| 1288 | self.assertTrue(os.path.isdir(llms_dir)) | 1288 | self.assertTrue(os.path.isdir(llms_dir)) |
| 1289 | |||
| 1290 | |||
| 1291 | class SyncToSuperprojectRevTests(unittest.TestCase): | ||
| 1292 | """Tests for Sync._SyncToSuperprojectRev.""" | ||
| 1293 | |||
| 1294 | def setUp(self): | ||
| 1295 | self.repodir = tempfile.mkdtemp(".repo") | ||
| 1296 | self.manifest = mock.MagicMock(repodir=self.repodir) | ||
| 1297 | self.manifest.superproject = mock.MagicMock() | ||
| 1298 | self.manifest.path_prefix = "" | ||
| 1299 | |||
| 1300 | self.mp = mock.MagicMock() | ||
| 1301 | self.cmd = sync.Sync(manifest=self.manifest) | ||
| 1302 | self.cmd.outer_manifest = self.manifest | ||
| 1303 | |||
| 1304 | self.opt = mock.Mock() | ||
| 1305 | self.opt.verbose = False | ||
| 1306 | self.opt.superproject_revision = "deadbeef" | ||
| 1307 | self.opt.mp_update = True | ||
| 1308 | |||
| 1309 | self.errors = [] | ||
| 1310 | |||
| 1311 | def tearDown(self): | ||
| 1312 | shutil.rmtree(self.repodir) | ||
| 1313 | |||
| 1314 | @mock.patch("subcmds.sync.GitCommand") | ||
| 1315 | def test_successful_sync(self, mock_git_command): | ||
| 1316 | """Test successful sync to superproject rev.""" | ||
| 1317 | mock_superproject = self.manifest.superproject | ||
| 1318 | mock_superproject.Sync.return_value = mock.Mock(success=True) | ||
| 1319 | |||
| 1320 | mock_git = mock.Mock() | ||
| 1321 | mock_git.Wait.return_value = 0 | ||
| 1322 | mock_git.stdout = "proj branch manifest_commit_hash\n" | ||
| 1323 | mock_git_command.return_value = mock_git | ||
| 1324 | |||
| 1325 | with mock.patch.object( | ||
| 1326 | self.cmd, "_UpdateManifestProject" | ||
| 1327 | ) as mock_update: | ||
| 1328 | self.cmd._SyncToSuperprojectRev( | ||
| 1329 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1330 | ) | ||
| 1331 | |||
| 1332 | mock_superproject.SetRevisionId.assert_called_with("deadbeef") | ||
| 1333 | mock_superproject.Sync.assert_called_once() | ||
| 1334 | mock_git_command.assert_called_once() | ||
| 1335 | self.mp.SetRevision.assert_called_with("manifest_commit_hash") | ||
| 1336 | mock_update.assert_called_once() | ||
| 1337 | self.assertEqual(self.errors, []) | ||
| 1338 | |||
| 1339 | @mock.patch("subcmds.sync.GitCommand") | ||
| 1340 | def test_parse_error(self, mock_git_command): | ||
| 1341 | """Test error when .supermanifest cannot be parsed.""" | ||
| 1342 | mock_superproject = self.manifest.superproject | ||
| 1343 | mock_superproject.Sync.return_value = mock.Mock(success=True) | ||
| 1344 | |||
| 1345 | mock_git = mock.Mock() | ||
| 1346 | mock_git.Wait.return_value = 0 | ||
| 1347 | # Invalid format (not 3 parts) | ||
| 1348 | mock_git.stdout = "invalid_content\n" | ||
| 1349 | mock_git_command.return_value = mock_git | ||
| 1350 | |||
| 1351 | with self.assertRaises(sync.SyncError) as e: | ||
| 1352 | self.cmd._SyncToSuperprojectRev( | ||
| 1353 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1354 | ) | ||
| 1355 | self.assertIn("could not parse .supermanifest", str(e.exception)) | ||
| 1356 | |||
| 1357 | @mock.patch("subcmds.sync.GitCommand") | ||
| 1358 | def test_read_error(self, mock_git_command): | ||
| 1359 | """Test error when reading .supermanifest fails.""" | ||
| 1360 | mock_superproject = self.manifest.superproject | ||
| 1361 | mock_superproject.Sync.return_value = mock.Mock(success=True) | ||
| 1362 | |||
| 1363 | mock_git = mock.Mock() | ||
| 1364 | mock_git.Wait.return_value = 1 | ||
| 1365 | mock_git.stderr = "git error" | ||
| 1366 | mock_git_command.return_value = mock_git | ||
| 1367 | |||
| 1368 | with self.assertRaises(sync.SyncError) as e: | ||
| 1369 | self.cmd._SyncToSuperprojectRev( | ||
| 1370 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1371 | ) | ||
| 1372 | self.assertIn("failed to read .supermanifest", str(e.exception)) | ||
| 1373 | |||
| 1374 | def test_no_superproject(self): | ||
| 1375 | """Test error when superproject is not defined.""" | ||
| 1376 | self.manifest.superproject = None | ||
| 1377 | |||
| 1378 | with self.assertRaises(sync.SyncError) as e: | ||
| 1379 | self.cmd._SyncToSuperprojectRev( | ||
| 1380 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1381 | ) | ||
| 1382 | self.assertIn("superproject not defined", str(e.exception)) | ||
| 1383 | |||
| 1384 | @mock.patch("subcmds.sync.GitCommand") | ||
| 1385 | def test_sync_failure(self, mock_git_command): | ||
| 1386 | """Test error when superproject sync fails.""" | ||
| 1387 | mock_superproject = self.manifest.superproject | ||
| 1388 | mock_superproject.Sync.return_value = mock.Mock(success=False) | ||
| 1389 | |||
| 1390 | with self.assertRaises(sync.SyncError) as e: | ||
| 1391 | self.cmd._SyncToSuperprojectRev( | ||
| 1392 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1393 | ) | ||
| 1394 | self.assertIn("failed to sync superproject", str(e.exception)) | ||
| 1395 | |||
| 1396 | |||
| 1397 | class UpdateAllManifestProjectsTests(unittest.TestCase): | ||
| 1398 | """Tests for Sync._UpdateAllManifestProjects.""" | ||
| 1399 | |||
| 1400 | def setUp(self): | ||
| 1401 | self.repodir = tempfile.mkdtemp(".repo") | ||
| 1402 | self.manifest = mock.MagicMock(repodir=self.repodir) | ||
| 1403 | self.manifest.superproject = mock.MagicMock() | ||
| 1404 | self.manifest.path_prefix = "" | ||
| 1405 | self.manifest.standalone_manifest_url = None | ||
| 1406 | self.manifest.submanifests = {} | ||
| 1407 | |||
| 1408 | self.mp = mock.MagicMock() | ||
| 1409 | self.mp.manifest = self.manifest | ||
| 1410 | self.mp.standalone_manifest_url = None | ||
| 1411 | self.cmd = sync.Sync(manifest=self.manifest) | ||
| 1412 | self.cmd.outer_manifest = self.manifest | ||
| 1413 | |||
| 1414 | self.opt = mock.Mock() | ||
| 1415 | self.opt.verbose = False | ||
| 1416 | self.opt.superproject_revision = None | ||
| 1417 | self.opt.mp_update = True | ||
| 1418 | |||
| 1419 | self.errors = [] | ||
| 1420 | |||
| 1421 | def tearDown(self): | ||
| 1422 | shutil.rmtree(self.repodir) | ||
| 1423 | |||
| 1424 | def test_superproject_revision_outer_manifest(self): | ||
| 1425 | """Test that _SyncToSuperprojectRev is called for outer manifest.""" | ||
| 1426 | self.opt.superproject_revision = "deadbeef" | ||
| 1427 | |||
| 1428 | with mock.patch.object( | ||
| 1429 | self.cmd, "_SyncToSuperprojectRev" | ||
| 1430 | ) as mock_sync_to_rev: | ||
| 1431 | self.cmd._UpdateAllManifestProjects( | ||
| 1432 | self.opt, self.mp, "name", self.errors | ||
| 1433 | ) | ||
| 1434 | mock_sync_to_rev.assert_called_once_with( | ||
| 1435 | self.opt, self.manifest, self.mp, "name", self.errors | ||
| 1436 | ) | ||
| 1437 | |||
| 1438 | def test_superproject_revision_submanifest(self): | ||
| 1439 | """Test that _SyncToSuperprojectRev is NOT called for submanifest.""" | ||
| 1440 | self.opt.superproject_revision = "deadbeef" | ||
| 1441 | submanifest = mock.MagicMock() | ||
| 1442 | submanifest.path_prefix = "sub/" | ||
| 1443 | submanifest.standalone_manifest_url = None | ||
| 1444 | self.mp.manifest = submanifest | ||
| 1445 | |||
| 1446 | with mock.patch.object( | ||
| 1447 | self.cmd, "_SyncToSuperprojectRev" | ||
| 1448 | ) as mock_sync_to_rev: | ||
| 1449 | with mock.patch.object( | ||
| 1450 | self.cmd, "_UpdateManifestProject" | ||
| 1451 | ) as mock_update_manifest: | ||
| 1452 | self.cmd._UpdateAllManifestProjects( | ||
| 1453 | self.opt, self.mp, "name", self.errors | ||
| 1454 | ) | ||
| 1455 | mock_sync_to_rev.assert_not_called() | ||
| 1456 | mock_update_manifest.assert_called_once() | ||
