summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty Taylor <mordred@inaugust.com>2012-05-26 14:58:14 -0400
committerGabriel Hurley <gabriel@strikeawe.com>2012-05-26 14:36:19 -0700
commitc93e7c06fdfbd357767d8bb14b4a4d6fd9693e1e (patch)
tree188bb19696462c9f925a62841f7f04b96981851f
parent4f7ee81b5850b43a2c1eaba85d6bac8099600e19 (diff)
downloadhorizon-c93e7c06fdfbd357767d8bb14b4a4d6fd9693e1e.tar.gz
Add ProjectTestingInterface to horizon.
Horizon is the last project that doesn't have support for the common Project Testing Interface. This gets horizon up to speed with the other bits, but shouldn't break any of the existing interfaces. Change-Id: I464c3b10d9708a0b7b5ffd42c88cd3cf515ef6a7
-rw-r--r--.gitignore4
-rw-r--r--AUTHORS57
-rw-r--r--MANIFEST.in1
-rw-r--r--horizon/openstack/__init__.py0
-rw-r--r--horizon/openstack/common/__init__.py0
-rw-r--r--horizon/openstack/common/setup.py200
-rw-r--r--horizon/tests/authors_tests.py64
-rw-r--r--openstack-common.conf7
-rwxr-xr-xrun_tests.sh2
-rw-r--r--setup.cfg4
-rwxr-xr-xsetup.py61
-rw-r--r--tools/pip-requires6
-rw-r--r--tools/test-requires7
-rw-r--r--tox.ini46
14 files changed, 283 insertions, 176 deletions
diff --git a/.gitignore b/.gitignore
index a933f74fa..5453cb622 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
.coverage*
.noseids
coverage.xml
+nosetests.xml
pep8.txt
pylint.txt
reports
@@ -13,5 +14,8 @@ openstack_dashboard/local/local_settings.py
docs/build/
docs/source/sourcecode
.venv
+.tox
build
dist
+AUTHORS
+ChangeLog
diff --git a/AUTHORS b/AUTHORS
deleted file mode 100644
index 3e36e98b9..000000000
--- a/AUTHORS
+++ /dev/null
@@ -1,57 +0,0 @@
-Alessio Ababilov <aababilov@griddynamics.com>
-Andrews Medina <andrewsmedina@gmail.com>
-Andy Chong <andycjw@gmail.com>
-Anthony Young <sleepsonthefloor@gmail.com>
-Arvind Somya <asomya@cisco.com>
-Bernhard M. Wiedemann <bwiedemann@suse.de>
-Carlo Truijllo <truijllo@crs4.it>
-Chuck Short <chuck.short@canonical.com>
-Cole Robinson <crobinso@redhat.com>
-Dean Troyer <dtroyer@gmail.com>
-Devin Carlen <devin.carlen@gmail.com>
-Doug Doan <dougdoan@gmail.com>
-Duncan McGreggor <duncan@dreamhost.com>
-Emma Steimann <emmasteimann@gmail.com>
-Erwan Gallen <dev@zinux.com>
-Ewan Mellor <ewan.mellor@citrix.com>
-Gabriel Hurley <gabriel@strikeawe.com>
-Ghe Rivero <ghe@debian.org>
-Greg Althaus <galthaus@austin.rr.com>
-Hengqing Hu <hudayou@hotmail.com>
-Ionuț Arțăriși <iartarisi@suse.cz>
-Ivan Kolodyazhny <e0ne@e0ne.info>
-J. Daniel Schmidt <jdsn@suse.de>
-Jake Dahn <jake@ansolabs.com>
-Jake Zukowski <jake@ponyloaf.com>
-James E. Blair <jeblair@hp.com>
-Jay Pipes <jaypipes@gmail.com>
-Jeffrey Wilcox <jeffjapan@gmail.com>
-Jesse Andrews <anotherjesse@gmail.com>
-Jim Yeh <lemonlatte@gmail.com>
-John Postlethwait <john.postlethwait@nebula.com>
-Joseph Heck <heckj@mac.com>
-Joshua McKenty <joshua@pistoncloud.com>
-Julien Danjou <julien.danjou@enovance.com>
-Ke Wu <ke.wu@ibeca.me>
-Ken Pepple <ken.pepple@gmail.com>
-Mark Gius <launchpad@markgius.com>
-Michael Szilagyi <mszilagyi@gmail.com>
-Mike Perez <thingee@gmail.com>
-Mike Scherbakov <mihgen@gmail.com>
-Monty Taylor <mordred@inaugust.com>
-Neil Johnston <onewheeldrive.net@gmail.com>
-Paul McMillan <paul.mcmillan@nebula.com>
-Sam Morrison <sorrison@gmail.com>
-Stephane Angot <sa@hydre.org>
-termie <github@anarkystic.com>
-Thierry Carrez <thierry@openstack.org>
-Tihomir Trifonov <t.trifonov@gmail.com>
-Todd Willey <todd@ansolabs.com>
-Tom Fifield <fifieldt@unimelb.edu.au>
-Tomasz 'Zen' Napierala <tomasz@napierala.org>
-Tres Henry <tres@treshenry.net>
-Vishvananda Ishaya <vishvananda@gmail.com>
-Yuriy Taraday <yorik.sar@gmail.com>
-ZhongYue Luo <lzyeval@gmail.com>
-Ziad Sawalha <github@highbridgellc.com>
-ZHANG Hua <zhuadl@cn.ibm.com>
diff --git a/MANIFEST.in b/MANIFEST.in
index 411e8d2f2..e55ad11ce 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,6 +4,7 @@ recursive-include openstack_dashboard *.html *.js *.css *.less *.csv *.template
recursive-include tools *.py *.sh
include AUTHORS
+include ChangeLog
include LICENSE
include Makefile
include manage.py
diff --git a/horizon/openstack/__init__.py b/horizon/openstack/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/horizon/openstack/__init__.py
diff --git a/horizon/openstack/common/__init__.py b/horizon/openstack/common/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/horizon/openstack/common/__init__.py
diff --git a/horizon/openstack/common/setup.py b/horizon/openstack/common/setup.py
new file mode 100644
index 000000000..79b5a62bc
--- /dev/null
+++ b/horizon/openstack/common/setup.py
@@ -0,0 +1,200 @@
+# 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
+
+from setuptools.command import sdist
+
+
+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 = [x for x in l.split(' ')
+ if x.startswith('<')]
+ mapping[alias] = canonical_email
+ return mapping
+
+
+def canonicalize_emails(changelog, mapping):
+ """Takes in a string and an email alias mapping and replaces all
+ instances of the aliases in the string with their real email.
+ """
+ for alias, email in mapping.iteritems():
+ changelog = changelog.replace(alias, email)
+ return changelog
+
+
+# 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):
+ # For the requirements list, we need to inject only the portion
+ # after egg= so that distutils knows the package it's looking for
+ # such as:
+ # -e git://github.com/openstack/nova/master#egg=nova
+ if re.match(r'\s*-e\s+', line):
+ requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
+ line))
+ # such as:
+ # http://github.com/openstack/nova/zipball/master#egg=nova
+ elif re.match(r'\s*https?:', line):
+ requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1',
+ line))
+ # -f lines are for index locations, and don't get used here
+ 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 = []
+ # dependency_links inject alternate locations to find packages listed
+ # in requirements
+ for line in get_reqs_from_files(requirements_files):
+ # skip comments and blank lines
+ if re.match(r'(\s*#)|(\s*$)', line):
+ continue
+ # lines with -e or -f need the whole line, minus the flag
+ if re.match(r'\s*-[ef]\s+', line):
+ dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line))
+ # lines that are only urls can go in unmolested
+ elif re.match(r'\s*https?:', line):
+ dependency_links.append(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_shell_command(cmd):
+ output = subprocess.Popen(["/bin/sh", "-c", cmd],
+ stdout=subprocess.PIPE)
+ return output.communicate()[0].strip()
+
+
+def write_vcsversion(location):
+ """Produce a vcsversion dict that mimics the old one produced by bzr.
+ """
+ if os.path.isdir('.git'):
+ branch_nick_cmd = 'git branch | grep -Ei "\* (.*)" | cut -f2 -d" "'
+ branch_nick = _run_shell_command(branch_nick_cmd)
+ revid_cmd = "git rev-parse HEAD"
+ revid = _run_shell_command(revid_cmd).split()[0]
+ revno_cmd = "git log --oneline | wc -l"
+ revno = _run_shell_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():
+ """Write a changelog based on the git changelog."""
+ if os.path.isdir('.git'):
+ git_log_cmd = 'git log --stat'
+ changelog = _run_shell_command(git_log_cmd)
+ mailmap = parse_mailmap()
+ with open("ChangeLog", "w") as changelog_file:
+ changelog_file.write(canonicalize_emails(changelog, mailmap))
+
+
+def generate_authors():
+ """Create AUTHORS file using git commits."""
+ jenkins_email = 'jenkins@review.openstack.org'
+ old_authors = 'AUTHORS.in'
+ new_authors = 'AUTHORS'
+ if os.path.isdir('.git'):
+ # don't include jenkins email address in AUTHORS file
+ git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | "
+ "grep -v " + jenkins_email)
+ changelog = _run_shell_command(git_log_cmd)
+ mailmap = parse_mailmap()
+ with open(new_authors, 'w') as new_authors_fh:
+ new_authors_fh.write(canonicalize_emails(changelog, mailmap))
+ if os.path.exists(old_authors):
+ with open(old_authors, "r") as old_authors_fh:
+ new_authors_fh.write('\n' + old_authors_fh.read())
+
+
+def get_cmdclass():
+ """Return dict of commands to run from setup.py."""
+
+ cmdclass = dict()
+
+ class LocalSDist(sdist.sdist):
+ """Builds the ChangeLog and Authors files from VC first."""
+
+ def run(self):
+ write_git_changelog()
+ generate_authors()
+ # sdist.sdist is an old style class, can't use super()
+ sdist.sdist.run(self)
+
+ cmdclass['sdist'] = LocalSDist
+
+ # If Sphinx is installed on the box running setup.py,
+ # enable setup.py to build the documentation, otherwise,
+ # just ignore it
+ try:
+ from sphinx.setup_command import BuildDoc
+
+ class LocalBuildDoc(BuildDoc):
+ def run(self):
+ for builder in ['html', 'man']:
+ self.builder = builder
+ self.finalize_options()
+ BuildDoc.run(self)
+ cmdclass['build_sphinx'] = LocalBuildDoc
+ except ImportError:
+ pass
+
+ return cmdclass
diff --git a/horizon/tests/authors_tests.py b/horizon/tests/authors_tests.py
deleted file mode 100644
index a7779e242..000000000
--- a/horizon/tests/authors_tests.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 OpenStack LLC
-# Copyright 2012 Nebula Inc
-#
-# 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 os
-import commands
-import unittest
-
-
-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
-
-
-class AuthorsTestCase(unittest.TestCase):
- def test_authors_up_to_date(self):
- path_bits = (os.path.dirname(__file__), '..', '..')
- root = os.path.normpath(os.path.join(*path_bits))
- contributors = set()
- missing = set()
- authors_file = open(os.path.join(root, 'AUTHORS'), 'r').read()
-
- if os.path.exists(os.path.join(root, '.git')):
- mailmap = parse_mailmap(os.path.join(root, '.mailmap'))
- for email in commands.getoutput('git log --format=%ae').split():
- if not email:
- continue
- if "jenkins" in email and "openstack.org" in email:
- continue
- email = '<' + email + '>'
- contributors.add(str_dict_replace(email, mailmap))
-
- for contributor in contributors:
- if not contributor in authors_file:
- missing.add(contributor)
-
- self.assertTrue(len(missing) == 0,
- '%r not listed in AUTHORS file.' % missing)
diff --git a/openstack-common.conf b/openstack-common.conf
new file mode 100644
index 000000000..80c62f4f9
--- /dev/null
+++ b/openstack-common.conf
@@ -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=horizon
diff --git a/run_tests.sh b/run_tests.sh
index 43a1076ce..9fe546517 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -6,7 +6,7 @@ set -o errexit
# Increment me any time the environment should be rebuilt.
# This includes dependncy changes, directory renames, etc.
# Simple integer secuence: 1, 2, 3...
-environment_version=17
+environment_version=18
#--------------------------------------------------------#
function usage {
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 000000000..c4c71f1e3
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[nosetests]
+verbosity=2
+detailed-errors=1
+
diff --git a/setup.py b/setup.py
index f551bf905..28e053ecb 100755
--- a/setup.py
+++ b/setup.py
@@ -21,60 +21,22 @@
import os
import re
-from setuptools import setup, find_packages
+import setuptools
from horizon import version
+from horizon.openstack.common import setup
-ROOT = os.path.dirname(__file__)
-PIP_REQUIRES = os.path.join(ROOT, "tools", "pip-requires")
-TEST_REQUIRES = os.path.join(ROOT, "tools", "test-requires")
-
-
-def parse_requirements(*filenames):
- """
- We generate our install_requires from the pip-requires and test-requires
- files so that we don't have to maintain the dependency definitions in
- two places.
- """
- requirements = []
- for f in filenames:
- for line in open(f, 'r').read().split('\n'):
- # Comment lines. Skip.
- if re.match(r'(\s*#)|(\s*$)', line):
- continue
- # Editable matches. Put the egg name into our reqs list.
- if re.match(r'\s*-e\s+', line):
- pkg = re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', line)
- requirements.append("%s" % pkg)
- # File-based installs not supported/needed. Skip.
- elif re.match(r'\s*-f\s+', line):
- pass
- else:
- requirements.append(line)
- return requirements
-
-
-def parse_dependency_links(*filenames):
- """
- We generate our dependency_links from the pip-requires and test-requires
- files for the dependencies pulled from github (prepended with -e).
- """
- dependency_links = []
- for f in filenames:
- for line in open(f, 'r').read().split('\n'):
- if re.match(r'\s*-[ef]\s+', line):
- line = re.sub(r'\s*-[ef]\s+', '', line)
- line = re.sub(r'\s*git\+https', 'http', line)
- line = re.sub(r'\.git#', '/tarball/master#', line)
- dependency_links.append(line)
- return dependency_links
+requires = setup.parse_requirements()
+depend_links = setup.parse_dependency_links()
+tests_require = setup.parse_requirements(['tools/test-requires'])
+ROOT = os.path.dirname(__file__)
def read(fname):
return open(os.path.join(ROOT, fname)).read()
-setup(name="horizon",
+setuptools.setup(name="horizon",
version=version.canonical_version_string(),
url='https://github.com/openstack/horizon/',
license='Apache 2.0',
@@ -82,12 +44,13 @@ setup(name="horizon",
long_description=read('README.rst'),
author='OpenStack',
author_email='horizon@lists.launchpad.net',
- packages=find_packages(),
+ packages=setuptools.find_packages(),
+ cmdclass=setup.get_cmdclass(),
include_package_data=True,
+ install_requires=requires,
+ tests_require=tests_require,
+ dependency_links=depend_links,
zip_safe=False,
- install_requires=parse_requirements(PIP_REQUIRES),
- tests_require=parse_requirements(TEST_REQUIRES),
- dependency_links=parse_dependency_links(PIP_REQUIRES, TEST_REQUIRES),
classifiers=['Development Status :: 4 - Beta',
'Framework :: Django',
'Intended Audience :: Developers',
diff --git a/tools/pip-requires b/tools/pip-requires
index 9584143ff..6c52d96ba 100644
--- a/tools/pip-requires
+++ b/tools/pip-requires
@@ -4,6 +4,6 @@ python-cloudfiles
python-dateutil
# Horizon Non-pip Requirements
--e git+https://github.com/openstack/python-novaclient.git#egg=python-novaclient
--e git+https://github.com/openstack/python-keystoneclient.git#egg=python-keystoneclient
--e git+https://github.com/openstack/python-glanceclient.git#egg=python-glanceclient
+https://github.com/openstack/python-novaclient/zipball/master#egg=python-novaclient
+https://github.com/openstack/python-keystoneclient/zipball/master#egg=python-keystoneclient
+https://github.com/openstack/python-glanceclient/zipball/master#egg=python-glanceclient
diff --git a/tools/test-requires b/tools/test-requires
index c33108bf9..04bf506e6 100644
--- a/tools/test-requires
+++ b/tools/test-requires
@@ -1,14 +1,17 @@
+distribute>=0.6.24
+
# Testing Requirements
coverage
django-nose
mox
+netaddr
nose
nose-exclude
+nosexcover
+openstack.nose_plugin
pep8
pylint
-distribute>=0.6.24
selenium
-netaddr
# Docs Requirements
sphinx
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 000000000..0913e1e38
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,46 @@
+[tox]
+envlist = py26,py27,pep8
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+ NOSE_WITH_OPENSTACK=1
+ NOSE_OPENSTACK_COLOR=1
+ NOSE_OPENSTACK_RED=0.05
+ NOSE_OPENSTACK_YELLOW=0.025
+ NOSE_OPENSTACK_SHOW_ELAPSED=1
+deps = -r{toxinidir}/tools/pip-requires
+ -r{toxinidir}/tools/test-requires
+commands = /bin/bash run_tests.sh -N
+
+[testenv:pep8]
+deps = pep8
+commands = /bin/bash run_tests.sh -N --pep8
+
+[testenv:venv]
+commands = {posargs}
+
+[testenv:cover]
+commands = /bin/bash run_tests.sh -N --coverage
+
+[tox:jenkins]
+downloadcache = ~/cache/pip
+
+[testenv:jenkins26]
+setenv = NOSE_WITH_XUNIT=1
+basepython = python2.6
+
+[testenv:jenkins27]
+setenv = NOSE_WITH_XUNIT=1
+basepython = python2.7
+
+[testenv:jenkinspep8]
+setenv = NOSE_WITH_XUNIT=1
+commands = /bin/bash run_tests.sh -N --pep8
+
+[testenv:jenkinscover]
+setenv = NOSE_WITH_XUNIT=1
+commands = /bin/bash run_tests.sh -N --coverage
+
+[testenv:jenkinsvenv]
+setenv = NOSE_WITH_XUNIT=1
+commands = {posargs}