summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Kelly <mkelly@arista.com>2021-06-30 01:58:28 -0700
committerMichael Kelly <mkelly@arista.com>2021-07-08 16:48:21 +0000
commit06da9987f6be6ddc1637e8ae02646d6dfab09862 (patch)
treebe93f68a568f27341b61fa367a42dcdfe75df234
parent58929732123780497ba08ed9c2d24f4bc65971a1 (diff)
downloadgit-repo-06da9987f6be6ddc1637e8ae02646d6dfab09862.tar.gz
Gracefully ignore bad remove-project line
Sometimes, we don't care if the remove project is referring to a non-existing project and we can just ignore it. This change allows us to ignore remove-project entries if the project that they refer to doesn't exist, making them effectively a no-op. Because this change breaks existing configuration, we allow this to be configuration controlled using the `optional` attribute in the remove-project tag. Change-Id: I6313a02983e81344eadcb4e47d7d6b037ee7420e Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/310964 Tested-by: Michael Kelly <mkelly@arista.com> Reviewed-by: Mike Frysinger <vapier@google.com>
-rw-r--r--docs/manifest-format.md4
-rw-r--r--manifest_xml.py20
-rw-r--r--tests/test_manifest_xml.py50
3 files changed, 64 insertions, 10 deletions
diff --git a/docs/manifest-format.md b/docs/manifest-format.md
index 45fd615e..c3bfcff0 100644
--- a/docs/manifest-format.md
+++ b/docs/manifest-format.md
@@ -96,6 +96,7 @@ following DTD:
96 96
97 <!ELEMENT remove-project EMPTY> 97 <!ELEMENT remove-project EMPTY>
98 <!ATTLIST remove-project name CDATA #REQUIRED> 98 <!ATTLIST remove-project name CDATA #REQUIRED>
99 <!ATTLIST remove-project optional CDATA #IMPLIED>
99 100
100 <!ELEMENT repo-hooks EMPTY> 101 <!ELEMENT repo-hooks EMPTY>
101 <!ATTLIST repo-hooks in-project CDATA #REQUIRED> 102 <!ATTLIST repo-hooks in-project CDATA #REQUIRED>
@@ -393,6 +394,9 @@ This element is mostly useful in a local manifest file, where
393the user can remove a project, and possibly replace it with their 394the user can remove a project, and possibly replace it with their
394own definition. 395own definition.
395 396
397Attribute `optional`: Set to true to ignore remove-project elements with no
398matching `project` element.
399
396### Element repo-hooks 400### Element repo-hooks
397 401
398NB: See the [practical documentation](./repo-hooks.md) for using repo hooks. 402NB: See the [practical documentation](./repo-hooks.md) for using repo hooks.
diff --git a/manifest_xml.py b/manifest_xml.py
index ab4be2f5..be74bf49 100644
--- a/manifest_xml.py
+++ b/manifest_xml.py
@@ -918,19 +918,19 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
918 if node.nodeName == 'remove-project': 918 if node.nodeName == 'remove-project':
919 name = self._reqatt(node, 'name') 919 name = self._reqatt(node, 'name')
920 920
921 if name not in self._projects: 921 if name in self._projects:
922 for p in self._projects[name]:
923 del self._paths[p.relpath]
924 del self._projects[name]
925
926 # If the manifest removes the hooks project, treat it as if it deleted
927 # the repo-hooks element too.
928 if self._repo_hooks_project and (self._repo_hooks_project.name == name):
929 self._repo_hooks_project = None
930 elif not XmlBool(node, 'optional', False):
922 raise ManifestParseError('remove-project element specifies non-existent ' 931 raise ManifestParseError('remove-project element specifies non-existent '
923 'project: %s' % name) 932 'project: %s' % name)
924 933
925 for p in self._projects[name]:
926 del self._paths[p.relpath]
927 del self._projects[name]
928
929 # If the manifest removes the hooks project, treat it as if it deleted
930 # the repo-hooks element too.
931 if self._repo_hooks_project and (self._repo_hooks_project.name == name):
932 self._repo_hooks_project = None
933
934 def _AddMetaProjectMirror(self, m): 934 def _AddMetaProjectMirror(self, m):
935 name = None 935 name = None
936 m_url = m.GetRemote(m.remote.name).url 936 m_url = m.GetRemote(m.remote.name).url
diff --git a/tests/test_manifest_xml.py b/tests/test_manifest_xml.py
index 55468b51..96ee4c4a 100644
--- a/tests/test_manifest_xml.py
+++ b/tests/test_manifest_xml.py
@@ -638,3 +638,53 @@ class RemoteElementTests(ManifestParseTestCase):
638 self.assertNotEqual(a, manifest_xml._Default()) 638 self.assertNotEqual(a, manifest_xml._Default())
639 self.assertNotEqual(a, 123) 639 self.assertNotEqual(a, 123)
640 self.assertNotEqual(a, None) 640 self.assertNotEqual(a, None)
641
642
643class RemoveProjectElementTests(ManifestParseTestCase):
644 """Tests for <remove-project>."""
645
646 def test_remove_one_project(self):
647 manifest = self.getXmlManifest("""
648<manifest>
649 <remote name="default-remote" fetch="http://localhost" />
650 <default remote="default-remote" revision="refs/heads/main" />
651 <project name="myproject" />
652 <remove-project name="myproject" />
653</manifest>
654""")
655 self.assertEqual(manifest.projects, [])
656
657 def test_remove_one_project_one_remains(self):
658 manifest = self.getXmlManifest("""
659<manifest>
660 <remote name="default-remote" fetch="http://localhost" />
661 <default remote="default-remote" revision="refs/heads/main" />
662 <project name="myproject" />
663 <project name="yourproject" />
664 <remove-project name="myproject" />
665</manifest>
666""")
667
668 self.assertEqual(len(manifest.projects), 1)
669 self.assertEqual(manifest.projects[0].name, 'yourproject')
670
671 def test_remove_one_project_doesnt_exist(self):
672 with self.assertRaises(manifest_xml.ManifestParseError):
673 manifest = self.getXmlManifest("""
674<manifest>
675 <remote name="default-remote" fetch="http://localhost" />
676 <default remote="default-remote" revision="refs/heads/main" />
677 <remove-project name="myproject" />
678</manifest>
679""")
680 manifest.projects
681
682 def test_remove_one_optional_project_doesnt_exist(self):
683 manifest = self.getXmlManifest("""
684<manifest>
685 <remote name="default-remote" fetch="http://localhost" />
686 <default remote="default-remote" revision="refs/heads/main" />
687 <remove-project name="myproject" optional="true" />
688</manifest>
689""")
690 self.assertEqual(manifest.projects, [])