/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/plugins/github/hoster.py

  • Committer: Gustav Hartvigsson
  • Date: 2021-01-11 20:19:38 UTC
  • mfrom: (7526.3.2 work)
  • Revision ID: gustav.hartvigsson@gmail.com-20210111201938-omr9wjz3qdgyxe8k
MergedĀ lp:brz

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    version_string as breezy_version,
43
43
    )
44
44
from ...config import AuthenticationConfig, GlobalStack
45
 
from ...errors import InvalidHttpResponse, PermissionDenied
 
45
from ...errors import (
 
46
    InvalidHttpResponse,
 
47
    PermissionDenied,
 
48
    UnexpectedHttpStatus,
 
49
    )
46
50
from ...git.urls import git_url_to_bzr_url
47
51
from ...i18n import gettext
48
52
from ...trace import note
120
124
    def __repr__(self):
121
125
        return "<%s at %r>" % (type(self).__name__, self.url)
122
126
 
 
127
    name = 'GitHub'
 
128
 
123
129
    @property
124
130
    def url(self):
125
131
        return self._pr['html_url']
132
138
    def get_source_branch_url(self):
133
139
        return self._branch_from_part(self._pr['head'])
134
140
 
 
141
    def get_source_revision(self):
 
142
        """Return the latest revision for the source branch."""
 
143
        from breezy.git.mapping import default_mapping
 
144
        return default_mapping.revision_id_foreign_to_bzr(
 
145
            self._pr['head']['sha'].encode('ascii'))
 
146
 
135
147
    def get_target_branch_url(self):
136
148
        return self._branch_from_part(self._pr['base'])
137
149
 
156
168
        if response.status == 422:
157
169
            raise ValidationFailed(json.loads(response.text))
158
170
        if response.status != 200:
159
 
            raise InvalidHttpResponse(self._pr['url'], response.text)
 
171
            raise UnexpectedHttpStatus(self._pr['url'], response.status)
160
172
        self._pr = json.loads(response.text)
161
173
 
162
174
    def set_description(self, description):
185
197
 
186
198
    def merge(self, commit_message=None):
187
199
        # https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
188
 
        self._pr.merge(commit_message=commit_message)
 
200
        data = {}
 
201
        if commit_message:
 
202
            data['commit_message'] = commit_messae
 
203
        response = self._gh._api_request(
 
204
            'PUT', self._pr['url'] + "/merge", body=json.dumps(data).encode('utf-8'))
 
205
        if response.status == 422:
 
206
            raise ValidationFailed(json.loads(response.text))
 
207
        if response.status != 200:
 
208
            raise UnexpectedHttpStatus(self._pr['url'], response.status)
189
209
 
190
210
    def get_merged_by(self):
191
211
        merged_by = self._pr.get('merged_by')
200
220
        import iso8601
201
221
        return iso8601.parse_date(merged_at)
202
222
 
 
223
    def post_comment(self, body):
 
224
        data = {'body': body}
 
225
        response = self._gh._api_request(
 
226
            'POST', self._pr['comments_url'], body=json.dumps(data).encode('utf-8'))
 
227
        if response.status == 422:
 
228
            raise ValidationFailed(json.loads(response.text))
 
229
        if response.status != 201:
 
230
            raise UnexpectedHttpStatus(
 
231
                self._pr['comments_url'], response.status)
 
232
        json.loads(response.text)
 
233
 
203
234
 
204
235
def parse_github_url(url):
205
236
    (scheme, user, password, host, port, path) = urlutils.parse_url(
244
275
            'Accept': 'application/vnd.github.v3+json'}
245
276
        if self._token:
246
277
            headers['Authorization'] = 'token %s' % self._token
247
 
        response = self.transport.request(
248
 
            method, urlutils.join(self.transport.base, path),
249
 
            headers=headers, body=body, retries=3)
 
278
        try:
 
279
            response = self.transport.request(
 
280
                method, urlutils.join(self.transport.base, path),
 
281
                headers=headers, body=body, retries=3)
 
282
        except UnexpectedHttpStatus as e:
 
283
            if e.code == 401:
 
284
                raise GitHubLoginRequired(self)
 
285
            else:
 
286
                raise
250
287
        if response.status == 401:
251
288
            raise GitHubLoginRequired(self)
252
289
        return response
258
295
            raise NoSuchProject(path)
259
296
        if response.status == 200:
260
297
            return json.loads(response.text)
261
 
        raise InvalidHttpResponse(path, response.text)
 
298
        raise UnexpectedHttpStatus(path, response.status)
262
299
 
263
300
    def _get_repo_pulls(self, path, head=None, state=None):
264
301
        path = path + '?'
274
311
            raise NoSuchProject(path)
275
312
        if response.status == 200:
276
313
            return json.loads(response.text)
277
 
        raise InvalidHttpResponse(path, response.text)
 
314
        raise UnexpectedHttpStatus(path, response.status)
278
315
 
279
316
    def _create_pull(self, path, title, head, base, body=None, labels=None,
280
317
                     assignee=None, draft=False, maintainer_can_modify=False):
297
334
        if response.status == 403:
298
335
            raise PermissionDenied(path, response.text)
299
336
        if response.status != 201:
300
 
            raise InvalidHttpResponse(path, 'req is invalid %d %r: %r' % (response.status, data, response.text))
 
337
            raise UnexpectedHttpStatus(path, response.status)
301
338
        return json.loads(response.text)
302
339
 
303
340
    def _get_user_by_email(self, email):
304
341
        path = 'search/users?q=%s+in:email' % email
305
342
        response = self._api_request('GET', path)
306
343
        if response.status != 200:
