Skip to content

Commit dadf1a6

Browse files
committed
Collapsing sub-package explosion in Travis config into a script.
This script will be extended a great deal in coming commits.
1 parent 938ac21 commit dadf1a6

File tree

3 files changed

+180
-53
lines changed

3 files changed

+180
-53
lines changed

.travis.yml

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5,53 +5,11 @@ install:
55
- pip install --upgrade pip tox
66

77
script:
8-
- (cd core && tox -e py27)
9-
- (cd bigtable && tox -e py27)
10-
- (cd storage && tox -e py27)
11-
- (cd datastore && tox -e py27)
12-
- (cd bigquery && tox -e py27)
13-
- (cd pubsub && tox -e py27)
14-
- (cd logging && tox -e py27)
15-
- (cd dns && tox -e py27)
16-
- (cd language && tox -e py27)
17-
- (cd error_reporting && tox -e py27)
18-
- (cd resource_manager && tox -e py27)
19-
- (cd monitoring && tox -e py27)
20-
- (cd vision && tox -e py27)
21-
- (cd translate && tox -e py27)
22-
- (cd speech && tox -e py27)
23-
- (cd core && tox -e py34)
24-
- (cd bigtable && tox -e py34)
25-
- (cd storage && tox -e py34)
26-
- (cd datastore && tox -e py34)
27-
- (cd bigquery && tox -e py34)
28-
- (cd pubsub && tox -e py34)
29-
- (cd logging && tox -e py34)
30-
- (cd dns && tox -e py34)
31-
- (cd language && tox -e py34)
32-
- (cd error_reporting && tox -e py34)
33-
- (cd resource_manager && tox -e py34)
34-
- (cd monitoring && tox -e py34)
35-
- (cd vision && tox -e py34)
36-
- (cd translate && tox -e py34)
37-
- (cd speech && tox -e py34)
8+
- tox -e py27
9+
- tox -e py34
3810
- tox -e lint
3911
- tox -e cover
40-
- (cd core && tox -e cover)
41-
- (cd bigtable && tox -e cover)
42-
- (cd storage && tox -e cover)
43-
- (cd datastore && tox -e cover)
44-
- (cd bigquery && tox -e cover)
45-
- (cd pubsub && tox -e cover)
46-
- (cd logging && tox -e cover)
47-
- (cd dns && tox -e cover)
48-
- (cd language && tox -e cover)
49-
- (cd error_reporting && tox -e cover)
50-
- (cd resource_manager && tox -e cover)
51-
- (cd monitoring && tox -e cover)
52-
- (cd vision && tox -e cover)
53-
- (cd translate && tox -e cover)
54-
- (cd speech && tox -e cover)
12+
- tox -e isolated-cover
5513
- tox -e system-tests
5614
- tox -e system-tests3
5715
- scripts/update_docs.sh

