Create check_constraints command

The check_constraints utility wraps a new check_exists cmd.
This command looks at a project's requirements and checks:

  - That the requirement name alone exists in both g-r and u-c
  - If it exists in both, then check that the version in u-c
    is covered.
  - Added an extra g-r check as a flag, but not quite happy with it.
    It needs more work.. but would be a _little_ more correct
    if/when g-r stops defining the minimum.

This patch is currently WIP as tests are still required. But is
the starting point for the fuzzy checking for projects managing
their own lower-constraints.

Change-Id: I36690fddcfc24d49aab0d28d7d46dcd8d9128b2a
This commit is contained in:
Matthew Oliver 2017-03-13 16:02:59 +11:00 committed by Matthew Thode
parent 9eb6e51f98
commit 302ba18d81
No known key found for this signature in database
GPG Key ID: 64A37BEAAE19A4E8
9 changed files with 846 additions and 13 deletions

View File

@ -0,0 +1,113 @@
# 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.
"""Check to see if a package from a project's requrements file exist in g-r or
u-c.
"""
from __future__ import print_function
import argparse
from packaging.specifiers import SpecifierSet
from packaging.version import Version
from openstack_requirements import project
from openstack_requirements import requirement
def read_requirements_file(filename):
with open(filename, 'rt') as f:
body = f.read()
return requirement.parse(body)
def main(args=None):
parser = argparse.ArgumentParser()
parser.add_argument(
'project',
default='',
help='path to the project source root folder.')
parser.add_argument(
'-u', '--upper-constraints',
default='upper-constraints.txt',
help='path to the upper-constraints.txt file')
parser.add_argument(
'-g', '--global-requirements',
default='global-requirements.txt',
help='Path to the global-requirements.txt file')
parser.add_argument(
'-b', '--blacklist',
default='blacklist.txt',
help='Path to the blacklist.txt file')
parser.add_argument(
'-G', '--gr-check', action='store_true',
help='Do a specifier check of global-requirements')
args = parser.parse_args(args)
upper_constraints = read_requirements_file(args.upper_constraints)
global_requirements = read_requirements_file(args.global_requirements)
blacklist = read_requirements_file(args.blacklist)
project_data = project.read(args.project)
error_count = 0
for require_file, data in project_data.get('requirements', {}).items():
print(u'\nComparing %s with global-requirements and upper-constraints'
% require_file)
requirements = requirement.parse(data)
for name, spec_list in requirements.items():
if not name or name in blacklist:
continue
if name not in global_requirements:
print(u'%s from %s not found in global-requirements' % (
name, require_file))
error_count += 1
continue
if name not in upper_constraints:
print(u'%s from %s not found in upper-constraints' % (
name, require_file))
error_count += 1
continue
elif spec_list:
uc = upper_constraints[name][0][0]
gr = global_requirements[name][0][0]
spec_gr = SpecifierSet(gr.specifiers)
for req, _ in spec_list:
specs = SpecifierSet(req.specifiers)
# This assumes uc will only have == specifiers
for uc_spec in SpecifierSet(uc.specifiers):
# if the uc version isn't in the lower specifier
# then something is wrong.
if Version(uc_spec.version) not in specs:
print(
u'%s must be <= %s from upper-constraints and '
'include the upper-constraints version' %
(name, uc_spec.version))
error_count += 1
continue
if args.gr_check:
for spec in specs:
# g-r will mostly define blocked versions. And a
# local project may define there own, so there is
# no point checking a != specifier
if spec.operator == '!=':
continue
if spec.version not in spec_gr:
print(
u'Specifier %s from %s is failing check '
'from global-requirements specifiers %s' %
(spec.version, name, str(spec_gr)))
error_count += 1
continue
return 1 if error_count else 0

View File

@ -89,6 +89,11 @@ def make_project(fixture):
global_reqs = requirement.parse(
open("openstack_requirements/tests/files/gr-base.txt", "rt").read())
upper_constraints = requirement.parse(
open("openstack_requirements/tests/files/upper-constraints.txt",
"rt").read())
blacklist = requirement.parse(
open("openstack_requirements/tests/files/blacklist.txt", "rt").read())
pbr_project = make_project(pbr_fixture)
project_project = make_project(project_fixture)
bad_project = make_project(bad_project_fixture)

View File

