Skip to content

Commit e8f7de6

Browse files
authored
Merge pull request HypothesisWorks#1014 from HypothesisWorks/fast-builds
Skip running tests if we're sure there aren't test relevant changes
2 parents 985e27e + ba2e9f1 commit e8f7de6

6 files changed

+148
-16
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ env:
6767
- TASK=deploy
6868

6969
script:
70-
- make $TASK
70+
- python scripts/run_travis_make_task.py
7171

7272
matrix:
7373
fast_finish: true

circle.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
test:
22
override:
3-
- scripts/run-circle.sh
3+
- scripts/run_circle.py
44

55
machine:
66
# Courtesy of https://pewpewthespells.com/blog/building_python_on_circleci.html

scripts/hypothesistooling.py

+73
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,76 @@ def update_for_pending_release():
327327
'commit', '-m',
328328
'Bump version to %s and update changelog\n\n[skip ci]' % (__version__,)
329329
)
330+
331+
332+
def could_affect_tests(path):
333+
"""Does this file have any effect on test results?"""
334+
# RST files are the input to some tests -- in particular, the
335+
# documentation build and doctests. Both of those jobs are always run,
336+
# so we can ignore their effect here.
337+
#
338+
# IPython notebooks aren't currently used in any tests.
339+
if path.endswith(('.rst', '.ipynb')):
340+
return False
341+
342+
# These files exist but have no effect on tests.
343+
if path in ('CITATION', 'LICENSE.txt', ):
344+
return False
345+
346+
# We default to marking a file "interesting" unless we know otherwise --
347+
# it's better to run tests that could have been skipped than skip tests
348+
# when they needed to be run.
349+
return True
350+
351+
352+
def changed_files_from_master():
353+
"""Returns a list of files which have changed between a branch and
354+
master."""
355+
files = set()
356+
command = ['git', 'diff', '--name-only', 'HEAD', 'master']
357+
diff_output = subprocess.check_output(command).decode('ascii')
358+
for line in diff_output.splitlines():
359+
filepath = line.strip()
360+
if filepath:
361+
files.add(filepath)
362+
return files
363+
364+
365+
def should_run_ci_task(task, is_pull_request):
366+
"""Given a task name, should we run this task?"""
367+
if not is_pull_request:
368+
print('We only skip tests if the job is a pull request.')
369+
return True
370+
371+
# These tests are usually fast; we always run them rather than trying
372+
# to keep up-to-date rules of exactly which changed files mean they
373+
# should run.
374+
if task in [
375+
'check-pyup-yml',
376+
'check-release-file',
377+
'check-shellcheck',
378+
'documentation',
379+
'lint',
380+
]:
381+
print('We always run the %s task.' % task)
382+
return True
383+
384+
# The remaining tasks are all some sort of test of Hypothesis
385+
# functionality. Since it's better to run tests when we don't need to
386+
# than skip tests when it was important, we remove any files which we
387+
# know are safe to ignore, and run tests if there's anything left.
388+
changed_files = changed_files_from_master()
389+
390+
interesting_changed_files = [
391+
f for f in changed_files if could_affect_tests(f)
392+
]
393+
394+
if interesting_changed_files:
395+
print(
396+
'Changes to the following files mean we need to run tests: %s' %
397+
', '.join(interesting_changed_files)
398+
)
399+
return True
400+
else:
401+
print('There are no changes which would need a test run.')
402+
return False

scripts/run-circle.sh

-14
This file was deleted.

scripts/run_circle.py

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python
2+
3+
# coding=utf-8
4+
#
5+
# This file is part of Hypothesis, which may be found at
6+
# https://github.com/HypothesisWorks/hypothesis-python
7+
#
8+
# Most of this work is copyright (C) 2013-2017 David R. MacIver
9+
# (david@drmaciver.com), but it contains contributions by others. See
10+
# CONTRIBUTING.rst for a full list of people who may hold copyright, and
11+
# consult the git log if you need to determine who owns an individual
12+
# contribution.
13+
#
14+
# This Source Code Form is subject to the terms of the Mozilla Public License,
15+
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
16+
# obtain one at http://mozilla.org/MPL/2.0/.
17+
#
18+
# END HEADER
19+
20+
from __future__ import division, print_function, absolute_import
21+
22+
import os
23+
import sys
24+
import subprocess
25+
26+
from hypothesistooling import should_run_ci_task
27+
28+
if __name__ == '__main__':
29+
30+
if (
31+
os.environ['CIRCLE_BRANCH'] != 'master' and
32+
os.environ['CI_PULL_REQUEST'] == ''
33+
):
34+
print('We only run CI builds on the master branch or in pull requests')
35+
sys.exit(0)
36+
37+
is_pull_request = (os.environ['CI_PULL_REQUEST'] != '')
38+
39+
for task in ['check-pypy', 'check-py36', 'check-py27']:
40+
if should_run_ci_task(task=task, is_pull_request=is_pull_request):
41+
subprocess.check_call(['make', task])

scripts/run_travis_make_task.py

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env python
2+
3+
# coding=utf-8
4+
#
5+
# This file is part of Hypothesis, which may be found at
6+
# https://github.com/HypothesisWorks/hypothesis-python
7+
#
8+
# Most of this work is copyright (C) 2013-2017 David R. MacIver
9+
# (david@drmaciver.com), but it contains contributions by others. See
10+
# CONTRIBUTING.rst for a full list of people who may hold copyright, and
11+
# consult the git log if you need to determine who owns an individual
12+
# contribution.
13+
#
14+
# This Source Code Form is subject to the terms of the Mozilla Public License,
15+
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
16+
# obtain one at http://mozilla.org/MPL/2.0/.
17+
#
18+
# END HEADER
19+
20+
from __future__ import division, print_function, absolute_import
21+
22+
import os
23+
import subprocess
24+
25+
from hypothesistooling import should_run_ci_task
26+
27+
if __name__ == '__main__':
28+
is_pull_request = (os.environ.get('TRAVIS_EVENT_TYPE') == 'pull_request')
29+
task = os.environ['TASK']
30+
31+
if should_run_ci_task(task=task, is_pull_request=is_pull_request):
32+
subprocess.check_call(['make', task])

0 commit comments

Comments
 (0)