Add policy check on global-requirements.txt entries

We want to ensure that every entry in global-requirements has
at least a minimum version specified, and if there is an exclude,
the exclude is not outside the lower bounds.

Change-Id: Ie12d99d3317bd4c81de9a47a43fa99345b2b9664
This commit is contained in:
Dirk Mueller 2017-09-11 15:46:34 -06:00 committed by Tony Breeds
parent ee1a3433f1
commit 4153903939
3 changed files with 64 additions and 0 deletions

View File

@ -61,6 +61,12 @@ def main():
print(msg) print(msg)
error_count += 1 error_count += 1
# Check requirements to satisfy policy.
print('\nChecking requirements on %s' % args.global_requirements)
for msg in requirement.check_reqs_bounds_policy(global_reqs):
print(msg)
error_count += 1
# Check that all of the items in the global-requirements list # Check that all of the items in the global-requirements list
# appear in exactly one of the constraints file or the blacklist. # appear in exactly one of the constraints file or the blacklist.
print('\nChecking %s' % args.blacklist) print('\nChecking %s' % args.blacklist)

View File

@ -203,3 +203,36 @@ def to_reqs(content, permit_urls=False):
yield None, content_line yield None, content_line
else: else:
yield parse_line(req_line, permit_urls=permit_urls), content_line yield parse_line(req_line, permit_urls=permit_urls), content_line
def check_reqs_bounds_policy(global_reqs):
"""Check that the global requirement version specifiers match the policy.
The policy is defined as
* There needs to be exactly one lower bound (>=1.2 defined)
* There can be one or more excludes (!=1.2.1, !=1.2.2)
* TODO: Clarify (non-) existance of upper caps
"""
for pkg_requirement in global_reqs.values():
req = pkg_requirement[0][0]
if req.package:
_specifiers = packaging.specifiers.SpecifierSet(req.specifiers)
lower_bound = set()
for spec in _specifiers:
if spec.operator == '>=':
lower_bound.add(spec)
if len(lower_bound) < 1:
yield ('Requirement %s needs a >= specifier' % req.package)
elif len(lower_bound) > 1:
yield ('Requirement %s has multiple >= specifier' %
req.package)
else:
lower_bound = lower_bound.pop()
for spec in _specifiers:
if spec.operator == '!=':
if not lower_bound.contains(spec.version):
yield('Requirement %s has a !=%s specifier '
'that is not >=%s' % (req.package,
spec.version,
lower_bound.version))

View File

@ -194,3 +194,28 @@ class TestToDict(testtools.TestCase):
req = requirement.Requirement('Foo_bar', '', '', '', '') req = requirement.Requirement('Foo_bar', '', '', '', '')
self.assertEqual( self.assertEqual(
{'foo-bar': [(req, '')]}, requirement.to_dict([(req, '')])) {'foo-bar': [(req, '')]}, requirement.to_dict([(req, '')]))
class TestReqPolicy(testtools.TestCase):
def test_requirements_policy_pass(self):
content = textwrap.dedent("""\
cffi>=1.1.1,!=1.1.2
other>=1.1.1
""")
reqs = requirement.parse(content)
policy_check = [x for x in requirement.check_reqs_bounds_policy(reqs)]
self.assertEqual(len(policy_check), 0)
def test_requirements_policy_fail(self):
content = textwrap.dedent("""\
cffi>=1.1.1,!=1.1.0
other>=1,>=2,!=1.1.0
no_lower_bound
""")
reqs = requirement.parse(content)
self.assertEqual([
'Requirement cffi has a !=1.1.0 specifier that is not >=1.1.1',
'Requirement no-lower-bound needs a >= specifier',
'Requirement other has multiple >= specifier'],
sorted([x for x in requirement.check_reqs_bounds_policy(reqs)]))