summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAndrew Chant <achant@google.com>2026-07-17 15:09:06 -0700
committergerrit-scoped@luci-project-accounts.iam.gserviceaccount.com <gerrit-scoped@luci-project-accounts.iam.gserviceaccount.com>2026-07-21 13:42:38 -0700
commit0b82311632d14d3f49675fb6a017c20f7a7dee37 (patch)
tree265e41f241585ae11afd6f4b12dfa0e9a60ef726 /tests
parent06c4f9e1cca33a51b5396de2d1d975648e9f2ce4 (diff)
downloadgit-repo-0b82311632d14d3f49675fb6a017c20f7a7dee37.tar.gz
git-repo-0b82311632d14d3f49675fb6a017c20f7a7dee37.zip
sync: allow syncing groups with repo sync -g groupHEADmain
Similar to how repo init -g can restrict repo syncs to a subset of the manifest globally, allow "repo sync -g" to only sync a subset of projects from the manifest when running that specific sync command. Change-Id: I4929aad109de05c73a7db42bb27fd8d47eea32fc Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/609481 Reviewed-by: Mike Frysinger <vapier@google.com> Commit-Queue: Andrew Chant <achant@google.com> Reviewed-by: Gavin Mak <gavinmak@google.com> Tested-by: Andrew Chant <achant@google.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/test_subcmds_sync.py129
1 files changed, 129 insertions, 0 deletions
diff --git a/tests/test_subcmds_sync.py b/tests/test_subcmds_sync.py
index 36ba13cae..bc0a82759 100644
--- a/tests/test_subcmds_sync.py
+++ b/tests/test_subcmds_sync.py
@@ -15,6 +15,7 @@
import json
import os
+from pathlib import Path
import shutil
import tempfile
import time
@@ -26,6 +27,7 @@ import pytest
import command
from error import GitError
from error import RepoExitError
+import manifest_xml
from project import SyncNetworkHalfResult
from subcmds import sync
@@ -96,6 +98,120 @@ def test_get_current_branch_only(use_superproject, cli_args, result):
assert cmd._GetCurrentBranchOnly(opts, cmd.manifest) == result
+@pytest.mark.parametrize(
+ "cli_args, expected_groups",
+ [
+ ([], None),
+ (["-g", "groupA"], "groupA"),
+ (["--groups=groupB,groupC"], "groupB,groupC"),
+ ],
+)
+def test_groups_option_parsing(cli_args, expected_groups):
+ """Test --groups / -g option parsing."""
+ cmd = sync.Sync()
+ opts, _ = cmd.OptionParser.parse_args(cli_args)
+ assert opts.groups == expected_groups
+
+
+def _create_manifest_with_groups(topdir: Path) -> manifest_xml.XmlManifest:
+ """Create a test XmlManifest with projects assigned to various groups."""
+ repodir = topdir / ".repo"
+ manifest_dir = repodir / "manifests"
+ manifest_file = repodir / manifest_xml.MANIFEST_FILE_NAME
+
+ repodir.mkdir(exist_ok=True)
+ manifest_dir.mkdir(exist_ok=True)
+
+ gitdir = repodir / "manifests.git"
+ gitdir.mkdir(exist_ok=True)
+ (gitdir / "config").write_text(
+ """[remote "origin"]
+ url = https://localhost:0/manifest
+ """,
+ encoding="utf-8",
+ )
+
+ manifest_file.write_text(
+ """
+ <manifest>
+ <remote name="origin" fetch="http://localhost" />
+ <default remote="origin" revision="refs/heads/main" />
+ <project name="proj_g1" path="path_g1" groups="group1" />
+ <project name="proj_g2" path="path_g2" groups="group2" />
+ <project name="proj_g1_g2" path="path_g1_g2"
+ groups="group1,group2" />
+ <project name="proj_default" path="path_default" />
+ <project name="proj_notdefault" path="path_notdefault"
+ groups="notdefault" />
+ </manifest>
+ """,
+ encoding="utf-8",
+ )
+
+ for p in [
+ "proj_g1",
+ "proj_g2",
+ "proj_g1_g2",
+ "proj_default",
+ "proj_notdefault",
+ ]:
+ (repodir / "projects" / f"{p}.git").mkdir(parents=True, exist_ok=True)
+
+ return manifest_xml.XmlManifest(str(repodir), str(manifest_file))
+
+
+@pytest.mark.parametrize(
+ "cli_args, expected_projects",
+ [
+ (["-g", "group1"], ["proj_g1", "proj_g1_g2"]),
+ (["-g", "group2"], ["proj_g2", "proj_g1_g2"]),
+ (["-g", "group1,group2"], ["proj_g1", "proj_g1_g2", "proj_g2"]),
+ (["-g", "default,-group1"], ["proj_default", "proj_g2"]),
+ ([], ["proj_default", "proj_g1", "proj_g1_g2", "proj_g2"]),
+ ],
+)
+def test_sync_groups_manifest_filtering(
+ tmp_path: Path, cli_args, expected_projects
+):
+ """Test that repo sync -g selects only matching projects."""
+ manifest = _create_manifest_with_groups(tmp_path)
+ cmd = sync.Sync()
+ cmd.manifest = manifest
+
+ opts, args = cmd.OptionParser.parse_args(cli_args)
+ projects = cmd.GetProjects(args, groups=opts.groups, missing_ok=True)
+ project_names = sorted([p.name for p in projects])
+ assert project_names == sorted(expected_projects)
+
+
+def test_sync_update_projects_revision_id_respects_groups(tmp_path: Path):
+ """Test that _UpdateProjectsRevisionId filters projects using opt.groups."""
+ manifest = _create_manifest_with_groups(tmp_path)
+ cmd = sync.Sync()
+ cmd.manifest = manifest
+
+ superproject = mock.MagicMock()
+ superproject.UpdateProjectsRevisionId.return_value = mock.MagicMock(
+ manifest_path=None
+ )
+ manifest._superproject = superproject
+
+ opts, args = cmd.OptionParser.parse_args(["-g", "group1"])
+ opts.verbose = False
+ opts.fetch_submodules = False
+ opts.this_manifest_only = True
+ opts.local_only = False
+
+ with mock.patch.object(
+ cmd, "GetProjects", wraps=cmd.GetProjects
+ ) as spy_get_projects:
+ with mock.patch.object(cmd, "ManifestList", return_value=[manifest]):
+ cmd._UpdateProjectsRevisionId(opts, args, {}, manifest)
+ spy_get_projects.assert_called_once()
+ _, kwargs = spy_get_projects.call_args
+ assert kwargs.get("groups") == "group1"
+
+
# Used to patch os.cpu_count() for reliable results.
OS_CPU_COUNT = 24
@@ -832,6 +948,19 @@ class SyncCommand(unittest.TestCase):
self.assertIn(self.sync_local_half_error, e.aggregate_errors)
self.assertIn(self.sync_network_half_error, e.aggregate_errors)
+ def test_groups_passed_to_get_projects(self):
+ """Ensure Execute passes opt.groups to GetProjects."""
+ self.opt.groups = "my_group"
+ self.opt.mp_update = False
+ with mock.patch.object(self.cmd, "_UpdateRepoProject"):
+ with mock.patch.object(self.cmd, "_ValidateOptionsWithManifest"):
+ with mock.patch.object(self.cmd, "_SyncInterleaved"):
+ with mock.patch.object(self.cmd, "_RunPostSyncHook"):
+ self.cmd.Execute(self.opt, [])
+ self.cmd.GetProjects.assert_called()
+ _, kwargs = self.cmd.GetProjects.call_args
+ self.assertEqual(kwargs.get("groups"), "my_group")
+
class SyncUpdateRepoProject(unittest.TestCase):
"""Tests for Sync._UpdateRepoProject."""