Skip to content

Commit 95c2f27

Browse files
committed
Add openstack-common and test infrastructure.
Fix pep8 errors (project is pep8 clean now). Update setup.py to use openstack-common style dependencies. Remove the unused novaclient dependency. Change the keystoneclient dependency to a git URL. Add test-requires, and move some pip-requires dependencies into it. Remove the test_utils unit test which wasn't testing anything that is actually present in the project. Add the test_authors unit test. Use tox for running tests locally. See: http://wiki.openstack.org/ProjectTestingInterface Tox can manage virtualenvs, and is currently doing so for running tests in Jenkins. It's just as, or more, useful for running tests locally, so this starts the migration from the run_tests system to tox. The goal is to reduce duplicate testing infrastructure, and get what's running locally on developer workstations as close to what is run by Jenkins as possible. Run_tests.sh will now call tox to facilitate the transition for developers used to typing "run_tests.sh". Developers will need tox installed on their workstations. It can be installed from PyPI with "pip install tox". run_tests.sh outputs those instructions if tox is not present. New facilities are available using tox directly, including: tox -e py26 # run tests under python 2.6 tox -e py27 # run tests under python 2.7 tox -e pep8 # run pep8 tests tox # run all of the above tox -e venv foo # run the command "foo" inside a virtualenv The OpenStack nose plugin is used when running tox from the command line, so the enhanced, colorized output is visible to developers running the test suite locally. However, when Jenkins runs tox, xunit output will be used instead, which is natively understood by jenkins and much more readable in that context. Change-Id: Ib627be3b37b5a09d3795006d412ddcc35f8c6c1e
1 parent 9c945be commit 95c2f27

File tree

20 files changed

+353
-243
lines changed

20 files changed

+353
-243
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@
77
build
88
dist
99
python_openstackclient.egg-info
10+
.tox/
11+
ChangeLog

.gitreview

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[gerrit]
2+
host=review.openstack.org
3+
port=29418
4+
project=openstack/python-openstackclient.git

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
Dean Troyer <dtroyer@gmail.com>
2+
James E. Blair <jeblair@hp.com>

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
include AUTHORS
22
include LICENSE
33
include README.rst
4-
recursive-inlcude docs *
4+
recursive-include docs *
55
recursive-include tests *

openstack-common.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[DEFAULT]
2+
3+
# The list of modules to copy from openstack-common
4+
modules=setup
5+
6+
# The base module to hold the copy of openstack.common
7+
base=openstackclient

openstackclient/compute/v2/server.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def _find_server(cs, server):
2929
"""Get a server by name or ID."""
3030
return utils.find_resource(cs.servers, server)
3131

32+
3233
def _print_server(cs, server):
3334
# By default when searching via name we will do a
3435
# findall(name=blah) and due a REST /details which is not the same
@@ -56,6 +57,7 @@ def _print_server(cs, server):
5657

5758
utils.print_dict(info)
5859

60+
5961
class List_Server(command.OpenStackCommand):
6062
"List server command."
6163

@@ -74,6 +76,7 @@ def get_parser(self, prog_name):
7476
def run(self, parsed_args):
7577
self.log.info('v2.List_Server.run(%s)' % parsed_args)
7678

79+
7780
class Show_Server(command.OpenStackCommand):
7881
"Show server command."
7982

openstackclient/openstack/__init__.py

Whitespace-only changes.

openstackclient/openstack/common/__init__.py