@ -0,0 +1,11 @@
# linters - each project may have a different version with loose convergence
# over time.
flake8
flake8_docstrings
flake8-import-order
hacking
mccabe
pep257
pep8
pyflakes
pylint

View File

@ -4,7 +4,7 @@
greenlet>=0.3.1
# < 0.8.0/0.8 does not work, see https://bugs.launchpad.net/bugs/1153983
SQLAlchemy>=0.7.8,<=0.7.99
SQLAlchemy>=0.7.8,<=1.0.17
anyjson>=0.3.3
eventlet>=0.9.12
PasteDeploy
@ -22,7 +22,7 @@ oslo.config>=1.1.0
# For Swift storage backend.
python-swiftclient>=1.2,<2
python-swiftclient>=1.2,<4
# Note you will need gcc buildtools installed and must
# have installed libxml headers for lxml to be successfully

View File

@ -4,7 +4,7 @@ discover
feedparser
fixtures>=0.3.12
mox==0.5.3
mox3==0.7.3
mox3==0.21.0
MySQL-python
psycopg2
pylint==0.25.2

View File

@ -0,0 +1,507 @@
voluptuous===0.9.3
chardet===2.3.0
enum-compat===0.0.2
rsa===3.4.2
restructuredtext-lint===1.0.1
netmiko===1.2.8
PasteDeploy===1.5.2
typing===3.5.3.0
python-saharaclient===1.1.0
Routes===2.4.1
rtslib-fb===2.1.63
smmap===0.9.0
XStatic-Angular-Bootstrap===2.2.0.0
WebOb===1.6.3
pecan===1.2.1
ryu===4.12
os-api-ref===1.3.0
oslo.concurrency===3.19.0
websocket-client===0.40.0
osprofiler===1.6.0
bandit===1.4.0
tabulate===0.7.7
python-ironic-inspector-client===1.11.0
lxml===3.7.3
python-kingbirdclient===0.1.0
pytest===3.0.6
python-etcd===0.4.5
cursive===0.1.1
oslo.service===1.20.0
django-appconf===1.0.2
pykerberos===1.1.14
certifi===2017.1.23
requests-aws===0.1.8
alabaster===0.7.10
pbr===2.0.0
microversion-parse===0.1.4
Pint===0.7.2
oslo.i18n===3.13.0
jsonpath-rw-ext===1.1.1
python-mistralclient===3.0.0
oslo.context===2.13.0
python-senlinclient===1.2.0
rcssmin===1.0.6
pycadf===2.5.0
pysendfile===2.0.1
fixtures===3.0.0
neutron-lib===1.2.0
pystache===0.5.4
XStatic-Font-Awesome===4.7.0.0
nose===1.3.7
click-spinner===0.1.7
nosehtmloutput===0.0.5
waitress===1.0.2
mistral===4.0.0
os-refresh-config===6.0.0
jsbeautifier===1.6.11;python_version=='3.4'
jsbeautifier===1.6.11;python_version=='3.5'
pysnmp===4.3.4
Mako===1.0.6
XStatic-angular-ui-router===0.3.1.2
pyScss===1.3.4
XStatic-jQuery===1.10.2.1
jsonmodels===2.1.5
ddt===1.1.1
ipaddress===1.0.18
python-freezerclient===1.2.0
os-xenapi===0.1.1
python-vitrageclient===1.1.1
nosexcover===1.0.11
krest===1.3.1
psycopg2===2.7
networkx===1.11
bashate===0.5.1
XStatic-Angular===1.5.8.0
pyngus===2.2.0
Pillow===4.0.0
python-mimeparse===1.6.0
tripleo-common===6.0.0
Tempita===0.5.2
ply===3.10
simplejson===3.10.0
suds-jurko===0.6
python-swiftclient===3.3.0
pyOpenSSL===16.2.0
monasca-common===1.5.0
hyperframe===4.0.2;python_version=='3.4'
hyperframe===4.0.2;python_version=='3.5'
cssutils===1.0.2;python_version=='3.4'
cssutils===1.0.2;python_version=='3.5'
scipy===0.19.0
MySQL-python===1.2.5;python_version=='2.7'
XStatic-Jasmine===2.4.1.1
python-glanceclient===2.6.0
pyinotify===0.9.6
debtcollector===1.12.0
requests-unixsocket===0.1.5
asn1crypto===0.21.1
croniter===0.3.15
python-watcherclient===1.0.0
MarkupSafe===1.0
pypowervm===1.0.0.4.1
doc8===0.7.0
pymongo===3.4.0
sqlparse===0.2.3
oslotest===2.14.0
jsonpointer===1.10
netaddr===0.7.19
pyghmi===1.0.18
sphinxcontrib-blockdiag===1.5.5
kaitaistruct===0.6;python_version=='3.4'
kaitaistruct===0.6;python_version=='3.5'
thrift===0.10.0;python_version=='2.7'
gnocchiclient===3.1.1
wcwidth===0.1.7
jsonpath-rw===1.4.0
prettytable===0.7.2
vine===1.1.3
taskflow===2.10.0
traceback2===1.4.0
semantic-version===2.6.0
tablib===0.11.4
astroid===1.3.8
deprecation===1.0
SQLAlchemy===1.0.17
pyroute2===0.4.13
kazoo===2.2.1
XStatic-roboto-fontface===0.5.0.0
pyudev===0.21.0
eventlet===0.19.0
openstack-doc-tools===1.5.0
frozendict===1.2
oslo.messaging===5.18.0
extras===1.0.0
PyJWT===1.4.2
paramiko===2.1.2
ordereddict===1.1
reno===2.1.2
unicodecsv===0.14.1;python_version=='2.7'
imagesize===0.7.1
pathlib===1.0.1;python_version=='2.7'
urllib3===1.20
graphviz===0.6
PyKMIP===0.6.0
python-subunit===1.2.0
tornado===4.4.2;python_version=='3.4'
tornado===4.4.2;python_version=='3.5'
pycparser===2.17
mock===2.0.0
PyYAML===3.12
beautifulsoup4===4.5.3
ovs===2.7.0
cryptography===1.8.1
backports.ssl-match-hostname===3.5.0.1
pylxd===2.2.3
anyjson===0.3.3
requests-mock===1.3.0
os-apply-config===6.0.0
oslosphinx===4.11.0
mox3===0.21.0
gunicorn===19.7.0
unittest2===1.1.0
django-compressor===2.1.1
libvirt-python===3.1.0
tzlocal===1.3
python-novaclient===7.1.0
bcrypt===3.1.3
os-client-config===1.26.0
XStatic-Angular-Gettext===2.3.8.0
Pygments===2.2.0
XStatic-Hogan===2.0.0.2
XStatic-objectpath===1.2.1.0
python-manilaclient===1.14.0
requests===2.12.5
snowballstemmer===1.2.1
Jinja2===2.9.5
XStatic-Bootstrap-SCSS===3.3.7.1
pyzabbix===0.7.4
ptyprocess===0.5.1
amqp===2.1.3
ruamel.yaml===0.13.14;python_version=='3.4'
ruamel.yaml===0.13.14;python_version=='3.5'
websockify===0.8.0
html2text===2016.9.19;python_version=='3.4'
html2text===2016.9.19;python_version=='3.5'
XStatic-JQuery.quicksearch===2.0.3.1
mpmath===0.19
XStatic-JQuery-Migrate===1.2.1.1
appdirs===1.4.3
tinyrpc===0.5
influxdb===4.0.0
funcparserlib===0.3.6
passlib===1.7.1
dib-utils===0.0.11
cliff===2.4.0
os-brick===1.11.0
trollius===2.1
scp===0.10.2
python-zaqarclient===1.4.0
funcsigs===1.0.2;python_version=='2.7'
zhmcclient===0.10.0
dnspython3===1.15.0;python_version=='3.4'
dnspython3===1.15.0;python_version=='3.5'
ldappool===2.0.0
termcolor===1.1.0
hpack===2.3.0;python_version=='3.4'
hpack===2.3.0;python_version=='3.5'
hiredis===0.2.0
google-api-python-client===1.6.2
castellan===0.5.0
oslo.versionedobjects===1.22.0
webcolors===1.7
aodhclient===0.9.0
autobahn===0.17.2
SQLAlchemy-Utils===0.32.12
coverage===4.3.4
freezegun===0.3.8
python-pytun===2.2.1
pyperclip===1.5.27;python_version=='3.4'
pyperclip===1.5.27;python_version=='3.5'
cassandra-driver===3.8.0
mox===0.5.3
XStatic-Angular-Schema-Form===0.8.13.0
gabbi===1.32.0
XStatic-bootswatch===3.3.7.0
XStatic-term.js===0.0.7.0
oslo.log===3.21.0
nodeenv===1.1.2
pylev===1.3.0
python-searchlightclient===1.1.0
oslo.middleware===3.24.0
brotlipy===0.6.0;python_version=='3.4'
brotlipy===0.6.0;python_version=='3.5'
XStatic-mdi===1.4.57.0
django-pyscss===2.0.2
uritemplate===3.0.0
django-babel===0.5.1
docutils===0.13.1
notifier===1.0.3
pycrypto===2.6.1
ujson===1.35
selenium===3.3.0
mypy===0.501;python_version=='3.4'
mypy===0.501;python_version=='3.5'
dogtag-pki===10.3.5.1
sphinxcontrib-seqdiag===0.8.5
os-win===1.4.1
retrying===1.3.3
pathlib2===2.2.1
pydotplus===2.0.2
urwid===1.3.1;python_version=='3.4'
urwid===1.3.1;python_version=='3.5'
singledispatch===3.4.0.3;python_version=='2.7'
oslo.serialization===2.17.0
warlock===1.2.0
sphinxcontrib-httpdomain===1.5.0
murano-pkg-check===0.3.0
oslo.vmware===2.18.0
sqlalchemy-migrate===0.11.0
gitdb===0.6.4
python-monascaclient===1.5.0
ldap3===2.2.1
automaton===1.8.0
argh===0.26.2;python_version=='3.4'
argh===0.26.2;python_version=='3.5'
keyring===10.3
testscenarios===0.5.0
sphinxcontrib-pecanwsme===0.8.0
enum34===1.1.6
packaging===16.8
nose-exclude===0.5.0
psutil===5.2.0
py===1.4.32
txaio===2.6.1
elasticsearch===2.4.1
django-nose===1.4.4
XStatic-JQuery.TableSorter===2.14.5.1
pifpaf===0.25.1
pysmi===0.0.7
blockdiag===1.5.3
testtools===2.2.0
Parsley===1.3
XStatic-tv4===1.2.7.0
positional===1.1.1
XStatic-JSEncrypt===2.3.1.1
python-cinderclient===1.11.0
keystonemiddleware===4.14.0
django-formtools===2.0
python-ceilometerclient===2.8.0
XStatic-Spin===1.2.5.2
SecretStorage===2.3.1
XStatic-Rickshaw===1.5.0.0
iso8601===0.1.11
tooz===1.50.0
linecache2===1.0.0
oauth2client===3.0.0
idna===2.5
python-karborclient===0.1.3
weakrefmethod===1.0.3;python_version=='2.7'
PuLP===1.6.5
crc16===0.1.1
os-dpm===1.0.0
python-neutronclient===6.1.0
pika===0.10.0
oslo.cache===1.18.0
WebTest===2.0.26
openstack.nose-plugin===0.11
os-collect-config===6.0.0
python-qpid-proton===0.17.0
pysaml2===4.0.2
oslo.reports===1.18.0
ceilometermiddleware===1.0.1
python-nss===1.0.1
testrepository===0.0.20
sympy===1.0
sphinxmark===0.1.17
osc-lib===1.3.0
python-consul===0.7.0
seqdiag===0.9.5
numpy===1.12.0
repoze.who===2.3
Sphinx===1.5.3
oslo.config===3.23.0
tempest===15.0.0
django-floppyforms===1.7.0
openstackdocstheme===1.6.1
progressbar2===3.12.0
zake===0.2.2
python-solumclient===2.2.0
PyMySQL===0.7.10
kubernetes===1.0.0
httplib2===0.10.3
os-cloud-config===6.0.0
bottle===0.12.13
betamax===0.8.0
construct===2.8.10
pyparsing===2.2.0
dogpile.cache===0.6.2
python-barbicanclient===4.2.0
blinker===1.4;python_version=='3.4'
blinker===1.4;python_version=='3.5'
WSME===0.9.2
msgpack-python===0.4.8
proboscis===1.2.6.0
fortiosclient===0.0.2
stevedore===1.21.0
botocore===1.5.24
xmltodict===0.10.2
pyasn1===0.2.3
python-utils===2.0.1
oslo.rootwrap===5.5.0
Django===1.8.17
pexpect===4.2.1
cmd2===0.7.0
redis===2.10.5
jmespath===0.9.2
click===6.7
docker-pycreds===0.2.1
XStatic-smart-table===1.4.13.2
kuryr-lib===0.3.0
scrypt===0.8.0
jsonpatch===1.15
typed-ast===1.0.2;python_version=='3.4'
typed-ast===1.0.2;python_version=='3.5'
os-testr===0.8.0
stomp.py===4.1.17
xattr===0.9.1
python-memcached===1.58
openstacksdk===0.9.13
six===1.10.0
h2===2.6.0;python_version=='3.4'
h2===2.6.0;python_version=='3.5'
dulwich===0.17.1
pykafka===2.5.0
kombu===4.0.1
mitmproxy===2.0.0;python_version=='3.4'
mitmproxy===2.0.0;python_version=='3.5'
yaql===1.1.3
requestsexceptions===1.2.0
testresources===2.0.1
falcon===1.1.0
pycryptodome===3.4.5
pyldap===2.4.28
Flask-RESTful===0.3.5
GitPython===2.1.3
python-ironicclient===1.11.1
XStatic===1.0.1
click-repl===0.1.1
XStatic-Angular-FileUpload===12.0.4.0
python-openstackclient===3.9.0
pika-pool===0.1.3
pyzmq===16.0.2
EditorConfig===0.12.1;python_version=='3.4'
EditorConfig===0.12.1;python_version=='3.5'
oslo.db===4.18.0
simplegeneric===0.8.1
abclient===0.2.3
pymemcache===1.4.2
wrapt===1.10.8
oslo.privsep===1.17.0
zope.interface===4.3.3
oslo.policy===1.19.0
python-muranoclient===0.12.0
pyeclib===1.4.0
django-openstack-auth===3.1.1
wsgi-intercept===1.5.0
ndg-httpsclient===0.4.2;python_version=='2.7'
tempest-lib===1.0.0
spec-cleaner===0.9.2
repoze.lru===0.6
rfc3986===0.4.1
tenacity===4.0.0
logilab-common===1.3.0
XStatic-Magic-Search===0.2.5.1
python-designateclient===2.6.0
Paste===2.0.3
pycodestyle===2.3.1
boto===2.46.1
functools32===3.2.3.post2;python_version=='2.7'
watchdog===0.8.3;python_version=='3.4'
watchdog===0.8.3;python_version=='3.5'
gevent===1.2.1
os-vif===1.4.0
Werkzeug===0.12
pyasn1-modules===0.0.8
APScheduler===3.3.1
monotonic===1.2
python-smaugclient===0.0.8
python-troveclient===2.8.0
cliff-tablib===2.0
XStatic-Bootstrap-Datepicker===1.3.1.0
CouchDB===1.1
netifaces===0.10.5
cachetools===2.0.0
ws4py===0.3.4
backports-abc===0.5;python_version=='3.4'
backports-abc===0.5;python_version=='3.5'
keystoneauth1===2.18.0
statsd===3.2.1
XenAPI===1.2
python-keystoneclient===3.10.0
demjson===2.2.4
diskimage-builder===1.28.0
heat-translator===0.7.0
python-magnumclient===2.5.0
docker===2.1.0
prompt-toolkit===1.0.13
pathtools===0.1.2;python_version=='3.4'
pathtools===0.1.2;python_version=='3.5'
qpid-python===0.32.1;python_version=='2.7'
contextlib2===0.5.4
XStatic-Angular-lrdragndrop===1.0.2.2
python-congressclient===1.6.0
aniso8601===1.2.0
rjsmin===1.0.12
icalendar===3.11.3
decorator===4.0.11
cffi===1.9.1
futurist===0.22.0
jsonschema===2.6.0
alembic===0.9.1
glance-store===0.20.0
sphinx-testing===0.7.1
dnspython===1.15.0
oauthlib===2.0.1
Babel===2.3.4
logutils===0.3.4.1
scandir===1.5
sphinxcontrib-fulltoc===1.1
smmap2===2.0.1
olefile===0.44
greenlet===0.4.12
xvfbwrapper===0.2.9
futures===3.0.5
tosca-parser===0.7.0
Flask===0.12
pymod2pkg===0.7.2
happybase===0.9;python_version=='2.7'
marathon===0.8.11
docker-py===1.10.6
fasteners===0.14.1
sortedcontainers===1.5.7;python_version=='3.4'
sortedcontainers===1.5.7;python_version=='3.5'
python-tackerclient===0.9.0
python-heatclient===1.8.0
kafka-python===1.3.2
oslo.utils===3.23.0
python-editor===1.0.3
gitdb2===2.0.0
requests-kerberos===0.11.0
itsdangerous===0.24
XStatic-jquery-ui===1.12.0.1
monasca-statsd===1.5.0
python-dateutil===2.6.0
virtualenv===15.1.0
colorama===0.3.7
ironic-lib===2.6.0
pytz===2016.10
XStatic-D3===3.5.17.0
sysv-ipc===0.7.0
scikit-learn===0.18.1
wsgiref==0.1.2
discover==0.4.0
oslo.sphinx==0.9.27
python-ldap==2.3.13
argparse==1.4.0
setuptools-git==25.1.4
feedparser==5.2.1

