Update tox testing infrastructure.

Change-Id: I18967dde83bca38a1bfa9c85c7b2b21b28b415e3
This commit is contained in:
Monty Taylor 2012-02-07 10:12:00 -08:00
parent b8b951060d
commit 029eddc0d8
13 changed files with 235 additions and 46 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
local_settings.py local_settings.py
keeper keeper
build/* build/*
ChangeLog
build-stamp build-stamp
python_melangeclient.egg-info python_melangeclient.egg-info
.tox .tox

View File

@ -1,2 +1,5 @@
include ChangeLog
include openstack-common.conf
include README.rst include README.rst
include tox.ini
include melange/client/views/*.tpl include melange/client/views/*.tpl

View File

@ -1,30 +0,0 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# 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.
import gettext
from melange.client.client import HTTPClient
from melange.client.client import AuthorizationClient
# NOTE(jkoelker) should this be melange.client? Are translations going
# to be separate?
gettext.install('melange', unicode=1)
__all__ = [HTTPClient,
AuthorizationClient]

View File

View File

@ -0,0 +1,121 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 OpenStack LLC.
# All Rights Reserved.
#
# 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.
"""
Utilities with minimum-depends for use in setup.py
"""
import os
import re
import subprocess
def parse_mailmap(mailmap='.mailmap'):
mapping = {}
if os.path.exists(mailmap):
fp = open(mailmap, 'r')
for l in fp:
l = l.strip()
if not l.startswith('#') and ' ' in l:
canonical_email, alias = l.split(' ')
mapping[alias] = canonical_email
return mapping
def str_dict_replace(s, mapping):
for s1, s2 in mapping.iteritems():
s = s.replace(s1, s2)
return s
# Get requirements from the first file that exists
def get_reqs_from_files(requirements_files):
reqs_in = []
for requirements_file in requirements_files:
if os.path.exists(requirements_file):
return open(requirements_file, 'r').read().split('\n')
return []
def parse_requirements(requirements_files=['requirements.txt',
'tools/pip-requires']):
requirements = []
for line in get_reqs_from_files(requirements_files):
if re.match(r'\s*-e\s+', line):
requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
line))
elif re.match(r'\s*-f\s+', line):
pass
else:
requirements.append(line)
return requirements
def parse_dependency_links(requirements_files=['requirements.txt',
'tools/pip-requires']):
dependency_links = []
for line in get_reqs_from_files(requirements_files):
if re.match(r'(\s*#)|(\s*$)', line):
continue
if re.match(r'\s*-[ef]\s+', line):
dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line))
return dependency_links
def write_requirements():
venv = os.environ.get('VIRTUAL_ENV', None)
if venv is not None:
with open("requirements.txt", "w") as req_file:
output = subprocess.Popen(["pip", "-E", venv, "freeze", "-l"],
stdout=subprocess.PIPE)
requirements = output.communicate()[0].strip()
req_file.write(requirements)
def run_git_command(cmd):
output = subprocess.Popen(["/bin/sh", "-c", cmd],
stdout=subprocess.PIPE)
return output.communicate()[0].strip()
def write_vcsversion(location):
if os.path.isdir('.git'):
branch_nick_cmd = 'git branch | grep -Ei "\* (.*)" | cut -f2 -d" "'
branch_nick = run_git_command(branch_nick_cmd)
revid_cmd = "git --no-pager log --max-count=1 --pretty=oneline"
revid = run_git_command(revid_cmd).split()[0]
revno_cmd = "git --no-pager log --oneline | wc -l"
revno = run_git_command(revno_cmd)
with open(location, 'w') as version_file:
version_file.write("""
# This file is automatically generated by setup.py, So don't edit it. :)
version_info = {
'branch_nick': '%s',
'revision_id': '%s',
'revno': %s
}
""" % (branch_nick, revid, revno))
def write_git_changelog():
if os.path.isdir('.git'):
git_log_gnu = 'git log --format="%ai %aN %n%n%x09* %s%d%n"'
changelog = run_git_command(git_log_gnu)
mailmap = parse_mailmap()
with open("ChangeLog", "w") as changelog_file:
changelog_file.write(str_dict_replace(changelog, mailmap))

7
openstack-common.conf Normal file
View File

@ -0,0 +1,7 @@
[DEFAULT]
# The list of modules to copy from openstack-common
modules=setup
# The base module to hold the copy of openstack.common
base=melange.client

38
pylintrc Normal file
View File

@ -0,0 +1,38 @@
# The format of this file isn't really documented; just use --generate-rcfile
[Messages Control]
# NOTE(justinsb): We might want to have a 2nd strict pylintrc in future
# C0111: Don't require docstrings on every method
# W0511: TODOs in code comments are fine.
# W0142: *args and **kwargs are fine.
# W0622: Redefining id is fine.
disable=C0111,W0511,W0142,W0622
[Basic]
# Variable names can be 1 to 31 characters long, with lowercase and underscores
variable-rgx=[a-z_][a-z0-9_]{0,30}$
# Argument names can be 2 to 31 characters long, with lowercase and underscores
argument-rgx=[a-z_][a-z0-9_]{1,30}$
# Method names should be at least 3 characters long
# and be lowecased with underscores
method-rgx=([a-z_][a-z0-9_]{2,50}|setUp|tearDown)$
# Module names matching melange-* are ok (files in bin/)
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+)|(melange-[a-z0-9_-]+))$
# Don't require docstrings on tests.
no-docstring-rgx=((__.*__)|([tT]est.*)|setUp|tearDown)$
[Design]
max-public-methods=100
min-public-methods=0
max-args=6
[Variables]
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
# _ is used by our localization
additional-builtins=_

View File

@ -1,13 +1,6 @@
[nosetests] [nosetests]
verbosity=2 verbosity=2
detailed-errors=1 detailed-errors=1
with-tissue=1
tissue-repeat=1
tissue-show-pep8=1
tissue-show-source=1
tissue-inclusive=1
tissue-color=1
tissue-package=melange.client
with-openstack=1 with-openstack=1
openstack-red=0.1 openstack-red=0.1
openstack-yellow=0.075 openstack-yellow=0.075

View File

@ -15,10 +15,23 @@
import os import os
import sys import sys
from melange.client.openstack.common.setup import parse_requirements
from melange.client.openstack.common.setup import parse_dependency_links
from melange.client.openstack.common.setup import write_requirements
from melange.client.openstack.common.setup import write_git_changelog
from setuptools.command.sdist import sdist
import setuptools import setuptools
version = "0.1" version = "0.1"
install_requires = ["httplib2", "pyyaml"]
class local_sdist(sdist):
"""Customized sdist hook - builds the ChangeLog file from VC first"""
def run(self):
write_git_changelog()
sdist.run(self)
cmdclass = {'sdist': local_sdist}
if sys.version_info < (2, 6): if sys.version_info < (2, 6):
install_requires.append("simplejson") install_requires.append("simplejson")
@ -34,6 +47,8 @@ classifiers = ["Development Status :: 5 - Production/Stable",
console_scripts = ["melange = melange.client.cli:main"] console_scripts = ["melange = melange.client.cli:main"]
write_requirements()
def read_file(file_name): def read_file(file_name):
return open(os.path.join(os.path.dirname(__file__), return open(os.path.join(os.path.dirname(__file__),
@ -46,12 +61,14 @@ setuptools.setup(name="python-melangeclient",
long_description=read_file("README.rst"), long_description=read_file("README.rst"),
license="Apache License, Version 2.0", license="Apache License, Version 2.0",
url="https://github.com/openstack/python-melangeclient", url="https://github.com/openstack/python-melangeclient",
cmdclass=cmdclass,
classifiers=classifiers, classifiers=classifiers,
author="Openstack Melange Team", author="Openstack Melange Team",
author_email="openstack@lists.launchpad.net", author_email="openstack@lists.launchpad.net",
include_package_data=True, include_package_data=True,
packages=setuptools.find_packages(exclude=["tests"]), packages=setuptools.find_packages(exclude=["tests"]),
install_requires=install_requires, install_requires=parse_requirements(),
entry_points = {"console_scripts": console_scripts}, dependency_links=parse_dependency_links(),
entry_points={"console_scripts": console_scripts},
zip_safe=False, zip_safe=False,
) )

2
tools/pip-requires Normal file
View File

@ -0,0 +1,2 @@
pyyaml
httplib2

10
tools/test-requires Normal file
View File

@ -0,0 +1,10 @@
# Packages needed for dev testing
distribute>=0.6.24
coverage
mox
nose
nosexcover
openstack.nose_plugin
pep8
pylint

39
tox.ini
View File

@ -1,9 +1,36 @@
[tox] [tox]
envlist = py26,py27 envlist = py26,py27,pep8
[testenv] [testenv]
deps= nose setenv = VIRTUAL_ENV={envdir}
mox deps = -r{toxinidir}/tools/pip-requires
tissue -r{toxinidir}/tools/test-requires
openstack.nose_plugin commands = nosetests --where=melange/client/tests/unit
commands=nosetests []
[testenv:pep8]
deps = pep8
commands = pep8 --repeat --show-source melange setup.py
[testenv:pylint]
commands = pylint --rcfile=pylintrc --output-format=parseable melange
[testenv:cover]
commands = nosetests --where=melange/client/tests/unit --with-coverage --cover-html --cover-erase --cover-package=melange
[testenv:sdist]
commands = python setup.py sdist {posargs}
[testenv:hudson]
downloadcache = ~/cache/pip
[testenv:jenkins26]
basepython = python2.6
deps = file://{toxinidir}/.cache.bundle
[testenv:jenkins27]
basepython = python2.7
deps = file://{toxinidir}/.cache.bundle
[testenv:jenkinscover]
deps = file://{toxinidir}/.cache.bundle
commands = nosetests --cover-erase --cover-package=melange --with-xcoverage