##// END OF EJS Templates
Use requests throughout test_pr
Thomas Kluyver -
Show More
@@ -1,201 +1,196 b''
1 1 """
2 2 This is a script for testing pull requests for IPython. It merges the pull
3 3 request with current master, installs and tests on all available versions of
4 4 Python, and posts the results to Gist if any tests fail.
5 5
6 6 Usage:
7 7 python test_pr.py 1657
8 8 """
9 9 from __future__ import print_function
10 10
11 11 import errno
12 12 from glob import glob
13 13 import json
14 14 import os
15 15 import re
16 16 import requests
17 17 import shutil
18 18 from subprocess import call, check_call, check_output, PIPE, STDOUT, CalledProcessError
19 try:
20 from urllib.request import urlopen
21 except ImportError:
22 from urllib2 import urlopen
23 19
24 20 import gh_auth
25 21
26 22 basedir = os.path.join(os.path.expanduser("~"), ".ipy_pr_tests")
27 23 repodir = os.path.join(basedir, "ipython")
28 24 ipy_repository = 'git://github.com/ipython/ipython.git'
29 25 gh_project="ipython/ipython"
30 26
31 27 supported_pythons = ['python2.6', 'python2.7', 'python3.1', 'python3.2']
32 28 unavailable_pythons = []
33 29
34 30 def available_python_versions():
35 31 """Get the executable names of available versions of Python on the system.
36 32 """
37 33 del unavailable_pythons[:]
38 34 for py in supported_pythons:
39 35 try:
40 36 check_call([py, '-c', 'import nose'], stdout=PIPE)
41 37 yield py
42 38 except (OSError, CalledProcessError):
43 39 unavailable_pythons.append(py)
44 40
45 41 venvs = []
46 42
47 43 def setup():
48 44 """Prepare the repository and virtualenvs."""
49 45 global venvs
50 46
51 47 try:
52 48 os.mkdir(basedir)
53 49 except OSError as e:
54 50 if e.errno != errno.EEXIST:
55 51 raise
56 52 os.chdir(basedir)
57 53
58 54 # Delete virtualenvs and recreate
59 55 for venv in glob('venv-*'):
60 56 shutil.rmtree(venv)
61 57 for py in available_python_versions():
62 58 check_call(['virtualenv', '-p', py, '--system-site-packages', 'venv-%s' % py])
63 59 venvs.append((py, 'venv-%s' % py))
64 60
65 61 # Check out and update the repository
66 62 if not os.path.exists('ipython'):
67 63 check_call(['git', 'clone', ipy_repository])
68 64 os.chdir(repodir)
69 65 check_call(['git', 'checkout', 'master'])
70 66 check_call(['git', 'pull', ipy_repository, 'master'])
71 67 os.chdir(basedir)
72 68
73 69 def get_pull_request(num):
74 70 url = "https://api.github.com/repos/{project}/pulls/{num}".format(project=gh_project, num=num)
75 response = urlopen(url).read().decode('utf-8')
76 return json.loads(response)
71 return json.loads(requests.get(url).text)
77 72
78 73 missing_libs_re = re.compile(r"Tools and libraries NOT available at test time:\n"
79 74 r"\s*(.*?)\n")
80 75 def get_missing_libraries(log):
81 76 m = missing_libs_re.search(log)
82 77 if m:
83 78 return m.group(1)
84 79
85 80 def get_branch(repo, branch, owner, mergeable):
86 81 os.chdir(repodir)
87 82 if mergeable:
88 83 merged_branch = "%s-%s" % (owner, branch)
89 84 # Delete the branch first
90 85 call(['git', 'branch', '-D', merged_branch])
91 86 check_call(['git', 'checkout', '-b', merged_branch])
92 87 check_call(['git', 'pull', repo, branch])
93 88 else:
94 89 # Fetch the branch without merging it.
95 90 check_call(['git', 'fetch', repo, branch])
96 91 check_call(['git', 'checkout', 'FETCH_HEAD'])
97 92 os.chdir(basedir)
98 93
99 94 def run_tests(venv):
100 95 py = os.path.join(basedir, venv, 'bin', 'python')
101 96 print(py)
102 97 os.chdir(repodir)
103 98 check_call([py, 'setup.py', 'install'])
104 99 os.chdir(basedir)
105 100
106 101 iptest = os.path.join(basedir, venv, 'bin', 'iptest')
107 102 if not os.path.exists(iptest):
108 103 iptest = os.path.join(basedir, venv, 'bin', 'iptest3')
109 104
110 105 print("\nRunning tests, this typically takes a few minutes...")
111 106 try:
112 107 return True, check_output([iptest], stderr=STDOUT).decode('utf-8')
113 108 except CalledProcessError as e:
114 109 return False, e.output.decode('utf-8')
115 110
116 111 def post_gist(content, description='IPython test log', filename="results.log"):
117 112 """Post some text to a Gist, and return the URL."""
118 113 post_data = json.dumps({
119 114 "description": description,
120 115 "public": True,
121 116 "files": {
122 117 filename: {
123 118 "content": content
124 119 }
125 120 }
126 121 }).encode('utf-8')
127 122
128 response = urlopen("https://api.github.com/gists", post_data)
129 response_data = json.loads(response.read().decode('utf-8'))
123 response = requests.post("https://api.github.com/gists", data=post_data)
124 response_data = json.loads(response.text)
130 125 return response_data['html_url']
131 126
132 127 def markdown_format(pr, results):
133 128 def format_result(py, passed, gist_url, missing_libraries):
134 129 s = "* %s: " % py
135 130 if passed:
136 131 s += "OK"
137 132 else:
138 133 s += "Failed, log at %s" % gist_url
139 134 if missing_libraries:
140 135 s += " (libraries not available: " + missing_libraries + ")"
141 136 return s
142 137
143 138 if pr['mergeable']:
144 139 com = pr['head']['sha'][:7] + " merged into master"
145 140 else:
146 141 com = pr['head']['sha'][:7] + " (can't merge cleanly)"
147 142 lines = ["**Test results for commit %s**" % com,
148 143 "Platform: " + sys.platform,
149 144 ""] + \
150 145 [format_result(*r) for r in results] + \
151 146 ["",
152 147 "Not available for testing: " + ", ".join(unavailable_pythons)]
153 148 return "\n".join(lines)
154 149
155 150 def post_results_comment(pr, results, num):
156 151 body = markdown_format(pr, results)
157 152 url = 'https://api.github.com/repos/{project}/issues/{num}/comments'.format(project=gh_project, num=num)
158 153 payload = json.dumps({'body': body})
159 154 auth_token = gh_auth.get_auth_token()
160 155 headers = {'Authorization': 'token ' + auth_token}
161 156 r = requests.post(url, data=payload, headers=headers)
162
157
163 158
164 159 if __name__ == '__main__':
165 160 import sys
166 161 num = sys.argv[1]
167 162 setup()
168 163 pr = get_pull_request(num)
169 164 get_branch(repo=pr['head']['repo']['clone_url'],
170 165 branch=pr['head']['ref'],
171 166 owner=pr['head']['repo']['owner']['login'],
172 167 mergeable=pr['mergeable'],
173 168 )
174 169
175 170 results = []
176 171 for py, venv in venvs:
177 172 passed, log = run_tests(venv)
178 173 missing_libraries = get_missing_libraries(log)
179 174 if passed:
180 175 results.append((py, True, None, missing_libraries))
181 176 else:
182 177 gist_url = post_gist(log)
183 178 results.append((py, False, gist_url, missing_libraries))
184 179
185 180 print("\n")
186 181 if pr['mergeable']:
187 182 print("**Test results for commit %s merged into master**" % pr['head']['sha'][:7])
188 183 else:
189 184 print("**Test results for commit %s (can't merge cleanly)**" % pr['head']['sha'][:7])
190 185 print("Platform:", sys.platform)
191 186 for py, passed, gist_url, missing_libraries in results:
192 187 if passed:
193 188 print(py, ":", "OK")
194 189 else:
195 190 print(py, ":", "Failed")
196 191 print(" Test log:", gist_url)
197 192 if missing_libraries:
198 193 print(" Libraries not available:", missing_libraries)
199 194 print("Not available for testing:", ", ".join(unavailable_pythons))
200 195 post_results_comment(pr, results, num)
201 196 print("(Posted to Github)")
General Comments 0
You need to be logged in to leave comments. Login now