View File

@ -0,0 +1,196 @@
# 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 __future__ import print_function
import io
import mock
import os
import testscenarios
import testtools
from openstack_requirements.cmds import check_exists
from openstack_requirements import project
from openstack_requirements.tests import common
load_tests = testscenarios.load_tests_apply_scenarios
def mock_read_requirements_file(filename):
if os.path.basename(filename) == 'upper-constraints.txt':
return common.upper_constraints
elif os.path.basename(filename) == 'global-requirements.txt':
return common.global_reqs
elif os.path.basename(filename) == 'blacklist.txt':
return common.blacklist
else:
raise IOError('No such file or directory: %s' % filename)
class CheckExistsTest(testtools.TestCase):
def setUp(self):
super(CheckExistsTest, self).setUp()
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
@mock.patch('openstack_requirements.project.read',
return_value=common.project_project)
def test_good_project(self, mock_project_read):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 0)
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
def test_project_missing_from_uc(self):
self.useFixture(common.project_fixture)
orig_mocked_read_req = check_exists.read_requirements_file
read_req_path = ('openstack_requirements.cmds.check_exists.'
'read_requirements_file')
def remove_req_read_reqs_file(filename):
if filename == 'upper-constraints.txt':
upper_cons = common.upper_constraints.copy()
upper_cons.pop('six')
return upper_cons
return orig_mocked_read_req(filename)
expected_out = ('six from requirements.txt not found in'
' upper-constraints')
# Start capturing some output
mock_stdout = io.StringIO()
with mock.patch('openstack_requirements.project.read',
return_value=common.project_project), \
mock.patch('sys.stdout', mock_stdout), \
mock.patch(read_req_path, remove_req_read_reqs_file):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 1)
self.assertIn(expected_out, mock_stdout.getvalue())
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
def test_project_missing_from_gr(self):
self.useFixture(common.project_fixture)
# Add some random package that wont exist in G-R
with open(common.project_fixture.req_file, 'a') as req_file:
req_file.write(u'SomeRandomModule #Some random module\n')
req_file.flush()
expected_out = ('somerandommodule from requirements.txt not found in'
' global-requirements')
# Start capturing some output
mock_stdout = io.StringIO()
proj_read = project.read(common.project_fixture.root)
with mock.patch('openstack_requirements.project.read',
return_value=proj_read), \
mock.patch('sys.stdout', mock_stdout):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 1)
self.assertIn(expected_out, mock_stdout.getvalue())
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
def test_project_multiple_missing_from_uc_and_gr(self):
self.useFixture(common.project_fixture)
orig_mocked_read_req = check_exists.read_requirements_file
read_req_path = ('openstack_requirements.cmds.check_exists.'
'read_requirements_file')
def remove_req_read_reqs_file(filename):
if filename == 'upper-constraints.txt':
upper_cons = common.upper_constraints.copy()
upper_cons.pop('lxml')
return upper_cons
return orig_mocked_read_req(filename)
new_reqs = '>1.10.0\nsomerandommodule\n'
# lets change the six requirement not include the u-c version
proj_read = project.read(common.project_fixture.root)
proj_read['requirements']['requirements.txt'] = \
proj_read['requirements']['requirements.txt'][:-1] + new_reqs
proj_read['requirements']['test-requirements.txt'] = \
proj_read['requirements']['test-requirements.txt'] + \
'anotherrandommodule\n'
expected_outs = [
'lxml from requirements.txt not found in upper-constraints',
'somerandommodule from requirements.txt not found in '
'global-requirements',
'anotherrandommodule from test-requirements.txt not found in '
'global-requirements',
'six must be <= 1.10.0 from upper-constraints and include the '
'upper-constraints version']
# Start capturing some output
mock_stdout = io.StringIO()
with mock.patch('openstack_requirements.project.read',
return_value=proj_read), \
mock.patch('sys.stdout', mock_stdout), \
mock.patch(read_req_path, remove_req_read_reqs_file):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 1)
for expected in expected_outs:
self.assertIn(expected, mock_stdout.getvalue())
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
def test_project_req_bigger_then_uc(self):
self.useFixture(common.project_fixture)
# lets change the six requirement not include the u-c version
proj_read = project.read(common.project_fixture.root)
proj_read['requirements']['requirements.txt'] = \
proj_read['requirements']['requirements.txt'][:-1] + '>1.10.0\n'
expected_out = ('six must be <= 1.10.0 from upper-constraints and '
'include the upper-constraints version')
# Start capturing some output
mock_stdout = io.StringIO()
with mock.patch('openstack_requirements.project.read',
return_value=proj_read), \
mock.patch('sys.stdout', mock_stdout):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 1)
self.assertIn(expected_out, mock_stdout.getvalue())
@mock.patch(
'openstack_requirements.cmds.check_exists.read_requirements_file',
mock_read_requirements_file)
def test_project_req_not_include_uc_version(self):
self.useFixture(common.project_fixture)
# lets change the six requirement not include the u-c version
proj_read = project.read(common.project_fixture.root)
proj_read['requirements']['requirements.txt'] = \
proj_read['requirements']['requirements.txt'][:-1] + \
'<1.10.0,>1.10.0\n'
expected_out = ('six must be <= 1.10.0 from upper-constraints and '
'include the upper-constraints version')
# Start capturing some output
mock_stdout = io.StringIO()
with mock.patch('openstack_requirements.project.read',
return_value=proj_read), \
mock.patch('sys.stdout', mock_stdout):
ret = check_exists.main([common.project_fixture.root])
self.assertEqual(ret, 1)
self.assertIn(expected_out, mock_stdout.getvalue())

