gclient_scm: Fetch refs/changes/* when syncing.
When a git mirror is configured, it fetches only refs/heads/*,
and possibly branch-heads and tags, but not refs/changes.
When gclient attempts to sync refs/changes/* from a mirror,
it fails, since the mirror has no such objects.
See for example [1], where the DEPS entry for builtools was
modified to sync to a CL, but all the bots failed to sync to it.
This change modifies gclient to always fetch refs/changes/*
directly from the repo, even when a mirror is configured.
[1] https://chromium-review.googlesource.com/c/chromium/src/+/1119098/6
Bug: 858894
Change-Id: I71bb313e4325a81b2985db1d00c70a8844dc7c22
Reviewed-on: https://chromium-review.googlesource.com/1119525
Commit-Queue: Edward Lesmes <ehmaldonado@chromium.org>
Reviewed-by: Aaron Gable <agable@chromium.org>
diff --git a/tests/gclient_scm_test.py b/tests/gclient_scm_test.py
index 4742310..1abeb6f 100755
--- a/tests/gclient_scm_test.py
+++ b/tests/gclient_scm_test.py
@@ -21,6 +21,7 @@
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from testing_support import fake_repos
from testing_support.super_mox import mox, StdoutCheck, SuperMoxTestBase
from testing_support.super_mox import TestCaseUtils
@@ -989,6 +990,80 @@
scm.update(None, (), [])
+class GerritChangesFakeRepo(fake_repos.FakeReposBase):
+ def populateGit(self):
+ # Creates a tree that looks like this:
+ #
+ # 6 refs/changes/35/1235/1
+ # /
+ # 5 refs/changes/34/1234/1
+ # /
+ # 1--2--3--4 refs/heads/master
+
+
+ self._commit_git('repo_1', {'commit 1': 'touched'})
+ self._commit_git('repo_1', {'commit 2': 'touched'})
+ self._commit_git('repo_1', {'commit 3': 'touched'})
+ self._commit_git('repo_1', {'commit 4': 'touched'})
+ self._create_ref('repo_1', 'refs/heads/master', 4)
+
+ # Create a change on top of commit 3 that consists of two commits.
+ self._commit_git('repo_1',
+ {'commit 5': 'touched',
+ 'change': '1234'},
+ base=3)
+ self._create_ref('repo_1', 'refs/changes/34/1234/1', 5)
+ self._commit_git('repo_1',
+ {'commit 6': 'touched',
+ 'change': '1235'})
+ self._create_ref('repo_1', 'refs/changes/35/1235/1', 6)
+
+
+class GerritChangesTest(fake_repos.FakeReposTestBase):
+ FAKE_REPOS_CLASS = GerritChangesFakeRepo
+
+ def setUp(self):
+ super(GerritChangesTest, self).setUp()
+ self.enabled = self.FAKE_REPOS.set_up_git()
+ self.options = BaseGitWrapperTestCase.OptionsObject()
+ self.url = self.git_base + 'repo_1'
+ self.mirror = None
+
+ def setUpMirror(self):
+ self.mirror = tempfile.mkdtemp()
+ git_cache.Mirror.SetCachePath(self.mirror)
+ self.addCleanup(rmtree, self.mirror)
+ self.addCleanup(git_cache.Mirror.SetCachePath, None)
+
+ def testCanCloneGerritChange(self):
+ scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
+ file_list = []
+
+ self.options.revision = 'refs/changes/35/1235/1'
+ scm.update(self.options, None, file_list)
+ self.assertEqual(self.githash('repo_1', 6), self.gitrevparse(self.root_dir))
+
+ def testCanSyncToGerritChange(self):
+ scm = gclient_scm.GitWrapper(self.url, self.root_dir, '.')
+ file_list = []
+
+ self.options.revision = self.githash('repo_1', 1)
+ scm.update(self.options, None, file_list)
+ self.assertEqual(self.githash('repo_1', 1), self.gitrevparse(self.root_dir))
+
+ self.options.revision = 'refs/changes/35/1235/1'
+ scm.update(self.options, None, file_list)
+ self.assertEqual(self.githash('repo_1', 6), self.gitrevparse(self.root_dir))
+
+ def testCanCloneGerritChangeMirror(self):
+ self.setUpMirror()
+ self.testCanCloneGerritChange()
+
+ def testCanSyncToGerritChangeMirror(self):
+ self.setUpMirror()
+ self.testCanSyncToGerritChange()
+
+
if __name__ == '__main__':
level = logging.DEBUG if '-v' in sys.argv else logging.FATAL
logging.basicConfig(