Skip to content

Commit

Permalink
Running restricted set of unit tests on Travis PR.
Browse files Browse the repository at this point in the history
  • Loading branch information
dhermes committed Oct 3, 2016
1 parent 8fcf9ef commit 324a2c3
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 19 deletions.
53 changes: 35 additions & 18 deletions scripts/run_unit_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
import subprocess
import sys

from script_utils import check_output
from script_utils import get_changed_packages
from script_utils import in_travis
from script_utils import in_travis_pr
from script_utils import travis_branch


PROJECT_ROOT = os.path.abspath(
os.path.join(os.path.dirname(__file__), '..'))
Expand All @@ -44,24 +50,6 @@
UNSET_SENTINEL = object() # Sentinel for argparser


def check_output(*args):
"""Run a command on the operation system.
:type args: tuple
:param args: Keyword arguments to pass to ``subprocess.check_output``.
:rtype: str
:returns: The raw STDOUT from the command (converted from bytes
if necessary).
"""
cmd_output = subprocess.check_output(args)
# On Python 3, this returns bytes (from STDOUT), so we
# convert to a string.
cmd_output = cmd_output.decode('utf-8')
# Also strip the output since it usually has a trailing newline.
return cmd_output.strip()


def get_package_directories():
"""Get a list of directories containing sub-packages.
Expand All @@ -83,6 +71,30 @@ def get_package_directories():
return result


def get_travis_directories(package_list):
"""Get list of packages that need to be tested on Travis CI.
See: https://travis-ci.com/
If the current Travis build is for a pull request (PR), this will
limit the directories to the ones impacted by the PR. Otherwise
it will just test all package directories.
:type package_list: list
:param package_list: The list of **all** valid packages with unit tests.
:rtype: list
:returns: A list of all package directories where tests
need to be run.
"""
if in_travis_pr():
pr_against_branch = travis_branch()
return get_changed_packages('HEAD', pr_against_branch,
package_list)
else:
return package_list


def verify_packages(subset, all_packages):
"""Verify that a subset of packages are among all packages.
Expand All @@ -107,6 +119,9 @@ def get_test_packages():
Filters the package list in the following order:
* Check command line for packages passed in as positional arguments
* Check if in Travis, then limit the subset based on changes
in a Pull Request ("push" builds to branches may not have
any filtering)
* Just use all packages
:rtype: list
Expand All @@ -120,6 +135,8 @@ def get_test_packages():
if args.packages is not UNSET_SENTINEL:
verify_packages(args.packages, all_packages)
return sorted(args.packages)
elif in_travis():
return get_travis_directories(all_packages)
else:
return all_packages

Expand Down
78 changes: 77 additions & 1 deletion scripts/script_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Common helpers for testing scripts."""

import os
import subprocess


LOCAL_REMOTE_ENV = 'GOOGLE_CLOUD_TESTING_REMOTE'
Expand Down Expand Up @@ -81,5 +82,80 @@ def travis_branch():
:rtype: str
:returns: The name of the branch the current pull request is
changed against.
:raises: :class:`~exceptions.OSError` if the ``TRAVIS_BRANCH_ENV``
environment variable isn't set during a pull request
build.
"""
return os.getenv(TRAVIS_BRANCH_ENV)
try:
return os.environ[TRAVIS_BRANCH_ENV]
except KeyError:
msg = ('Pull request build does not have an '
'associated branch set (via %s)') % (TRAVIS_BRANCH_ENV,)
raise OSError(msg)


def check_output(*args):
"""Run a command on the operation system.
:type args: tuple
:param args: Arguments to pass to ``subprocess.check_output``.
:rtype: str
:returns: The raw STDOUT from the command (converted from bytes
if necessary).
"""
cmd_output = subprocess.check_output(args)
# On Python 3, this returns bytes (from STDOUT), so we
# convert to a string.
cmd_output = cmd_output.decode('utf-8')
# Also strip the output since it usually has a trailing newline.
return cmd_output.strip()


def rootname(filename):
"""Get the root directory that a file is contained in.
:type filename: str
:param filename: The path / name of a file.
:rtype: str
:returns: The root directory containing the file.
"""
if os.path.sep not in filename:
return ''
else:
file_root, _ = filename.split(os.path.sep, 1)
return file_root


def get_changed_packages(blob_name1, blob_name2, package_list):
"""Get a list of packages which have changed between two changesets.
:type blob_name1: str
:param blob_name1: The name of a commit hash or branch name or other
``git`` artifact.
:type blob_name2: str
:param blob_name2: The name of a commit hash or branch name or other
``git`` artifact.
:type package_list: list
:param package_list: The list of **all** valid packages with unit tests.
:rtype: list
:returns: A list of all package directories that have changed
between ``blob_name1`` and ``blob_name2``. Starts
with a list of valid packages (``package_list``)
and filters out the unchanged directories.
"""
changed_files = check_output(
'git', 'diff', '--name-only', blob_name1, blob_name2)
changed_files = changed_files.split('\n')

result = set()
for filename in changed_files:
file_root = rootname(filename)
if file_root in package_list:
result.add(file_root)

return sorted(result)
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ skip_install =
py34: True
py35: True
isolated-cover: True
passenv = TRAVIS*

[testenv:isolated-cover]
commands =
Expand Down

0 comments on commit 324a2c3

Please sign in to comment.