View File

@ -52,7 +52,7 @@ class SmokeTest(testtools.TestCase):
expected = ('Version change for: greenlet, SQLAlchemy, eventlet, PasteDeploy, routes, WebOb, wsgiref, boto, kombu, pycrypto, python-swiftclient, lxml, jsonschema, python-keystoneclient\n' # noqa
"""Updated %(project)s/requirements.txt:
greenlet>=0.3.1 -> greenlet>=0.3.2
SQLAlchemy>=0.7.8,<=0.7.99 -> SQLAlchemy<=0.7.99,>=0.7
SQLAlchemy>=0.7.8,<=1.0.17 -> SQLAlchemy<=0.7.99,>=0.7
eventlet>=0.9.12 -> eventlet>=0.12.0
PasteDeploy -> PasteDeploy>=1.5.0
routes -> Routes>=1.12.3
@ -61,14 +61,14 @@ class SmokeTest(testtools.TestCase):
boto -> boto>=2.4.0
kombu>2.4.7 -> kombu>=2.4.8
pycrypto>=2.1.0alpha1 -> pycrypto>=2.6
python-swiftclient>=1.2,<2 -> python-swiftclient>=1.2
python-swiftclient>=1.2,<4 -> python-swiftclient>=1.2
lxml -> lxml>=2.3
jsonschema -> jsonschema!=1.4.0,<2,>=1.0.0
python-keystoneclient>=0.2.0 -> python-keystoneclient>=0.4.1
Version change for: mox, mox3, testrepository, testtools
Updated %(project)s/test-requirements.txt:
mox==0.5.3 -> mox>=0.5.3
mox3==0.7.3 -> mox3>=0.7.0
mox3==0.21.0 -> mox3>=0.7.0
testrepository>=0.0.13 -> testrepository>=0.0.17
testtools>=0.9.27 -> testtools>=0.9.32
""") % dict(project=self.project.root)
@ -157,7 +157,7 @@ class UpdateTest(testtools.TestCase):
expected = ('Version change for: greenlet, SQLAlchemy, eventlet, PasteDeploy, routes, WebOb, wsgiref, boto, kombu, pycrypto, python-swiftclient, lxml, jsonschema, python-keystoneclient\n' # noqa
"""Updated %(project)s/requirements.txt:
greenlet>=0.3.1 -> greenlet>=0.3.2
SQLAlchemy>=0.7.8,<=0.7.99 -> SQLAlchemy<=0.7.99,>=0.7
SQLAlchemy>=0.7.8,<=1.0.17 -> SQLAlchemy<=0.7.99,>=0.7
eventlet>=0.9.12 -> eventlet>=0.12.0
PasteDeploy -> PasteDeploy>=1.5.0
routes -> Routes>=1.12.3
@ -166,14 +166,14 @@ class UpdateTest(testtools.TestCase):
boto -> boto>=2.4.0
kombu>2.4.7 -> kombu>=2.4.8
pycrypto>=2.1.0alpha1 -> pycrypto>=2.6
python-swiftclient>=1.2,<2 -> python-swiftclient>=1.2
python-swiftclient>=1.2,<4 -> python-swiftclient>=1.2
lxml -> lxml>=2.3
jsonschema -> jsonschema!=1.4.0,<2,>=1.0.0
python-keystoneclient>=0.2.0 -> python-keystoneclient>=0.4.1
Version change for: mox, mox3, testrepository, testtools
Updated %(project)s/test-requirements.txt:
mox==0.5.3 -> mox>=0.5.3
mox3==0.7.3 -> mox3>=0.7.0
mox3==0.21.0 -> mox3>=0.7.0
testrepository>=0.0.13 -> testrepository>=0.0.17
testtools>=0.9.27 -> testtools>=0.9.32
""") % dict(project=common.project_project['root'])
@ -190,7 +190,7 @@ Updated %(project)s/test-requirements.txt:
Version change for: greenlet, SQLAlchemy, eventlet, PasteDeploy, routes, WebOb, wsgiref, boto, kombu, pycrypto, python-swiftclient, lxml, jsonschema, python-keystoneclient\n""" # noqa
"""Updated %(project)s/requirements.txt:
greenlet>=0.3.1 -> greenlet>=0.3.2
SQLAlchemy>=0.7.8,<=0.7.99 -> SQLAlchemy<=0.7.99,>=0.7
SQLAlchemy>=0.7.8,<=1.0.17 -> SQLAlchemy<=0.7.99,>=0.7
eventlet>=0.9.12 -> eventlet>=0.12.0
PasteDeploy -> PasteDeploy>=1.5.0
routes -> Routes>=1.12.3
@ -199,7 +199,7 @@ Version change for: greenlet, SQLAlchemy, eventlet, PasteDeploy, routes, WebOb,
boto -> boto>=2.4.0
kombu>2.4.7 -> kombu>=2.4.8
pycrypto>=2.1.0alpha1 -> pycrypto>=2.6
python-swiftclient>=1.2,<2 -> python-swiftclient>=1.2
python-swiftclient>=1.2,<4 -> python-swiftclient>=1.2
lxml -> lxml>=2.3
jsonschema -> jsonschema!=1.4.0,<2,>=1.0.0
python-keystoneclient>=0.2.0 -> python-keystoneclient>=0.4.1
@ -207,7 +207,7 @@ Syncing %(project)s/test-requirements.txt
Version change for: mox, mox3, testrepository, testtools
Updated %(project)s/test-requirements.txt:
mox==0.5.3 -> mox>=0.5.3
mox3==0.7.3 -> mox3>=0.7.0
mox3==0.21.0 -> mox3>=0.7.0
testrepository>=0.0.13 -> testrepository>=0.0.17
testtools>=0.9.27 -> testtools>=0.9.32
Syncing setup.py

View File

@ -39,4 +39,5 @@ console_scripts =
validate-constraints = openstack_requirements.cmds.validate:main
validate-projects = openstack_requirements.cmds.validate_projects:main
normalize-requirements = openstack_requirements.cmds.normalize_requirements:main
check-python2-support = openstack_requirements.cmds.check_py2:main
check-python2-support = openstack_requirements.cmds.check_py2:main
check-constraints = openstack_requirements.cmds.check_exists:main