pre-upload: assert virtuals use metapackage

This change adds a pre-upload hook to assert that virtual
packages are using "metapackage" license.

BUG=chromium:1034174
TEST=new unit test passes

Change-Id: I9f9237e73c8fb0d0e94944b6a9faa39d1b3e7bc9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/repohooks/+/2639019
Tested-by: Sergey Frolov <sfrolov@google.com>
Commit-Queue: Sergey Frolov <sfrolov@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Auto-Submit: Sergey Frolov <sfrolov@google.com>
diff --git a/pre-upload.py b/pre-upload.py
index 9555eae..224cd34 100755
--- a/pre-upload.py
+++ b/pre-upload.py
@@ -1272,10 +1272,6 @@
   LICENSES_IGNORE = ['||', '(', ')']
 
   for ebuild in touched_ebuilds:
-    # Skip virutal packages.
-    if ebuild.split('/')[-3] == 'virtual':
-      continue
-
     # e.g. path/to/overlay/category/package/package.ebuild -> path/to/overlay
     overlay_path = os.sep.join(ebuild.split(os.sep)[:-3])
 
@@ -1286,6 +1282,12 @@
     except ValueError as e:
       return HookFailure(str(e), [ebuild])
 
+    # Virtual packages must use "metapackage" license.
+    if ebuild.split('/')[-3] == 'virtual':
+      if license_types != ['metapackage']:
+        return HookFailure('Virtual package must use LICENSE="metapackage".',
+                           [ebuild])
+
     # Also ignore licenses ending with '?'
     for license_type in [x for x in license_types
                          if x not in LICENSES_IGNORE and not x.endswith('?')]:
diff --git a/pre-upload_unittest.py b/pre-upload_unittest.py
index 0ddbbb1..769d578 100755
--- a/pre-upload_unittest.py
+++ b/pre-upload_unittest.py
@@ -801,6 +801,69 @@
     self._CheckContent(u'# HEADER\nKEYWORDS="~arm x86"\nblah\n', True)
 
 
+class CheckEbuildLicense(PreUploadTestCase):
+  """Tests for _check_ebuild_licenses."""
+
+  def setUp(self):
+    self.file_mock = self.PatchObject(pre_upload, '_get_affected_files')
+    self.content_mock = self.PatchObject(pre_upload, '_get_file_content')
+
+  def testNoEbuilds(self):
+    """If no ebuilds are found, do not scan."""
+    self.file_mock.return_value = ['a.file', 'ebuild-is-not.foo']
+
+    ret = pre_upload._check_ebuild_licenses(ProjectNamed('overlay'), 'HEAD')
+    self.assertIsNone(ret)
+
+    self.assertEqual(self.content_mock.call_count, 0)
+
+  def testSomeEbuilds(self):
+    """If ebuilds are found, only scan them."""
+    self.file_mock.return_value = ['a.file', 'blah', 'cow',
+                                   'overlay/category/pkg/pkg.ebuild']
+    self.content_mock.return_value = '# HEADER\nLICENSE="GPL-3"\nblah\n'
+
+    ret = pre_upload._check_ebuild_licenses(ProjectNamed('overlay'), 'HEAD')
+    self.assertIsNone(ret)
+
+    self.assertEqual(self.content_mock.call_count, 1)
+
+  def _CheckContent(self, license_field, ebuild_path, fails):
+    """Test helper for inputs/outputs.
+
+    Args:
+      license_field: Contents of LICENSE variable in the tested ebuild.
+      ebuild_path: The path to the tested ebuild.
+      fails: Whether inputs should trigger a hook failure.
+    """
+    self.file_mock.return_value = [ebuild_path]
+    self.content_mock.return_value = f'# blah\nLICENSE="{license_field}"\nbla\n'
+
+    ret = pre_upload._check_ebuild_licenses(ProjectNamed('overlay'), 'HEAD')
+    if fails:
+      self.assertIsInstance(ret, errors.HookFailure)
+    else:
+      self.assertIsNone(ret)
+
+    self.assertEqual(self.content_mock.call_count, 1)
+
+  def testEmpty(self):
+    """Check empty license is not accepted."""
+    self._CheckContent('', 'overlay/category/pkg/pkg.ebuild', True)
+
+  def testValid(self):
+    """Check valid license is accepted."""
+    self._CheckContent('GPL-3', 'overlay/category/pkg/pkg.ebuild', False)
+
+  def testVirtualNotMetapackage(self):
+    """Check virtual package not using metapackage is not accepted."""
+    self._CheckContent('GPL-3', 'overlay/virtual/pkg/pkg.ebuild', True)
+
+  def testVirtualMetapackage(self):
+    """Check virtual package using metapackage is accepted."""
+    self._CheckContent('metapackage', 'overlay/virtual/pkg/pkg.ebuild', False)
+
+
 class CheckEbuildOwners(PreUploadTestCase):
   """Tests for _check_ebuild_owners."""