/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/propose/github.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2019-09-21 14:54:21 UTC
  • mfrom: (7381.5.5 reopen-mp)
  • Revision ID: breezy.the.bot@gmail.com-20190921145421-mabvx568b7icpenq
Add functions for reopening merge proposals and checking if they are closed.

Merged from https://code.launchpad.net/~jelmer/brz/reopen-mp/+merge/371773

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
    MergeProposalExists,
30
30
    NoSuchProject,
31
31
    PrerequisiteBranchUnsupported,
 
32
    ReopenFailed,
32
33
    UnsupportedHoster,
33
34
    )
34
35
 
73
74
    return description.splitlines()[0]
74
75
 
75
76
 
 
77
class ValidationFailed(errors.BzrError):
 
78
 
 
79
    _fmt = "GitHub validation failed: %(error)s"
 
80
 
 
81
    def __init__(self, error):
 
82
        errors.BzrError.__init__(self)
 
83
        self.error = error
 
84
 
 
85
 
76
86
class NotGitHubUrl(errors.BzrError):
77
87
 
78
88
    _fmt = "Not a GitHub URL: %(url)s"
112
122
        self._gh = gh
113
123
        self._pr = pr
114
124
 
 
125
    def __repr__(self):
 
126
        return "<%s at %r>" % (type(self).__name__, self.url)
 
127
 
115
128
    @property
116
129
    def url(self):
117
130
        return self._pr['html_url']
139
152
    def _patch(self, data):
140
153
        response = self._gh._api_request(
141
154
            'PATCH', self._pr['url'], body=json.dumps(data).encode('utf-8'))
 
155
        if response.status == 422:
 
156
            raise ValidationFailed(json.loads(response.text))
142
157
        if response.status != 200:
143
158
            raise InvalidHttpResponse(self._pr['url'], response.text)
144
159
        self._pr = json.loads(response.text)
150
165
            })
151
166
 
152
167
    def is_merged(self):
153
 
        return self._pr['state'] == 'merged'
 
168
        return bool(self._pr.get('merged_at'))
 
169
 
 
170
    def is_closed(self):
 
171
        return self._pr['state'] == 'closed' and not bool(self._pr.get('merged_at'))
 
172
 
 
173
    def reopen(self):
 
174
        try:
 
175
            self._patch({'state': 'open'})
 
176
        except ValidationFailed as e:
 
177
            raise ReopenFailed(e.error['errors'][0]['message'])
154
178
 
155
179
    def close(self):
156
180
        self._patch({'state': 'closed'})
234
258
            return json.loads(response.text)
235
259
        raise InvalidHttpResponse(path, response.text)
236
260
 
 
261
    def _create_pull(self, path, title, head, base, body=None):
 
262
        path = 'repos/' + path + '/pulls'
 
263
        data = {
 
264
            'title': title,
 
265
            'head': head,
 
266
            'base': base,
 
267
        }
 
268
        if body:
 
269
            data['body'] = body
 
270
 
 
271
        response = self._api_request(
 
272
            'POST', path, body=json.dumps(data).encode('utf-8'))
 
273
        if response.status != 201:
 
274
            raise InvalidHttpResponse(path, response.text)
 
275
        return json.loads(response.text)
 
276
 
 
277
    def _get_user_by_email(self, email):
 
278
        path = 'search/users?q=%s+in:email' % email
 
279
        response = self._api_request('GET', path)
 
280
        if response.status != 200:
 
281
            raise InvalidHttpResponse(path, response.text)
 
282
        ret = json.loads(response.text)
 
283
        if ret['total_count'] == 0:
 
284
            raise KeyError('no user with email %s' % email)
 
285
        elif ret['total_count'] > 1:
 
286
            raise ValueError('more than one result for email %s' % email)
 
287
        return ret['items'][0]
 
288
 
237
289
    def _get_user(self, username=None):
238
290
        if username:
239
291
            path = 'users/:%s' % username
447
499
        # TODO(jelmer): Probe for right repo name
448
500
        if self.target_repo_name.endswith('.git'):
449
501
            self.target_repo_name = self.target_repo_name[:-4]
450
 
        target_repo = self.gh._get_repo("%s/%s" % (self.target_owner, self.target_repo_name))
451
502
        # TODO(jelmer): Allow setting title explicitly?
452
503
        title = determine_title(description)
453
 
        # TOOD(jelmer): Set maintainers_can_modify?
 
504
        # TODO(jelmer): Set maintainers_can_modify?
454
505
        try:
455
 
            pull_request = target_repo.create_pull(
 
506
            pull_request = self.gh._create_pull(
 
507
                "%s/%s" % (self.target_owner, self.target_repo_name),
456
508
                title=title, body=description,
457
509
                head="%s:%s" % (self.source_owner, self.source_branch_name),
458
510
                base=self.target_branch_name)
459
 
        except github.GithubException as e:
460
 
            if e.status == 422:
461
 
                raise MergeProposalExists(self.source_branch.user_url)
462
 
            raise
 
511
        except ValidationFailed:
 
512
            raise MergeProposalExists(self.source_branch.user_url)
463
513
        if reviewers:
464
514
            for reviewer in reviewers:
465
 
                pull_request.assignees.append(
466
 
                    self.gh._get_user(reviewer)['login'])
 
515
                if '@' in reviewer:
 
516
                    user = self.gh._get_user_by_email(reviewer)
 
517
                else:
 
518
                    user = self.gh._get_user(reviewer)
 
519
                pull_request.assignees.append(user['login'])
467
520
        if labels:
468
521
            for label in labels:
469
522
                pull_request.issue.labels.append(label)