scripts/run_unit_tests.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Copyright 2016 Google Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""Script to run unit tests for the entire project.
16+
17+
This script orchestrates stepping into each sub-package and
18+
running tests. It also allows running a limited subset of tests
19+
in cases where such a limited subset can be identified.
20+
"""
21+
22+
from __future__ import print_function
23+
24+
import argparse
25+
import os
26+
import subprocess
27+
import sys
28+
29+
30+
PROJECT_ROOT = os.path.abspath(
31+
os.path.join(os.path.dirname(__file__), '..'))
32+
IGNORED_DIRECTORIES = (
33+
'appveyor',
34+
'docs',
35+
'scripts',
36+
'system_tests',
37+
)
38+
39+
40+
def check_output(*args):
41+
"""Run a command on the operation system.
42+
43+
:type args: tuple
44+
:param args: Keyword arguments to pass to ``subprocess.check_output``.
45+
46+
:rtype: str
47+
:returns: The raw STDOUT from the command (converted from bytes
48+
if necessary).
49+
"""
50+
cmd_output = subprocess.check_output(args)
51+
# On Python 3, this returns bytes (from STDOUT), so we
52+
# convert to a string.
53+
cmd_output = cmd_output.decode('utf-8')
54+
# Also strip the output since it usually has a trailing newline.
55+
return cmd_output.strip()
56+
57+
58+
def get_package_directories():
59+
"""Get a list of directories containing sub-packages.
60+
61+
:rtype: list
62+
:returns: A list of all sub-package directories.
63+
"""
64+
# Run ls-tree with
65+
# -d: For directories only
66+
# --name-only: No extra info like the type/hash/permission bits.
67+
# --full-name: Give path relative to root, rather than cwd.
68+
ls_tree_out = check_output(
69+
'git', 'ls-tree',
70+
'-d', '--name-only', '--full-name',
71+
'HEAD', PROJECT_ROOT)
72+
result = []
73+
for package in ls_tree_out.split('\n'):
74+
if package not in IGNORED_DIRECTORIES:
75+
result.append(package)
76+
return result
77+
78+
79+
def run_package(package, tox_env):
80+
"""Run tox environment for a given package.
81+
82+
:type package: str
83+
:param package: The name of the subdirectory which holds the sub-package.
84+
This will be a path relative to ``PROJECT_ROOT``.
85+
86+
:type tox_env: str
87+
:param tox_env: The ``tox`` environment(s) to run in each sub-package.
88+
89+
:rtype: bool
90+
:returns: Flag indicating if the test run succeeded.
91+
"""
92+
curr_dir = os.getcwd()
93+
package_dir = os.path.join(PROJECT_ROOT, package)
94+
try:
95+
os.chdir(package_dir)
96+
return_code = subprocess.call(['tox', '-e', tox_env])
97+
return return_code == 0
98+
finally:
99+
os.chdir(curr_dir)
100+
101+
102+
def get_parser():
103+
"""Get simple ``argparse`` parser to determine configuration.
104+
105+
:rtype: :class:`argparse.ArgumentParser`
106+
:returns: The parser for this script.
107+
"""
108+
description = 'Run tox environment(s) in all sub-packages.'
109+
parser = argparse.ArgumentParser(description=description)
110+
parser.add_argument(
111+
'--tox-env', dest='tox_env', default='py27',
112+
help='The tox environment(s) to run in sub-packages.')
113+
return parser
114+
115+
116+
def get_tox_env():
117+
"""Get the environment to be used with ``tox``.
118+
119+
:rtype: str
120+
:returns: The current ``tox`` environment to be used, e.g. ``"py27"``.
121+
"""
122+
parser = get_parser()
123+
args = parser.parse_args()
124+
return args.tox_env
125+
126+
127+
def main():
128+
"""Run all the unit tests that need to be run."""
129+
packages_to_run = get_package_directories()
130+
if not packages_to_run:
131+
print('No tests to run.')
132+
return
133+
134+
tox_env = get_tox_env()
135+
failed_packages = []
136+
for package in packages_to_run:
137+
succeeded = run_package(package, tox_env)
138+
if not succeeded:
139+
failed_packages.append(package)
140+
141+
if failed_packages:
142+
msg_parts = ['Sub-packages failed:']
143+
for package in failed_packages:
144+
msg_parts.append('- ' + package)
145+
msg = '\n'.join(msg_parts)
146+
print(msg, file=sys.stderr)
147+
sys.exit(len(failed_packages))
148+
149+
150+
if __name__ == '__main__':
151+
main()

tox.ini

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,35 @@ covercmd =
112112
speech/unit_tests
113113
coverage report --show-missing --fail-under=100
114114

115-
[testenv]
115+
[testenv:py27]
116116
commands =
117-
py.test --quiet {posargs} unit_tests
117+
python {toxinidir}/scripts/run_unit_tests.py --tox-env py27
118118
deps =
119-
{[testing]deps}
119+
skip_install = True
120+
121+
[testenv:py34]
122+
commands =
123+
python {toxinidir}/scripts/run_unit_tests.py --tox-env py34
124+
deps =
125+
skip_install = True
126+
127+
[testenv:py35]
128+
commands =
129+
python {toxinidir}/scripts/run_unit_tests.py --tox-env py35
130+
deps =
131+
skip_install = True
132+
133+
[testenv:isolated-cover]
134+
commands =
135+
python {toxinidir}/scripts/run_unit_tests.py --tox-env cover
136+
deps =
137+
skip_install = True
120138

121139
[testenv:py27-pandas]
122140
basepython =
123141
python2.7
124142
deps =
125-
{[testenv]deps}
143+
{[testing]deps}
126144
pandas
127145

128146
[testenv:cover]
@@ -131,7 +149,7 @@ basepython =
131149
commands =
132150
{[testing]covercmd}
133151
deps =
134-
{[testenv]deps}
152+
{[testing]deps}
135153
coverage
136154
pytest-cov
137155

@@ -174,7 +192,7 @@ commands =
174192
sphinx-build -W -b html -d docs/_build/doctrees docs docs/_build/html
175193
python {toxinidir}/scripts/verify_included_modules.py --build-root _build
176194
deps =
177-
{[testenv]deps}
195+
{[testing]deps}
178196
Sphinx
179197
sphinx_rtd_theme
180198
passenv = {[testenv:system-tests]passenv} SPHINX_RELEASE READTHEDOCS
@@ -210,7 +228,7 @@ commands =
210228
python {toxinidir}/scripts/pycodestyle_on_repo.py
211229
python {toxinidir}/scripts/run_pylint.py
212230
deps =
213-
{[testenv]deps}
231+
{[testing]deps}
214232
pycodestyle
215233
pylint >= 1.6.4
216234
passenv = {[testenv:system-tests]passenv}
@@ -231,7 +249,7 @@ passenv = {[testenv:system-tests]passenv}
231249

232250
[emulator]
233251
deps =
234-
{[testenv]deps}
252+
{[testing]deps}
235253
psutil
236254
setenv =
237255
GOOGLE_CLOUD_NO_PRINT=true

0 commit comments

Comments
 (0)