##// END OF EJS Templates
Fix magic decorator logic so we correctly fetch bound instance methods.
Fix magic decorator logic so we correctly fetch bound instance methods.

File last commit:

r6754:3adb246f
r6924:07b7cbf8
Show More
test_pr.py
244 lines | 8.1 KiB | text/x-python | PythonLexer
Fernando Perez
Give test_pr proper env call to python interpreter....
r6745 #!/usr/bin/env python
Thomas Kluyver
Add script to test pull request
r6686 """
This is a script for testing pull requests for IPython. It merges the pull
request with current master, installs and tests on all available versions of
Python, and posts the results to Gist if any tests fail.
Usage:
python test_pr.py 1657
"""
from __future__ import print_function
import errno
from glob import glob
Thomas Kluyver
Add option to test without posting results.
r6711 import io
Thomas Kluyver
Add script to test pull request
r6686 import json
import os
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 import pickle
Thomas Kluyver
Print missing libraries and platform.
r6692 import re
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 import requests
Thomas Kluyver
Add script to test pull request
r6686 import shutil
MinRK
time test run
r6736 import time
Thomas Kluyver
Add script to test pull request
r6686 from subprocess import call, check_call, check_output, PIPE, STDOUT, CalledProcessError
Thomas Kluyver
Add option to test without posting results.
r6711 import sys
Thomas Kluyver
Add script to test pull request
r6686
Thomas Kluyver
Add option to test without posting results.
r6711 import gh_api
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694
Thomas Kluyver
Add script to test pull request
r6686 basedir = os.path.join(os.path.expanduser("~"), ".ipy_pr_tests")
repodir = os.path.join(basedir, "ipython")
ipy_repository = 'git://github.com/ipython/ipython.git'
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 gh_project="ipython/ipython"
Thomas Kluyver
Add script to test pull request
r6686
supported_pythons = ['python2.6', 'python2.7', 'python3.1', 'python3.2']
unavailable_pythons = []
def available_python_versions():
"""Get the executable names of available versions of Python on the system.
"""
del unavailable_pythons[:]
for py in supported_pythons:
try:
check_call([py, '-c', 'import nose'], stdout=PIPE)
yield py
except (OSError, CalledProcessError):
unavailable_pythons.append(py)
venvs = []
def setup():
"""Prepare the repository and virtualenvs."""
global venvs
try:
os.mkdir(basedir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
os.chdir(basedir)
# Delete virtualenvs and recreate
for venv in glob('venv-*'):
shutil.rmtree(venv)
for py in available_python_versions():
check_call(['virtualenv', '-p', py, '--system-site-packages', 'venv-%s' % py])
venvs.append((py, 'venv-%s' % py))
# Check out and update the repository
if not os.path.exists('ipython'):
check_call(['git', 'clone', ipy_repository])
os.chdir(repodir)
check_call(['git', 'checkout', 'master'])
check_call(['git', 'pull', ipy_repository, 'master'])
os.chdir(basedir)
Thomas Kluyver
Print missing libraries and platform.
r6692 missing_libs_re = re.compile(r"Tools and libraries NOT available at test time:\n"
r"\s*(.*?)\n")
def get_missing_libraries(log):
m = missing_libs_re.search(log)
if m:
return m.group(1)
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 def get_branch(repo, branch, owner, mergeable):
Thomas Kluyver
Add script to test pull request
r6686 os.chdir(repodir)
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 if mergeable:
merged_branch = "%s-%s" % (owner, branch)
# Delete the branch first
call(['git', 'branch', '-D', merged_branch])
check_call(['git', 'checkout', '-b', merged_branch])
MinRK
add --no-ff to git pull in test_pr...
r6754 check_call(['git', 'pull', '--no-ff', '--no-commit', repo, branch])
MinRK
separate pull from commit in test_pr
r6735 check_call(['git', 'commit', '-m', "merge %s/%s" % (repo, branch)])
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 else:
# Fetch the branch without merging it.
check_call(['git', 'fetch', repo, branch])
check_call(['git', 'checkout', 'FETCH_HEAD'])
Thomas Kluyver
Add script to test pull request
r6686 os.chdir(basedir)
def run_tests(venv):
py = os.path.join(basedir, venv, 'bin', 'python')
print(py)
os.chdir(repodir)
MinRK
clean build dir in test_pr
r6734 # cleanup build-dir
if os.path.exists('build'):
shutil.rmtree('build')
Thomas Kluyver
Add script to test pull request
r6686 check_call([py, 'setup.py', 'install'])
os.chdir(basedir)
iptest = os.path.join(basedir, venv, 'bin', 'iptest')
if not os.path.exists(iptest):
iptest = os.path.join(basedir, venv, 'bin', 'iptest3')
print("\nRunning tests, this typically takes a few minutes...")
try:
return True, check_output([iptest], stderr=STDOUT).decode('utf-8')
except CalledProcessError as e:
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 return False, e.output.decode('utf-8')
Thomas Kluyver
Add script to test pull request
r6686
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 def markdown_format(pr, results_urls):
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 def format_result(py, passed, gist_url, missing_libraries):
s = "* %s: " % py
if passed:
s += "OK"
else:
s += "Failed, log at %s" % gist_url
if missing_libraries:
s += " (libraries not available: " + missing_libraries + ")"
return s
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 if pr['mergeable']:
com = pr['head']['sha'][:7] + " merged into master"
else:
com = pr['head']['sha'][:7] + " (can't merge cleanly)"
lines = ["**Test results for commit %s**" % com,
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 "Platform: " + sys.platform,
""] + \
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 [format_result(*r) for r in results_urls] + \
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 ["",
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 "Not available for testing: " + ", ".join(unavailable_pythons)]
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694 return "\n".join(lines)
def post_results_comment(pr, results, num):
body = markdown_format(pr, results)
Thomas Kluyver
Add option to test without posting results.
r6711 gh_api.post_issue_comment(gh_project, num, body)
Thomas Kluyver
Use requests throughout test_pr
r6709
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 def print_results(pr, results_urls):
Thomas Kluyver
Add option to test without posting results.
r6711 print("\n")
if pr['mergeable']:
print("**Test results for commit %s merged into master**" % pr['head']['sha'][:7])
else:
print("**Test results for commit %s (can't merge cleanly)**" % pr['head']['sha'][:7])
print("Platform:", sys.platform)
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 for py, passed, gist_url, missing_libraries in results_urls:
Thomas Kluyver
Add option to test without posting results.
r6711 if passed:
print(py, ":", "OK")
else:
print(py, ":", "Failed")
print(" Test log:", gist_url)
if missing_libraries:
print(" Libraries not available:", missing_libraries)
print("Not available for testing:", ", ".join(unavailable_pythons))
Thomas Kluyver
PR tester can now post results to Github as a comment.
r6694
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 def dump_results(num, results, pr):
with open(os.path.join(basedir, 'lastresults.pkl'), 'wb') as f:
pickle.dump((num, results, pr), f)
def load_results():
with open(os.path.join(basedir, 'lastresults.pkl'), 'rb') as f:
return pickle.load(f)
def save_logs(results, pr):
results_paths = []
for py, passed, log, missing_libraries in results:
if passed:
results_paths.append((py, passed, None, missing_libraries))
else:
result_locn = os.path.abspath(os.path.join('venv-%s' % py,
pr['head']['sha'][:7]+".log"))
with io.open(result_locn, 'w', encoding='utf-8') as f:
f.write(log)
results_paths.append((py, False, result_locn, missing_libraries))
return results_paths
def post_logs(results):
results_urls = []
for py, passed, log, missing_libraries in results:
if passed:
results_urls.append((py, passed, None, missing_libraries))
else:
result_locn = gh_api.post_gist(log, description='IPython test log',
filename="results.log", auth=True)
results_urls.append((py, False, result_locn, missing_libraries))
return results_urls
Thomas Kluyver
Add option to test without posting results.
r6711 def test_pr(num, post_results=True):
# Get Github authorisation first, so that the user is prompted straight away
# if their login is needed.
if post_results:
gh_api.get_auth_token()
Thomas Kluyver
Add script to test pull request
r6686 setup()
Thomas Kluyver
Add option to test without posting results.
r6711 pr = gh_api.get_pull_request(gh_project, num)
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 get_branch(repo=pr['head']['repo']['clone_url'],
Thomas Kluyver
Add script to test pull request
r6686 branch=pr['head']['ref'],
Thomas Kluyver
Handle testing unmergeable pull requests.
r6708 owner=pr['head']['repo']['owner']['login'],
mergeable=pr['mergeable'],
)
Thomas Kluyver
Add script to test pull request
r6686
results = []
for py, venv in venvs:
MinRK
time test run
r6736 tic = time.time()
Thomas Kluyver
Add script to test pull request
r6686 passed, log = run_tests(venv)
MinRK
time test run
r6736 elapsed = int(time.time() - tic)
print("Ran tests with %s in %is" % (py, elapsed))
Thomas Kluyver
Print missing libraries and platform.
r6692 missing_libraries = get_missing_libraries(log)
Thomas Kluyver
Add script to test pull request
r6686 if passed:
Thomas Kluyver
Print missing libraries and platform.
r6692 results.append((py, True, None, missing_libraries))
Thomas Kluyver
Add script to test pull request
r6686 else:
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 results.append((py, False, log, missing_libraries))
dump_results(num, results, pr)
results_paths = save_logs(results, pr)
print_results(pr, results_paths)
Thomas Kluyver
Add script to test pull request
r6686
Thomas Kluyver
Add option to test without posting results.
r6711 if post_results:
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 results_urls = post_logs(results)
post_results_comment(pr, results_urls, num)
Thomas Kluyver
Add option to test without posting results.
r6711 print("(Posted to Github)")
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 else:
post_script = os.path.join(os.path.dirname(sys.argv[0]), "post_pr_test.py")
print("To post the results to Github, run", post_script)
Thomas Kluyver
Add option to test without posting results.
r6711
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description="Test an IPython pull request")
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 parser.add_argument('-p', '--publish', action='store_true',
help="Publish the results to Github")
Thomas Kluyver
Add option to test without posting results.
r6711 parser.add_argument('number', type=int, help="The pull request number")
args = parser.parse_args()
Thomas Kluyver
Pickle PR test logs so they can be posted without rerunning tests.
r6713 test_pr(args.number, post_results=args.publish)