Prevent incompatible version bumps.
We shouldn't be able to bump global requirement versions if that would be incompatible with the current test set of versions. To assess 'works' we need to run them in tests which means that we need to update upper-constraints.txt at the same time. We don't test all versions however, so just checking that the constraints version is compatible with the updated global requirements is sufficient. This adds a dependency on the pypa packaging library. The library is maintained by the authors of setuptools and pip, is Apache V2, in good condition and Python 3 ready. Its a test-only dependency so I don't think the distro packaging status matters. This is *the* reference library for packaging facilities on Python. Change-Id: I032dd9a384453dcfa4911ea905c8f89b0c974211
This commit is contained in:
parent
5e4ca1b8b8
commit
24fe404d97
@ -53,6 +53,7 @@ jsonrpclib
|
||||
jsonschema>=2.0.0,<3.0.0,!=2.5.0
|
||||
kazoo>=2.2
|
||||
keystonemiddleware>=1.5.0
|
||||
packaging>=15.2
|
||||
pyScss>=1.3.4 # MIT License
|
||||
django-pyscss>=2.0.2 # BSD License (2 clause)
|
||||
kombu>=3.0.7
|
||||
|
75
openstack_requirements/tests/test_integration.py
Normal file
75
openstack_requirements/tests/test_integration.py
Normal file
@ -0,0 +1,75 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from packaging import specifiers
|
||||
import testtools
|
||||
|
||||
from openstack_requirements import update
|
||||
|
||||
|
||||
def check_compatible(global_reqs, constraints):
|
||||
"""Check compatibility between requirements and constraints.
|
||||
|
||||
A change to global-requirements that wants to make changes
|
||||
incompatible with the current frozen constraints needs to also raise
|
||||
those constraints.
|
||||
Load global-requirements
|
||||
Load upper-constraints.txt
|
||||
Check that every version within upper-constraints.txt is either
|
||||
A) Missing from global-requirements - its a transitive dep or
|
||||
a removed dep.
|
||||
B) Compatible with any of the versions in global-requirements.
|
||||
This is not-quite right, because we should in principle match
|
||||
markers, but that requires evaluating the markers which we
|
||||
haven't yet implemented. Being compatible with one of the
|
||||
requirements is good enough proxy to catch most cases.
|
||||
|
||||
:param global_reqs: A set of global requirements after parsing.
|
||||
:param constraints: The same from upper-constraints.txt.
|
||||
:return: A list of the parsed package tuples that failed.
|
||||
"""
|
||||
failures = []
|
||||
|
||||
def satisfied(reqs, name, version):
|
||||
if name not in reqs:
|
||||
return True
|
||||
for pkg in global_reqs.values():
|
||||
for constraint, _ in pkg:
|
||||
spec = specifiers.SpecifierSet(constraint.specifiers)
|
||||
if spec.contains(version):
|
||||
return True
|
||||
return False
|
||||
for pkg_constraints in constraints.values():
|
||||
for constraint, _ in pkg_constraints:
|
||||
name = constraint.package
|
||||
version = constraint.specifiers[3:]
|
||||
if not satisfied(global_reqs, name, version):
|
||||
failures.append(constraint)
|
||||
return failures
|
||||
|
||||
|
||||
class TestRequirements(testtools.TestCase):
|
||||
|
||||
def test_constraints_compatible(self):
|
||||
global_req_content = open('global-requirements.txt', 'rt').read()
|
||||
constraints_content = open('upper-constraints.txt', 'rt').read()
|
||||
global_reqs = update._parse_reqs(global_req_content)
|
||||
constraints = update._parse_reqs(constraints_content)
|
||||
self.assertEqual([], check_compatible(global_reqs, constraints))
|
||||
|
||||
def test_check_compatible(self):
|
||||
global_reqs = update._parse_reqs("foo>=1.2\n")
|
||||
good_constraints = update._parse_reqs("foo===1.2.5\n")
|
||||
bad_constraints = update._parse_reqs("foo===1.1.2\n")
|
||||
self.assertEqual([], check_compatible(global_reqs, good_constraints))
|
||||
self.assertNotEqual(
|
||||
[], check_compatible(global_reqs, bad_constraints))
|
@ -4,6 +4,7 @@
|
||||
# NOTE: These are requirements for testing the requirements project only
|
||||
# See global-requirements for the actual requirements list
|
||||
hacking<0.11,>=0.10
|
||||
packaging
|
||||
testrepository>=0.0.18
|
||||
testscenarios>=0.4
|
||||
testtools>=1.4.0
|
||||
|
Loading…
x
Reference in New Issue
Block a user