check PV of virtual ebuilds
We want people to follow the guidelines for the right PV value to use
when creating virtuals that boards will be able to override.
BUG=chromium:340036
TEST=`./pre-upload_unittest.py` passes
TEST=uploaded a few CLs with bad PVs & good PVs and checked behavior
Change-Id: Ie514a6b316465939498593c22fb7ca5f74972f01
Reviewed-on: https://chromium-review.googlesource.com/184623
Reviewed-by: David James <davidjames@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
diff --git a/pre-upload.py b/pre-upload.py
index 0cc52f1..6f38310 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -617,6 +617,64 @@
return HookFailure(e.message, [ebuild])
+def _check_ebuild_virtual_pv(project, commit):
+ """Enforce the virtual PV policies."""
+ # If this is the portage-stable overlay, then ignore the check.
+ # We want to import virtuals as-is from upstream Gentoo.
+ whitelist = (
+ 'chromiumos/overlays/portage-stable',
+ )
+ if project in whitelist:
+ return None
+
+ # We assume the repo name is the same as the dir name on disk.
+ # It would be dumb to not have them match though.
+ project = os.path.basename(project)
+
+ is_variant = lambda x: x.startswith('overlay-variant-')
+ is_board = lambda x: x.startswith('overlay-')
+ is_private = lambda x: x.endswith('-private')
+
+ get_pv = re.compile(r'(.*?)virtual/([^/]+)/\2-([^/]*)\.ebuild$')
+
+ ebuilds_re = [r'\.ebuild$']
+ ebuilds = _filter_files(_get_affected_files(commit, relative=True),
+ ebuilds_re)
+ bad_ebuilds = []
+
+ for ebuild in ebuilds:
+ m = get_pv.match(ebuild)
+ if m:
+ overlay = m.group(1)
+ if not overlay or not is_board(overlay):
+ overlay = project
+
+ pv = m.group(3).split('-', 1)[0]
+
+ if is_private(overlay):
+ want_pv = '3.5' if is_variant(overlay) else '3'
+ elif is_board(overlay):
+ want_pv = '2.5' if is_variant(overlay) else '2'
+ else:
+ want_pv = '1'
+
+ if pv != want_pv:
+ bad_ebuilds.append((ebuild, pv, want_pv))
+
+ if bad_ebuilds:
+ # pylint: disable=C0301
+ url = 'http://dev.chromium.org/chromium-os/how-tos-and-troubleshooting/portage-build-faq#TOC-Virtuals-and-central-management'
+ # pylint: enable=C0301
+ return HookFailure(
+ 'These virtuals have incorrect package versions (PVs). Please adjust:\n'
+ '\t%s\n'
+ 'If this is an upstream Gentoo virtual, then you may ignore this\n'
+ 'check (and re-run w/--no-verify). Otherwise, please see this\n'
+ 'page for more details:\n%s\n' %
+ ('\n\t'.join(['%s:\n\t\tPV is %s but should be %s' % x
+ for x in bad_ebuilds]), url))
+
+
def _check_change_has_proper_changeid(_project, commit):
"""Verify that Change-ID is present in last paragraph of commit message."""
desc = _get_commit_desc(commit)
@@ -779,6 +837,7 @@
_check_change_has_proper_changeid,
_check_ebuild_eapi,
_check_ebuild_licenses,
+ _check_ebuild_virtual_pv,
_check_no_stray_whitespace,
_check_no_long_lines,
_check_license,
diff --git a/pre-upload_unittest.py b/pre-upload_unittest.py
index 57633e6..8120c69 100755
--- a/pre-upload_unittest.py
+++ b/pre-upload_unittest.py
@@ -207,5 +207,80 @@
self.assertEqual(ret, None)
+class CheckEbuildVirtualPv(cros_test_lib.MockTestCase):
+ """Tests for _check_ebuild_virtual_pv."""
+
+ PORTAGE_STABLE = 'chromiumos/overlays/portage-stable'
+ CHROMIUMOS_OVERLAY = 'chromiumos/overlays/chromiumos'
+ BOARD_OVERLAY = 'chromiumos/overlays/board-overlays'
+ PRIVATE_OVERLAY = 'chromeos/overlays/overlay-link-private'
+ PRIVATE_VARIANT_OVERLAY = ('chromeos/overlays/'
+ 'overlay-variant-daisy-spring-private')
+
+ def setUp(self):
+ self.file_mock = self.PatchObject(pre_upload, '_get_affected_files')
+
+ def testNoVirtuals(self):
+ """Skip non virtual packages."""
+ self.file_mock.return_value = ['some/package/package-3.ebuild']
+ ret = pre_upload._check_ebuild_virtual_pv('overlay', 'H')
+ self.assertEqual(ret, None)
+
+ def testCommonVirtuals(self):
+ """Non-board overlays should use PV=1."""
+ template = 'virtual/foo/foo-%s.ebuild'
+ self.file_mock.return_value = [template % '1']
+ ret = pre_upload._check_ebuild_virtual_pv(self.CHROMIUMOS_OVERLAY, 'H')
+ self.assertEqual(ret, None)
+
+ self.file_mock.return_value = [template % '2']
+ ret = pre_upload._check_ebuild_virtual_pv(self.CHROMIUMOS_OVERLAY, 'H')
+ self.assertTrue(isinstance (ret, errors.HookFailure))
+
+ def testPublicBoardVirtuals(self):
+ """Public board overlays should use PV=2."""
+ template = 'overlay-lumpy/virtual/foo/foo-%s.ebuild'
+ self.file_mock.return_value = [template % '2']
+ ret = pre_upload._check_ebuild_virtual_pv(self.BOARD_OVERLAY, 'H')
+ self.assertEqual(ret, None)
+
+ self.file_mock.return_value = [template % '2.5']
+ ret = pre_upload._check_ebuild_virtual_pv(self.BOARD_OVERLAY, 'H')
+ self.assertTrue(isinstance (ret, errors.HookFailure))
+
+ def testPublicBoardVariantVirtuals(self):
+ """Public board variant overlays should use PV=2.5."""
+ template = 'overlay-variant-lumpy-foo/virtual/foo/foo-%s.ebuild'
+ self.file_mock.return_value = [template % '2.5']
+ ret = pre_upload._check_ebuild_virtual_pv(self.BOARD_OVERLAY, 'H')
+ self.assertEqual(ret, None)
+
+ self.file_mock.return_value = [template % '3']
+ ret = pre_upload._check_ebuild_virtual_pv(self.BOARD_OVERLAY, 'H')
+ self.assertTrue(isinstance (ret, errors.HookFailure))
+
+ def testPrivateBoardVirtuals(self):
+ """Private board overlays should use PV=3."""
+ template = 'virtual/foo/foo-%s.ebuild'
+ self.file_mock.return_value = [template % '3']
+ ret = pre_upload._check_ebuild_virtual_pv(self.PRIVATE_OVERLAY, 'H')
+ self.assertEqual(ret, None)
+
+ self.file_mock.return_value = [template % '3.5']
+ ret = pre_upload._check_ebuild_virtual_pv(self.PRIVATE_OVERLAY, 'H')
+ self.assertTrue(isinstance (ret, errors.HookFailure))
+
+ def testPrivateBoardVariantVirtuals(self):
+ """Private board variant overlays should use PV=3.5."""
+ template = 'virtual/foo/foo-%s.ebuild'
+ self.file_mock.return_value = [template % '3.5']
+ ret = pre_upload._check_ebuild_virtual_pv(self.PRIVATE_VARIANT_OVERLAY, 'H')
+ self.assertEqual(ret, None)
+
+ self.file_mock.return_value = [template % '4']
+ ret = pre_upload._check_ebuild_virtual_pv(self.PRIVATE_VARIANT_OVERLAY, 'H')
+ self.assertTrue(isinstance (ret, errors.HookFailure))
+
+
if __name__ == '__main__':
cros_test_lib.main()