summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2021-09-26 23:20:32 -0700
committerXin Li <delphij@google.com>2021-09-27 06:36:05 +0000
commite0b16a22a01c54a00a9e4a0c53dddfce3b0d59d6 (patch)
tree7759c55cdbe045de3974be17bc3a5557d42619db
parentd669d2dee5bd7986593d5df1dd8a736778501bbf (diff)
downloadgit-repo-e0b16a22a01c54a00a9e4a0c53dddfce3b0d59d6.tar.gz
superproject: support a new revision attribute.
Tested: $ ./run_tests Verified that a manifest that specified superproject revision would use the specified revision, and superproject will use the default revision. Note that this is a slight behavior change from earlier repo versions, which would always use the branch name of the manifest itself. However, the new behavior would be more consisitent with regular "project" element and would allow superproject be used even if it is not enabled for the particular manifest branch, so we have decided to make the change as it would provide more flexibility and better matches what other elements would do. Bug: [google internal] b/187868160 Change-Id: I35255ee347aff6e65179f7879d52931f168b477e Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/317643 Tested-by: Xin Li <delphij@google.com> Reviewed-by: Raman Tenneti <rtenneti@google.com> Reviewed-by: Mike Frysinger <vapier@google.com>
-rw-r--r--docs/manifest-format.md10
-rw-r--r--git_superproject.py14
-rw-r--r--manifest_xml.py10
-rw-r--r--tests/test_git_superproject.py2
-rw-r--r--tests/test_manifest_xml.py69
5 files changed, 90 insertions, 15 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md
index 854e5e1b..ed297ae7 100644
--- a/docs/manifest-format.md
+++ b/docs/manifest-format.md
@@ -103,8 +103,9 @@ following DTD:
103 <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED> 103 <!ATTLIST repo-hooks enabled-list CDATA #REQUIRED>
104 104
105 <!ELEMENT superproject EMPTY> 105 <!ELEMENT superproject EMPTY>
106 <!ATTLIST superproject name CDATA #REQUIRED> 106 <!ATTLIST superproject name CDATA #REQUIRED>
107 <!ATTLIST superproject remote IDREF #IMPLIED> 107 <!ATTLIST superproject remote IDREF #IMPLIED>
108 <!ATTLIST superproject revision CDATA #IMPLIED>
108 109
109 <!ELEMENT contactinfo EMPTY> 110 <!ELEMENT contactinfo EMPTY>
110 <!ATTLIST contactinfo bugurl CDATA #REQUIRED> 111 <!ATTLIST contactinfo bugurl CDATA #REQUIRED>
@@ -432,6 +433,11 @@ same meaning as project's name attribute. See the
432Attribute `remote`: Name of a previously defined remote element. 433Attribute `remote`: Name of a previously defined remote element.
433If not supplied the remote given by the default element is used. 434If not supplied the remote given by the default element is used.
434 435
436Attribute `revision`: Name of the Git branch the manifest wants
437to track for this superproject. If not supplied the revision given
438by the remote element is used if applicable, else the default
439element is used.
440
435### Element contactinfo 441### Element contactinfo
436 442
437*** 443***
diff --git a/git_superproject.py b/git_superproject.py
index 935e1250..ce68690f 100644
--- a/git_superproject.py
+++ b/git_superproject.py
@@ -90,7 +90,7 @@ class Superproject(object):
90 self._git_event_log = git_event_log 90 self._git_event_log = git_event_log
91 self._quiet = quiet 91 self._quiet = quiet
92 self._print_messages = print_messages 92 self._print_messages = print_messages
93 self._branch = self._GetBranch() 93 self._branch = manifest.branch
94 self._repodir = os.path.abspath(repodir) 94 self._repodir = os.path.abspath(repodir)
95 self._superproject_dir = superproject_dir 95 self._superproject_dir = superproject_dir
96 self._superproject_path = os.path.join(self._repodir, superproject_dir) 96 self._superproject_path = os.path.join(self._repodir, superproject_dir)
@@ -100,6 +100,7 @@ class Superproject(object):
100 if self._manifest.superproject: 100 if self._manifest.superproject:
101 remote = self._manifest.superproject['remote'] 101 remote = self._manifest.superproject['remote']
102 git_name = hashlib.md5(remote.name.encode('utf8')).hexdigest() + '-' 102 git_name = hashlib.md5(remote.name.encode('utf8')).hexdigest() + '-'
103 self._branch = self._manifest.superproject['revision']
103 self._remote_url = remote.url 104 self._remote_url = remote.url
104 else: 105 else:
105 self._remote_url = None 106 self._remote_url = None
@@ -116,17 +117,6 @@ class Superproject(object):
116 """Returns the manifest path if the path exists or None.""" 117 """Returns the manifest path if the path exists or None."""
117 return self._manifest_path if os.path.exists(self._manifest_path) else None 118 return self._manifest_path if os.path.exists(self._manifest_path) else None
118 119
119 def _GetBranch(self):
120 """Returns the branch name for getting the approved manifest."""
121 p = self._manifest.manifestProject
122 b = p.GetBranch(p.CurrentBranch)
123 if not b:
124 return None
125 branch = b.merge
126 if branch and branch.startswith(R_HEADS):
127 branch = branch[len(R_HEADS):]
128 return branch
129
130 def _LogMessage(self, message): 120 def _LogMessage(self, message):
131 """Logs message to stderr and _git_event_log.""" 121 """Logs message to stderr and _git_event_log."""
132 if self._print_messages: 122 if self._print_messages:
diff --git a/manifest_xml.py b/manifest_xml.py
index 7099d5fe..135c91fb 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -507,6 +507,9 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
507 if not d.remote or remote.orig_name != remoteName: 507 if not d.remote or remote.orig_name != remoteName:
508 remoteName = remote.orig_name 508 remoteName = remote.orig_name
509 e.setAttribute('remote', remoteName) 509 e.setAttribute('remote', remoteName)
510 revision = remote.revision or d.revisionExpr
511 if not revision or revision != self._superproject['revision']:
512 e.setAttribute('revision', self._superproject['revision'])
510 root.appendChild(e) 513 root.appendChild(e)
511 514
512 if self._contactinfo.bugurl != Wrapper().BUG_URL: 515 if self._contactinfo.bugurl != Wrapper().BUG_URL:
@@ -914,6 +917,13 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
914 raise ManifestParseError("no remote for superproject %s within %s" % 917 raise ManifestParseError("no remote for superproject %s within %s" %
915 (name, self.manifestFile)) 918 (name, self.manifestFile))
916 self._superproject['remote'] = remote.ToRemoteSpec(name) 919 self._superproject['remote'] = remote.ToRemoteSpec(name)
920 revision = node.getAttribute('revision') or remote.revision
921 if not revision:
922 revision = self._default.revisionExpr
923 if not revision:
924 raise ManifestParseError('no revision for superproject %s within %s' %
925 (name, self.manifestFile))
926 self._superproject['revision'] = revision
917 if node.nodeName == 'contactinfo': 927 if node.nodeName == 'contactinfo':
918 bugurl = self._reqatt(node, 'bugurl') 928 bugurl = self._reqatt(node, 'bugurl')
919 # This element can be repeated, later entries will clobber earlier ones. 929 # This element can be repeated, later entries will clobber earlier ones.
diff --git a/tests/test_git_superproject.py b/tests/test_git_superproject.py
index e9b824d6..a24fc7f0 100644
--- a/tests/test_git_superproject.py
+++ b/tests/test_git_superproject.py
@@ -157,7 +157,7 @@ class SuperprojectTestCase(unittest.TestCase):
157""") 157""")
158 self._superproject = git_superproject.Superproject(manifest, self.repodir, 158 self._superproject = git_superproject.Superproject(manifest, self.repodir,
159 self.git_event_log) 159 self.git_event_log)
160 with mock.patch.object(self._superproject, '_GetBranch', return_value='junk'): 160 with mock.patch.object(self._superproject, '_branch', 'junk'):
161 sync_result = self._superproject.Sync() 161 sync_result = self._superproject.Sync()
162 self.assertFalse(sync_result.success) 162 self.assertFalse(sync_result.success)
163 self.assertTrue(sync_result.fatal) 163 self.assertTrue(sync_result.fatal)
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index 20459d1d..ce422536 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -572,6 +572,7 @@ class SuperProjectElementTests(ManifestParseTestCase):
572 self.assertEqual(manifest.superproject['name'], 'superproject') 572 self.assertEqual(manifest.superproject['name'], 'superproject')
573 self.assertEqual(manifest.superproject['remote'].name, 'test-remote') 573 self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
574 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject') 574 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
575 self.assertEqual(manifest.superproject['revision'], 'refs/heads/main')
575 self.assertEqual( 576 self.assertEqual(
576 sort_attributes(manifest.ToXml().toxml()), 577 sort_attributes(manifest.ToXml().toxml()),
577 '<?xml version="1.0" ?><manifest>' 578 '<?xml version="1.0" ?><manifest>'
@@ -580,6 +581,72 @@ class SuperProjectElementTests(ManifestParseTestCase):
580 '<superproject name="superproject"/>' 581 '<superproject name="superproject"/>'
581 '</manifest>') 582 '</manifest>')
582 583
584 def test_superproject_revision(self):
585 """Check superproject settings with a different revision attribute"""
586 self.maxDiff = None
587 manifest = self.getXmlManifest("""
588<manifest>
589 <remote name="test-remote" fetch="http://localhost" />
590 <default remote="test-remote" revision="refs/heads/main" />
591 <superproject name="superproject" revision="refs/heads/stable" />
592</manifest>
593""")
594 self.assertEqual(manifest.superproject['name'], 'superproject')
595 self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
596 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
597 self.assertEqual(manifest.superproject['revision'], 'refs/heads/stable')
598 self.assertEqual(
599 sort_attributes(manifest.ToXml().toxml()),
600 '<?xml version="1.0" ?><manifest>'
601 '<remote fetch="http://localhost" name="test-remote"/>'
602 '<default remote="test-remote" revision="refs/heads/main"/>'
603 '<superproject name="superproject" revision="refs/heads/stable"/>'
604 '</manifest>')
605
606 def test_superproject_revision_default_negative(self):
607 """Check superproject settings with a same revision attribute"""
608 self.maxDiff = None
609 manifest = self.getXmlManifest("""
610<manifest>
611 <remote name="test-remote" fetch="http://localhost" />
612 <default remote="test-remote" revision="refs/heads/stable" />
613 <superproject name="superproject" revision="refs/heads/stable" />
614</manifest>
615""")
616 self.assertEqual(manifest.superproject['name'], 'superproject')
617 self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
618 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
619 self.assertEqual(manifest.superproject['revision'], 'refs/heads/stable')
620 self.assertEqual(
621 sort_attributes(manifest.ToXml().toxml()),
622 '<?xml version="1.0" ?><manifest>'
623 '<remote fetch="http://localhost" name="test-remote"/>'
624 '<default remote="test-remote" revision="refs/heads/stable"/>'
625 '<superproject name="superproject"/>'
626 '</manifest>')
627
628 def test_superproject_revision_remote(self):
629 """Check superproject settings with a same revision attribute"""
630 self.maxDiff = None
631 manifest = self.getXmlManifest("""
632<manifest>
633 <remote name="test-remote" fetch="http://localhost" revision="refs/heads/main" />
634 <default remote="test-remote" />
635 <superproject name="superproject" revision="refs/heads/stable" />
636</manifest>
637""")
638 self.assertEqual(manifest.superproject['name'], 'superproject')
639 self.assertEqual(manifest.superproject['remote'].name, 'test-remote')
640 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/superproject')
641 self.assertEqual(manifest.superproject['revision'], 'refs/heads/stable')
642 self.assertEqual(
643 sort_attributes(manifest.ToXml().toxml()),
644 '<?xml version="1.0" ?><manifest>'
645 '<remote fetch="http://localhost" name="test-remote" revision="refs/heads/main"/>'
646 '<default remote="test-remote"/>'
647 '<superproject name="superproject" revision="refs/heads/stable"/>'
648 '</manifest>')
649
583 def test_remote(self): 650 def test_remote(self):
584 """Check superproject settings with a remote.""" 651 """Check superproject settings with a remote."""
585 manifest = self.getXmlManifest(""" 652 manifest = self.getXmlManifest("""
@@ -593,6 +660,7 @@ class SuperProjectElementTests(ManifestParseTestCase):
593 self.assertEqual(manifest.superproject['name'], 'platform/superproject') 660 self.assertEqual(manifest.superproject['name'], 'platform/superproject')
594 self.assertEqual(manifest.superproject['remote'].name, 'superproject-remote') 661 self.assertEqual(manifest.superproject['remote'].name, 'superproject-remote')
595 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/platform/superproject') 662 self.assertEqual(manifest.superproject['remote'].url, 'http://localhost/platform/superproject')
663 self.assertEqual(manifest.superproject['revision'], 'refs/heads/main')
596 self.assertEqual( 664 self.assertEqual(
597 sort_attributes(manifest.ToXml().toxml()), 665 sort_attributes(manifest.ToXml().toxml()),
598 '<?xml version="1.0" ?><manifest>' 666 '<?xml version="1.0" ?><manifest>'
@@ -613,6 +681,7 @@ class SuperProjectElementTests(ManifestParseTestCase):
613""") 681""")
614 self.assertEqual(manifest.superproject['name'], 'superproject') 682 self.assertEqual(manifest.superproject['name'], 'superproject')
615 self.assertEqual(manifest.superproject['remote'].name, 'default-remote') 683 self.assertEqual(manifest.superproject['remote'].name, 'default-remote')
684 self.assertEqual(manifest.superproject['revision'], 'refs/heads/main')
616 self.assertEqual( 685 self.assertEqual(
617 sort_attributes(manifest.ToXml().toxml()), 686 sort_attributes(manifest.ToXml().toxml()),
618 '<?xml version="1.0" ?><manifest>' 687 '<?xml version="1.0" ?><manifest>'