Whitespace-only changes.
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# vim: tabstop=4 shiftwidth=4 softtabstop=4
2+
3+
# Copyright 2011 OpenStack LLC.
4+
# All Rights Reserved.
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
7+
# not use this file except in compliance with the License. You may obtain
8+
# a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15+
# License for the specific language governing permissions and limitations
16+
# under the License.
17+
18+
"""
19+
Utilities with minimum-depends for use in setup.py
20+
"""
21+
22+
import os
23+
import re
24+
import subprocess
25+
26+
27+
def parse_mailmap(mailmap='.mailmap'):
28+
mapping = {}
29+
if os.path.exists(mailmap):
30+
fp = open(mailmap, 'r')
31+
for l in fp:
32+
l = l.strip()
33+
if not l.startswith('#') and ' ' in l:
34+
canonical_email, alias = l.split(' ')
35+
mapping[alias] = canonical_email
36+
return mapping
37+
38+
39+
def canonicalize_emails(changelog, mapping):
40+
""" Takes in a string and an email alias mapping and replaces all
41+
instances of the aliases in the string with their real email
42+
"""
43+
for alias, email in mapping.iteritems():
44+
changelog = changelog.replace(alias, email)
45+
return changelog
46+
47+
48+
# Get requirements from the first file that exists
49+
def get_reqs_from_files(requirements_files):
50+
reqs_in = []
51+
for requirements_file in requirements_files:
52+
if os.path.exists(requirements_file):
53+
return open(requirements_file, 'r').read().split('\n')
54+
return []
55+
56+
57+
def parse_requirements(requirements_files=['requirements.txt',
58+
'tools/pip-requires']):
59+
requirements = []
60+
for line in get_reqs_from_files(requirements_files):
61+
if re.match(r'\s*-e\s+', line):
62+
requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1',
63+
line))
64+
elif re.match(r'\s*-f\s+', line):
65+
pass
66+
else:
67+
requirements.append(line)
68+
69+
return requirements
70+
71+
72+
def parse_dependency_links(requirements_files=['requirements.txt',
73+
'tools/pip-requires']):
74+
dependency_links = []
75+
for line in get_reqs_from_files(requirements_files):
76+
if re.match(r'(\s*#)|(\s*$)', line):
77+
continue
78+
if re.match(r'\s*-[ef]\s+', line):
79+
dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line))
80+
return dependency_links
81+
82+
83+
def write_requirements():
84+
venv = os.environ.get('VIRTUAL_ENV', None)
85+
if venv is not None:
86+
with open("requirements.txt", "w") as req_file:
87+
output = subprocess.Popen(["pip", "-E", venv, "freeze", "-l"],
88+
stdout=subprocess.PIPE)
89+
requirements = output.communicate()[0].strip()
90+
req_file.write(requirements)
91+
92+
93+
def _run_shell_command(cmd):
94+
output = subprocess.Popen(["/bin/sh", "-c", cmd],
95+
stdout=subprocess.PIPE)
96+
return output.communicate()[0].strip()
97+
98+
99+
def write_vcsversion(location):
100+
""" Produce a vcsversion dict that mimics the old one produced by bzr
101+
"""
102+
if os.path.isdir('.git'):
103+
branch_nick_cmd = 'git branch | grep -Ei "\* (.*)" | cut -f2 -d" "'
104+
branch_nick = _run_shell_command(branch_nick_cmd)
105+
revid_cmd = "git rev-parse HEAD"
106+
revid = _run_shell_command(revid_cmd).split()[0]
107+
revno_cmd = "git log --oneline | wc -l"
108+
revno = _run_shell_command(revno_cmd)
109+
with open(location, 'w') as version_file:
110+
version_file.write("""
111+
# This file is automatically generated by setup.py, So don't edit it. :)
112+
version_info = {
113+
'branch_nick': '%s',
114+
'revision_id': '%s',
115+
'revno': %s
116+
}
117+
""" % (branch_nick, revid, revno))
118+
119+
120+
def write_git_changelog():
121+
"""Write a changelog based on the git changelog"""
122+
if os.path.isdir('.git'):
123+
git_log_cmd = 'git log --stat'
124+
changelog = _run_shell_command(git_log_cmd)
125+
mailmap = parse_mailmap()
126+
with open("ChangeLog", "w") as changelog_file:
127+
changelog_file.write(canonicalize_emails(changelog, mailmap))
128+
129+
130+
def generate_authors():
131+
"""Create AUTHORS file using git commits"""
132+
jenkins_email = 'jenkins@review.openstack.org'
133+
if os.path.isdir('.git'):
134+
# don't include jenkins email address in AUTHORS file
135+
git_log_cmd = "git log --format='%aN <%aE>' | sort -u | " \
136+
"grep -v " + jenkins_email
137+
changelog = _run_shell_command(git_log_cmd)
138+
mailmap = parse_mailmap()
139+
with open("AUTHORS", "w") as authors_file:
140+
authors_file.write(canonicalize_emails(changelog, mailmap))

openstackclient/shell.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,20 @@ def build_option_parser(self, description, version):
9595
parser.add_argument('--os-identity-api-version',
9696
metavar='<identity-api-version>',
9797
default=env('OS_IDENTITY_API_VERSION', default='2.0'),
98-
help='Identity API version, default=2.0 (Env: OS_IDENTITY_API_VERSION)')
98+
help='Identity API version, default=2.0 '\
99+
'(Env: OS_IDENTITY_API_VERSION)')
99100

100101
parser.add_argument('--os-compute-api-version',
101102
metavar='<compute-api-version>',
102103
default=env('OS_COMPUTE_API_VERSION', default='2'),
103-
help='Compute API version, default=2 (Env: OS_COMPUTE_API_VERSION)')
104+
help='Compute API version, default=2 '\
105+
'(Env: OS_COMPUTE_API_VERSION)')
104106

105107
parser.add_argument('--os-image-api-version',
106108
metavar='<image-api-version>',
107109
default=env('OS_IMAGE_API_VERSION', default='1.0'),
108-
help='Image API version, default=1.0 (Env: OS_IMAGE_API_VERSION)')
110+
help='Image API version, default=1.0 '\
111+
'(Env: OS_IMAGE_API_VERSION)')
109112

110113
parser.add_argument('--os-token', metavar='<token>',
111114
default=env('OS_TOKEN'),
@@ -130,7 +133,10 @@ def prepare_to_run_command(self, cmd):
130133
}
131134

132135
if self.options.debug:
133-
print "API: Identity=%s Compute=%s Image=%s" % (self.api_version['identity'], self.api_version['compute'], self.api_version['image'])
136+
print "API: Identity=%s Compute=%s Image=%s" % (
137+
self.api_version['identity'],
138+
self.api_version['compute'],
139+
self.api_version['image'])
134140
print "cmd: %s" % cmd
135141

136142
# do checking of os_username, etc here
@@ -169,7 +175,8 @@ def prepare_to_run_command(self, cmd):
169175
auth_url=kwargs.get('auth_url'),
170176
)
171177
token = self.auth_client.auth_token
172-
endpoint = self.auth_client.service_catalog.url_for(service_type=cmd.api)
178+
endpoint = self.auth_client.service_catalog.url_for(
179+
service_type=cmd.api)
173180

174181
if self.options.debug:
175182
print "api: %s" % cmd.api

0 commit comments

Comments
 (0)