OLD | NEW |
1 # Copyright 2016 The Chromium Authors. All rights reserved. | 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import base64 | 5 import base64 |
6 import json | 6 import json |
7 import logging | 7 import logging |
8 import os | 8 import os |
9 import sys | 9 import sys |
10 import urllib2 | 10 import urllib2 |
(...skipping 23 matching lines...) Expand all Loading... |
34 assert path.startswith('/') | 34 assert path.startswith('/') |
35 if body: | 35 if body: |
36 body = json.dumps(body) | 36 body = json.dumps(body) |
37 opener = urllib2.build_opener(urllib2.HTTPHandler) | 37 opener = urllib2.build_opener(urllib2.HTTPHandler) |
38 request = urllib2.Request(url=API_BASE + path, data=body) | 38 request = urllib2.Request(url=API_BASE + path, data=body) |
39 request.add_header('Accept', 'application/vnd.github.v3+json') | 39 request.add_header('Accept', 'application/vnd.github.v3+json') |
40 request.add_header('Authorization', 'Basic {}'.format(self.auth_token())
) | 40 request.add_header('Authorization', 'Basic {}'.format(self.auth_token())
) |
41 request.get_method = lambda: method | 41 request.get_method = lambda: method |
42 response = opener.open(request) | 42 response = opener.open(request) |
43 status_code = response.getcode() | 43 status_code = response.getcode() |
44 return json.load(response), status_code | 44 try: |
| 45 return json.load(response), status_code |
| 46 except ValueError: |
| 47 return None, status_code |
45 | 48 |
46 def create_pr(self, local_branch_name, desc_title, body): | 49 def create_pr(self, remote_branch_name, desc_title, body): |
47 """Creates a PR on GitHub. | 50 """Creates a PR on GitHub. |
48 | 51 |
49 API doc: https://developer.github.com/v3/pulls/#create-a-pull-request | 52 API doc: https://developer.github.com/v3/pulls/#create-a-pull-request |
50 | 53 |
51 Returns: | 54 Returns: |
52 A raw response object if successful, None if not. | 55 A raw response object if successful, None if not. |
53 """ | 56 """ |
54 assert local_branch_name | 57 assert remote_branch_name |
55 assert desc_title | 58 assert desc_title |
56 assert body | 59 assert body |
57 | 60 |
58 pr_branch_name = '{}:{}'.format(self.user, local_branch_name) | |
59 | |
60 # TODO(jeffcarp): CC foolip and qyearsley on all PRs for now | 61 # TODO(jeffcarp): CC foolip and qyearsley on all PRs for now |
61 # TODO(jeffcarp): add HTTP to Host and use that here | 62 # TODO(jeffcarp): add HTTP to Host and use that here |
62 path = '/repos/w3c/web-platform-tests/pulls' | 63 path = '/repos/w3c/web-platform-tests/pulls' |
63 body = { | 64 body = { |
64 "title": desc_title, | 65 "title": desc_title, |
65 "body": body, | 66 "body": body, |
66 "head": pr_branch_name, | 67 "head": remote_branch_name, |
67 "base": 'master', | 68 "base": 'master', |
68 } | 69 } |
69 data, status_code = self.request(path, method='POST', body=body) | 70 data, status_code = self.request(path, method='POST', body=body) |
70 | 71 |
71 if status_code != 201: | 72 if status_code != 201: |
72 return None | 73 return None |
73 | 74 |
74 return data | 75 return data |
75 | 76 |
76 def add_label(self, number): | 77 def add_label(self, number): |
77 path = '/repos/w3c/web-platform-tests/issues/%d/labels' % number | 78 path = '/repos/w3c/web-platform-tests/issues/%d/labels' % number |
78 body = [EXPORT_LABEL] | 79 body = [EXPORT_LABEL] |
79 return self.request(path, method='POST', body=body) | 80 return self.request(path, method='POST', body=body) |
80 | 81 |
81 def in_flight_pull_requests(self): | 82 def in_flight_pull_requests(self): |
82 url_encoded_label = EXPORT_LABEL.replace(' ', '%20') | 83 path = '/search/issues?q=repo:w3c/web-platform-tests%20is:open%20type:pr
%20label:{}'.format(EXPORT_LABEL) |
83 path = '/search/issues?q=repo:w3c/web-platform-tests%20is:open%20type:pr
%20labels:{}'.format(url_encoded_label) | |
84 data, status_code = self.request(path, method='GET') | 84 data, status_code = self.request(path, method='GET') |
85 if status_code == 200: | 85 if status_code == 200: |
86 return data['items'] | 86 return data['items'] |
87 else: | 87 else: |
88 raise Exception('Non-200 status code (%s): %s' % (status_code, data)
) | 88 raise Exception('Non-200 status code (%s): %s' % (status_code, data)
) |
89 | 89 |
90 def merge_pull_request(self, pull_request_number): | 90 def merge_pull_request(self, pull_request_number): |
91 path = '/repos/w3c/web-platform-tests/pulls/%d/merge' % pull_request_num
ber | 91 path = '/repos/w3c/web-platform-tests/pulls/%d/merge' % pull_request_num
ber |
92 body = {} | 92 body = {} |
93 response, content = self.request(path, method='PUT', body=body) | 93 data, status_code = self.request(path, method='PUT', body=body) |
94 | 94 |
95 if response['status'] == '200': | 95 if status_code == 200: |
96 return json.loads(content) | 96 return data |
97 else: | 97 else: |
98 raise Exception('PR could not be merged: %d' % pull_request_number) | 98 raise Exception('PR could not be merged: %d' % pull_request_number) |
| 99 |
| 100 def delete_remote_branch(self, remote_branch_name): |
| 101 path = '/repos/w3c/web-platform-tests/git/refs/heads/%s' % remote_branch
_name |
| 102 data, status_code = self.request(path, method='DELETE') |
| 103 |
| 104 if status_code != 200: |
| 105 # TODO(jeffcarp): Raise more specific exception (create MergeError c
lass?) |
| 106 raise Exception('PR could not be merged') |
| 107 |
| 108 return data |
OLD | NEW |