Merge lp:~jelmer/brz/github-proposals-fix into lp:brz

Proposed by Jelmer Vernooij
Status: Merged
Approved by: Jelmer Vernooij
Approved revision: no longer in the source branch.
Merge reported by: The Breezy Bot
Merged at revision: not available
Proposed branch: lp:~jelmer/brz/github-proposals-fix
Merge into: lp:brz
Diff against target: 312 lines (+83/-44)
6 files modified
breezy/bzr/smart/medium.py (+1/-1)
breezy/git/transportgit.py (+2/-2)
breezy/plugins/propose/github.py (+54/-22)
breezy/plugins/propose/gitlabs.py (+21/-18)
breezy/plugins/propose/launchpad.py (+1/-1)
breezy/transport/http/__init__.py (+4/-0)
To merge this branch: bzr merge lp:~jelmer/brz/github-proposals-fix
Reviewer Review Type Date Requested Status
Martin Packman Approve
Review via email: mp+370033@code.launchpad.net

Commit message

Fix iter_proposals for GitHub and GitLab.

Description of the change

Fix iter_proposals for GitHub.

To post a comment you must log in.
Revision history for this message
Martin Packman (gz) wrote :

I think this is fine. Have a bit of nervousness over the json handling, as the Python 2 and 3 behaviours of that module are silly (both deal in str rather than bytes). So, the code is probably broken on Python 2 with non-ascii pull request titles. Can sort that later.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'breezy/bzr/smart/medium.py'
2--- breezy/bzr/smart/medium.py 2019-03-06 14:03:19 +0000
3+++ breezy/bzr/smart/medium.py 2019-07-28 23:05:30 +0000
4@@ -696,7 +696,7 @@
5 self.counts = weakref.WeakKeyDictionary()
6 client._SmartClient.hooks.install_named_hook(
7 'call', self.increment_call_count, 'hpss call counter')
8- breezy.get_global_state().cleanups.add_cleanup(self.flush_all)
9+ breezy.get_global_state().exit_stack.callback(self.flush_all)
10
11 def track(self, medium):
12 """Start tracking calls made to a medium.
13
14=== modified file 'breezy/git/transportgit.py'
15--- breezy/git/transportgit.py 2019-06-29 19:54:32 +0000
16+++ breezy/git/transportgit.py 2019-07-28 23:05:30 +0000
17@@ -427,11 +427,11 @@
18 refs_container = InfoRefsContainer(BytesIO(refs_text))
19 try:
20 head = TransportRefsContainer(
21- self._commontransport).read_loose_ref("HEAD")
22+ self._commontransport).read_loose_ref(b"HEAD")
23 except KeyError:
24 pass
25 else:
26- refs_container._refs["HEAD"] = head
27+ refs_container._refs[b"HEAD"] = head
28 else:
29 refs_container = TransportRefsContainer(
30 self._commontransport, self._controltransport)
31
32=== modified file 'breezy/plugins/propose/github.py'
33--- breezy/plugins/propose/github.py 2019-07-07 00:41:49 +0000
34+++ breezy/plugins/propose/github.py 2019-07-28 23:05:30 +0000
35@@ -108,7 +108,8 @@
36
37 class GitHubMergeProposal(MergeProposal):
38
39- def __init__(self, pr):
40+ def __init__(self, gh, pr):
41+ self._gh = gh
42 self._pr = pr
43
44 @property
45@@ -130,14 +131,27 @@
46 def get_commit_message(self):
47 return None
48
49+ def set_commit_message(self, message):
50+ self._patch({'title': message})
51+
52+ def _patch(self, data):
53+ response = self._gh._api_request(
54+ 'PATCH', self._pr['url'], body=json.dumps(data).encode('utf-8'))
55+ if response != 200:
56+ raise InvalidHttpResponse(self._pr['url'], response.text)
57+ self._pr = json.loads(response.text)
58+
59 def set_description(self, description):
60- self._pr.edit(body=description, title=determine_title(description))
61+ self._patch({
62+ 'body': description,
63+ 'title': determine_title(description),
64+ })
65
66 def is_merged(self):
67- return self._pr['merged']
68+ return self._pr['state'] == 'merged'
69
70 def close(self):
71- self._pr.edit(state='closed')
72+ self._patch({'state': 'closed'})
73
74 def merge(self, commit_message=None):
75 # https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
76@@ -178,14 +192,14 @@
77 def __repr__(self):
78 return "GitHub()"
79
80- def _api_request(self, method, path):
81+ def _api_request(self, method, path, body=None):
82 headers = {
83 'Accept': 'application/vnd.github.v3+json'}
84 if self._token:
85 headers['Authorization'] = 'token %s' % self._token
86 response = self.transport.request(
87 method, urlutils.join(self.transport.base, path),
88- headers=headers)
89+ headers=headers, body=body)
90 if response.status == 401:
91 raise GitHubLoginRequired(self)
92 return response
93@@ -199,6 +213,22 @@
94 return json.loads(response.text)
95 raise InvalidHttpResponse(path, response.text)
96
97+ def _get_repo_pulls(self, path, head=None, state=None):
98+ path = 'repos/' + path + '/pulls?'
99+ params = {}
100+ if head is not None:
101+ params['head'] = head
102+ if state is not None:
103+ params['state'] = state
104+ path += ';'.join(['%s=%s' % (k, urlutils.quote(v))
105+ for k, v in params.items()])
106+ response = self._api_request('GET', path)
107+ if response.status == 404:
108+ raise NoSuchProject(path)
109+ if response.status == 200:
110+ return json.loads(response.text)
111+ raise InvalidHttpResponse(path, response.text)
112+
113 def _get_user(self, username=None):
114 if username:
115 path = 'users/:%s' % username
116@@ -304,28 +334,30 @@
117 parse_github_branch_url(source_branch))
118 (target_owner, target_repo_name, target_branch_name) = (
119 parse_github_branch_url(target_branch))
120- target_repo = self._get_repo(
121- "%s/%s" % (target_owner, target_repo_name))
122+ target_repo_path = "%s/%s" % (target_owner, target_repo_name)
123+ target_repo = self._get_repo(target_repo_path)
124 state = {
125 'open': 'open',
126 'merged': 'closed',
127 'closed': 'closed',
128 'all': 'all'}
129- for pull in target_repo.get_pulls(
130- head=target_branch_name,
131- state=state[status]):
132- if (status == 'closed' and pull.merged or
133- status == 'merged' and not pull.merged):
134- continue
135- if pull.head.ref != source_branch_name:
136- continue
137- if pull.head.repo is None:
138+ pulls = self._get_repo_pulls(
139+ target_repo_path,
140+ head=target_branch_name,
141+ state=state[status])
142+ for pull in pulls:
143+ if (status == 'closed' and pull['merged'] or
144+ status == 'merged' and not pull['merged']):
145+ continue
146+ if pull['head']['ref'] != source_branch_name:
147+ continue
148+ if pull['head']['repo'] is None:
149 # Repo has gone the way of the dodo
150 continue
151- if (pull.head.repo.owner.login != source_owner or
152- pull.head.repo.name != source_repo_name):
153+ if (pull['head']['repo']['owner']['login'] != source_owner or
154+ pull['head']['repo']['name'] != source_repo_name):
155 continue
156- yield GitHubMergeProposal(pull)
157+ yield GitHubMergeProposal(self, pull)
158
159 def hosts(self, branch):
160 try:
161@@ -366,7 +398,7 @@
162 response = self._api_request('GET', url)
163 if response.status != 200:
164 raise InvalidHttpResponse(url, response.text)
165- yield GitHubMergeProposal(json.loads(response.text))
166+ yield GitHubMergeProposal(self, json.loads(response.text))
167
168 def get_proposal_by_url(self, url):
169 raise UnsupportedHoster(url)
170@@ -430,4 +462,4 @@
171 if labels:
172 for label in labels:
173 pull_request.issue.labels.append(label)
174- return GitHubMergeProposal(pull_request)
175+ return GitHubMergeProposal(self.gh, pull_request)
176
177=== modified file 'breezy/plugins/propose/gitlabs.py'
178--- breezy/plugins/propose/gitlabs.py 2019-07-07 15:50:07 +0000
179+++ breezy/plugins/propose/gitlabs.py 2019-07-28 23:05:30 +0000
180@@ -230,10 +230,10 @@
181 def base_url(self):
182 return self.transport.base
183
184- def _api_request(self, method, path):
185+ def _api_request(self, method, path, data=None):
186 return self.transport.request(
187 method, urlutils.join(self.base_url, 'api', 'v4', path),
188- headers=self.headers)
189+ headers=self.headers, body=data)
190
191 def __init__(self, transport, private_token):
192 self.transport = transport
193@@ -247,13 +247,13 @@
194 raise NoSuchProject(project_name)
195 if response.status == 200:
196 return json.loads(response.data)
197- raise InvalidHttpResponse(path, response.text)
198+ raise errors.InvalidHttpResponse(path, response.text)
199
200 def _fork_project(self, project_name):
201 path = 'projects/%s/fork' % urlutils.quote(str(project_name), '')
202 response = self._api_request('POST', path)
203 if response != 201:
204- raise InvalidHttpResponse(path, response.text)
205+ raise errors.InvalidHttpResponse(path, response.text)
206 return json.loads(response.data)
207
208 def _get_logged_in_username(self):
209@@ -261,7 +261,7 @@
210
211 def _list_merge_requests(self, owner=None, project=None, state=None):
212 if project is not None:
213- path = 'projects/%s/merge_requests' % urlutils.quote(str(project_name), '')
214+ path = 'projects/%s/merge_requests' % urlutils.quote(str(project), '')
215 else:
216 path = 'merge_requests'
217 parameters = {}
218@@ -276,27 +276,30 @@
219 raise errors.PermissionDenied(response.text)
220 if response.status == 200:
221 return json.loads(response.data)
222- raise InvalidHttpResponse(path, response.text)
223+ raise errors.InvalidHttpResponse(path, response.text)
224
225 def _create_mergerequest(
226 self, title, source_project_id, target_project_id,
227 source_branch_name, target_branch_name, description,
228 labels=None):
229 path = 'projects/%s/merge_requests' % source_project_id
230+ fields = {
231+ 'title': title,
232+ 'source_branch': source_branch_name,
233+ 'target_branch': target_branch_name,
234+ 'target_project_id': target_project_id,
235+ 'description': description,
236+ }
237+ if labels:
238+ fields['labels'] = labels
239 response = self._api_request(
240- 'POST', path, fields={
241- 'title': title,
242- 'source_branch': source_branch_name,
243- 'target_branch': target_branch_name,
244- 'target_project_id': target_project_id,
245- 'description': description,
246- 'labels': labels})
247+ 'POST', path, data=json.dumps(fields).encode('utf-8'))
248 if response.status == 403:
249 raise errors.PermissionDenied(response.text)
250 if response.status == 409:
251 raise MergeProposalExists(self.source_branch.user_url)
252- if response.status == 200:
253- raise InvalidHttpResponse(path, response.text)
254+ if response.status != 201:
255+ raise errors.InvalidHttpResponse(path, response.text)
256 return json.loads(response.data)
257
258 def get_push_url(self, branch):
259@@ -436,7 +439,7 @@
260
261 class GitlabMergeProposalBuilder(MergeProposalBuilder):
262
263- def __init__(self, l, source_branch, target_branch):
264+ def __init__(self, gl, source_branch, target_branch):
265 self.gl = gl
266 self.source_branch = source_branch
267 (self.source_host, self.source_project_name, self.source_branch_name) = (
268@@ -481,8 +484,8 @@
269 'title': title,
270 'source_project_id': source_project['id'],
271 'target_project_id': target_project['id'],
272- 'source_branch': self.source_branch_name,
273- 'target_branch': self.target_branch_name,
274+ 'source_branch_name': self.source_branch_name,
275+ 'target_branch_name': self.target_branch_name,
276 'description': description}
277 if labels:
278 kwargs['labels'] = ','.join(labels)
279
280=== modified file 'breezy/plugins/propose/launchpad.py'
281--- breezy/plugins/propose/launchpad.py 2019-07-07 00:41:01 +0000
282+++ breezy/plugins/propose/launchpad.py 2019-07-28 23:05:30 +0000
283@@ -188,7 +188,7 @@
284 lp_base_url = uris.STAGING_SERVICE_ROOT
285 else:
286 lp_base_url = uris.LPNET_SERVICE_ROOT
287- self.launchpad = lp_api.connect_launchpad(lp_base_url)
288+ self.launchpad = lp_api.connect_launchpad(lp_base_url, version='devel')
289
290 @property
291 def base_url(self):
292
293=== modified file 'breezy/transport/http/__init__.py'
294--- breezy/transport/http/__init__.py 2019-07-15 23:34:05 +0000
295+++ breezy/transport/http/__init__.py 2019-07-28 23:05:30 +0000
296@@ -1822,6 +1822,7 @@
297 """
298
299 accepted_errors = [200, # Ok
300+ 201,
301 206, # Partial content
302 400,
303 403,
304@@ -2029,6 +2030,9 @@
305 def readlines(self):
306 return self._actual.readlines()
307
308+ def readlines(self):
309+ return self._actual.readlines()
310+
311 def readline(self, size=-1):
312 return self._actual.readline(size)
313

Subscribers

People subscribed via source and target branches