307
 
            raise InvalidHttpResponse(path, response.text)
 
344
            raise UnexpectedHttpStatus(path, response.status)
308
345
        ret = json.loads(response.text)
309
346
        if ret['total_count'] == 0:
310
347
            raise KeyError('no user with email %s' % email)
319
356
            path = 'user'
320
357
        response = self._api_request('GET', path)
321
358
        if response.status != 200:
322
 
            raise InvalidHttpResponse(path, response.text)
 
359
            raise UnexpectedHttpStatus(path, response.status)
323
360
        return json.loads(response.text)
324
361
 
325
362
    def _get_organization(self, name):
326
363
        path = 'orgs/%s' % name
327
364
        response = self._api_request('GET', path)
328
365
        if response.status != 200:
329
 
            raise InvalidHttpResponse(path, response.text)
 
366
            raise UnexpectedHttpStatus(path, response.status)
330
367
        return json.loads(response.text)
331
368
 
332
369
    def _list_paged(self, path, parameters=None, per_page=None):
345
382
                ';'.join(['%s=%s' % (k, urlutils.quote(v))
346
383
                          for (k, v) in parameters.items()]))
347
384
            if response.status != 200:
348
 
                raise InvalidHttpResponse(path, response.text)
 
385
                raise UnexpectedHttpStatus(path, response.status)
349
386
            data = json.loads(response.text)
350
387
            for entry in data['items']:
351
388
                i += 1
359
396
        return self._list_paged(path, {'q': query}, per_page=DEFAULT_PER_PAGE)
360
397
 
361
398
    def _create_fork(self, path, owner=None):
362
 
        if owner and owner != self._current_user['login']:
 
399
        if owner and owner != self.current_user['login']:
363
400
            path += '?organization=%s' % owner
364
401
        response = self._api_request('POST', path)
365
402
        if response.status != 202:
366
 
            raise InvalidHttpResponse(path, 'status: %d, %r' % (response.status, response.text))
 
403
            raise UnexpectedHttpStatus(path, response.status)
367
404
        return json.loads(response.text)
368
405
 
369
406
    @property
373
410
    def __init__(self, transport):
374
411
        self._token = retrieve_github_token('https', GITHUB_HOST)
375
412
        self.transport = transport
376
 
        self._current_user = self._get_user()
 
413
        self._current_user = None
 
414
 
 
415
    @property
 
416
    def current_user(self):
 
417
        if self._current_user is None:
 
418
            self._current_user = self._get_user()
 
419
        return self._current_user
377
420
 
378
421
    def publish_derived(self, local_branch, base_branch, name, project=None,
379
422
                        owner=None, revision_id=None, overwrite=False,
381
424
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
382
425
        base_repo = self._get_repo(base_owner, base_project)
383
426
        if owner is None:
384
 
            owner = self._current_user['login']
 
427
            owner = self.current_user['login']
385
428
        if project is None:
386
429
            project = base_repo['name']
387
430
        try:
417
460
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
418
461
        base_repo = self._get_repo(base_owner, base_project)
419
462
        if owner is None:
420
 
            owner = self._current_user['login']
 
463
            owner = self.current_user['login']
421
464
        if project is None:
422
465
            project = base_repo['name']
423
466
        try:
481
524
    def iter_instances(cls):
482
525
        yield cls(get_transport(API_GITHUB_URL))
483
526
 
484
 
    def iter_my_proposals(self, status='open'):
 
527
    def iter_my_proposals(self, status='open', author=None):
485
528
        query = ['is:pr']
486
529
        if status == 'open':
487
530
            query.append('is:open')
492
535
            query.append('is:closed')
493
536
        elif status == 'merged':
494
537
            query.append('is:merged')
495
 
        query.append('author:%s' % self._current_user['login'])
 
538
        if author is None:
 
539
            author = self.current_user['login']
 
540
        query.append('author:%s' % author)
496
541
        for issue in self._search_issues(query=' '.join(query)):
497
542
            url = issue['pull_request']['url']
498
543
            response = self._api_request('GET', url)
499
544
            if response.status != 200:
500
 
                raise InvalidHttpResponse(url, response.text)
 
545
                raise UnexpectedHttpStatus(url, response.status)
501
546
            yield GitHubMergeProposal(self, json.loads(response.text))
502
547
 
503
548
    def get_proposal_by_url(self, url):
504
549
        raise UnsupportedHoster(url)
505
550
 
506
 
    def iter_my_forks(self):
507
 
        response = self._api_request('GET', '/user/repos')
 
551
    def iter_my_forks(self, owner=None):
 
552
        if owner:
 
553
            path = '/users/%s/repos' % owner
 
554
        else:
 
555
            path = '/user/repos'
 
556
        response = self._api_request('GET', path)
508
557
        if response.status != 200:
509
 
            raise InvalidHttpResponse(url, response.text)
 
558
            raise UnexpectedHttpStatus(self.transport.user_url, response.status)
510
559
        for project in json.loads(response.text):
511
560
            if not project['fork']:
512
561
                continue
521
570
            return
522
571
        if response.status == 200:
523
572
            return json.loads(response.text)
524
 
        raise InvalidHttpResponse(path, response.text)
 
573
        raise UnexpectedHttpStatus(path, response.status)
 
574
 
 
575
    def get_current_user(self):
 
576
        if self._token is not None:
 
577
            return self.current_user['login']
 
578
        return None
 
579
 
 
580
    def get_user_url(self, username):
 
581
        return urlutils.join(self.base_url, username)
525
582
 
526
583
 
527
584
class GitHubMergeProposalBuilder(MergeProposalBuilder):