/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
1
# Copyright (C) 2018 Breezy Developers
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
0.434.1 by Jelmer Vernooij
Use absolute_import.
17
"""Support for GitHub."""
18
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
19
from __future__ import absolute_import
20
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
21
import os
22
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
23
from .propose import (
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
24
    Hoster,
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
25
    HosterLoginRequired,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
26
    MergeProposal,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
27
    MergeProposalBuilder,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
28
    MergeProposalExists,
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
29
    PrerequisiteBranchUnsupported,
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
30
    UnsupportedHoster,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
31
    )
32
33
from ... import (
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
34
    branch as _mod_branch,
0.432.3 by Jelmer Vernooij
Publish command works for github.
35
    controldir,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
36
    errors,
37
    hooks,
38
    urlutils,
0.432.3 by Jelmer Vernooij
Publish command works for github.
39
    version_string as breezy_version,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
40
    )
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
41
from ...config import AuthenticationConfig, GlobalStack, config_dir
0.431.32 by Jelmer Vernooij
Properly resolve git+ssh URLs.
42
from ...git.urls import git_url_to_bzr_url
0.432.3 by Jelmer Vernooij
Publish command works for github.
43
from ...i18n import gettext
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
44
from ...sixish import PY3
0.432.3 by Jelmer Vernooij
Publish command works for github.
45
from ...trace import note
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
46
from ...lazy_import import lazy_import
47
lazy_import(globals(), """
48
from github import Github
49
""")
50
51
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
52
def store_github_token(scheme, host, token):
53
    with open(os.path.join(config_dir(), 'github.conf'), 'w') as f:
54
        f.write(token)
55
56
57
def retrieve_github_token(scheme, host):
58
    path = os.path.join(config_dir(), 'github.conf')
59
    if not os.path.exists(path):
60
        return None
0.435.1 by Jelmer Vernooij
Fix reading github credentials.
61
    with open(path, 'r') as f:
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
62
        return f.read().strip()
63
64
0.431.44 by Jelmer Vernooij
Support get/set description.
65
def determine_title(description):
66
    return description.splitlines()[0]
67
68
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
69
class NotGitHubUrl(errors.BzrError):
70
71
    _fmt = "Not a GitHub URL: %(url)s"
72
73
    def __init__(self, url):
74
        errors.BzrError.__init__(self)
75
        self.url = url
76
77
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
78
class GitHubLoginRequired(HosterLoginRequired):
79
80
    _fmt = "Action requires GitHub login."
81
82
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
83
def connect_github():
7211.13.7 by Jelmer Vernooij
Fix formatting.
84
    """Connect to GitHub.
85
    """
86
    user_agent = "Breezy/%s" % breezy_version
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
87
88
    auth = AuthenticationConfig()
89
90
    credentials = auth.get_credentials('https', 'github.com')
91
    if credentials is not None:
0.432.3 by Jelmer Vernooij
Publish command works for github.
92
        return Github(credentials['user'], credentials['password'],
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
93
                      user_agent=user_agent)
94
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
95
    # TODO(jelmer): token = auth.get_token('https', 'github.com')
96
    token = retrieve_github_token('https', 'github.com')
97
    if token is not None:
0.431.61 by Jelmer Vernooij
Fix token login.
98
        return Github(token, user_agent=user_agent)
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
99
    else:
100
        note('Accessing GitHub anonymously. To log in, run \'brz gh-login\'.')
101
        return Github(user_agent=user_agent)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
102
103
0.431.44 by Jelmer Vernooij
Support get/set description.
104
class GitHubMergeProposal(MergeProposal):
105
106
    def __init__(self, pr):
107
        self._pr = pr
108
109
    @property
110
    def url(self):
111
        return self._pr.html_url
112
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
113
    def _branch_from_part(self, part):
114
        return github_url_to_bzr_url(part.repo.html_url, part.ref)
115
116
    def get_source_branch_url(self):
117
        return self._branch_from_part(self._pr.head)
118
119
    def get_target_branch_url(self):
120
        return self._branch_from_part(self._pr.base)
121
0.431.44 by Jelmer Vernooij
Support get/set description.
122
    def get_description(self):
123
        return self._pr.body
124
125
    def set_description(self, description):
126
        self._pr.edit(body=description, title=determine_title(description))
127
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
128
    def is_merged(self):
129
        return self._pr.merged
130
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
131
    def close(self):
132
        self._pr.edit(state='closed')
133
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
134
    def merge(self, commit_message=None):
135
        # https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button
136
        self._pr.merge(commit_message=commit_message)
137
0.431.44 by Jelmer Vernooij
Support get/set description.
138
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
139
def parse_github_url(url):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
140
    (scheme, user, password, host, port, path) = urlutils.parse_url(
141
        url)
142
    if host != 'github.com':
143
        raise NotGitHubUrl(url)
144
    (owner, repo_name) = path.strip('/').split('/')
0.432.12 by Jelmer Vernooij
Fix .git ends.
145
    if repo_name.endswith('.git'):
146
        repo_name = repo_name[:-4]
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
147
    return owner, repo_name
148
149
150
def parse_github_branch_url(branch):
151
    url = urlutils.split_segment_parameters(branch.user_url)[0]
152
    owner, repo_name = parse_github_url(url)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
153
    return owner, repo_name, branch.name
154
155
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
156
def github_url_to_bzr_url(url, branch_name):
157
    if not PY3:
158
        branch_name = branch_name.encode('utf-8')
159
    return urlutils.join_segment_parameters(
7211.13.7 by Jelmer Vernooij
Fix formatting.
160
        git_url_to_bzr_url(url), {"branch": branch_name})
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
161
162
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
163
def convert_github_error(fn):
164
    def convert(self, *args, **kwargs):
165
        import github
166
        try:
167
            return fn(self, *args, **kwargs)
168
        except github.GithubException as e:
169
            if e.args[0] == 401:
170
                raise GitHubLoginRequired(self)
171
            raise
172
    return convert
173
174
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
175
class GitHub(Hoster):
176
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
177
    name = 'github'
178
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
179
    supports_merge_proposal_labels = True
180
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
181
    def __repr__(self):
182
        return "GitHub()"
183
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
184
    @property
185
    def base_url(self):
186
        # TODO(jelmer): Can we get the default URL from the Python API package
187
        # somehow?
188
        return "https://github.com"
189
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
190
    def __init__(self):
191
        self.gh = connect_github()
192
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
193
    @convert_github_error
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
194
    def publish_derived(self, local_branch, base_branch, name, project=None,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
195
                        owner=None, revision_id=None, overwrite=False,
196
                        allow_lossy=True):
0.432.12 by Jelmer Vernooij
Fix .git ends.
197
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
198
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
199
        base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
0.432.3 by Jelmer Vernooij
Publish command works for github.
200
        if owner is None:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
201
            owner = self.gh.get_user().login
0.432.3 by Jelmer Vernooij
Publish command works for github.
202
        if project is None:
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
203
            project = base_repo.name
0.432.3 by Jelmer Vernooij
Publish command works for github.
204
        try:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
205
            remote_repo = self.gh.get_repo('%s/%s' % (owner, project))
0.432.12 by Jelmer Vernooij
Fix .git ends.
206
            remote_repo.id
207
        except github.UnknownObjectException:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
208
            base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
209
            if owner == self.gh.get_user().login:
210
                owner_obj = self.gh.get_user()
0.432.3 by Jelmer Vernooij
Publish command works for github.
211
            else:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
212
                owner_obj = self.gh.get_organization(owner)
0.432.12 by Jelmer Vernooij
Fix .git ends.
213
            remote_repo = owner_obj.create_fork(base_repo)
0.432.3 by Jelmer Vernooij
Publish command works for github.
214
            note(gettext('Forking new repository %s from %s') %
7211.13.7 by Jelmer Vernooij
Fix formatting.
215
                 (remote_repo.html_url, base_repo.html_url))
0.432.3 by Jelmer Vernooij
Publish command works for github.
216
        else:
217
            note(gettext('Reusing existing repository %s') % remote_repo.html_url)
0.431.32 by Jelmer Vernooij
Properly resolve git+ssh URLs.
218
        remote_dir = controldir.ControlDir.open(git_url_to_bzr_url(remote_repo.ssh_url))
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
219
        try:
7211.13.7 by Jelmer Vernooij
Fix formatting.
220
            push_result = remote_dir.push_branch(
221
                local_branch, revision_id=revision_id, overwrite=overwrite,
222
                name=name)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
223
        except errors.NoRoundtrippingSupport:
224
            if not allow_lossy:
225
                raise
7211.13.7 by Jelmer Vernooij
Fix formatting.
226
            push_result = remote_dir.push_branch(
227
                local_branch, revision_id=revision_id,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
228
                overwrite=overwrite, name=name, lossy=True)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
229
        return push_result.target_branch, github_url_to_bzr_url(
7211.13.7 by Jelmer Vernooij
Fix formatting.
230
            remote_repo.html_url, name)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
231
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
232
    @convert_github_error
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
233
    def get_push_url(self, branch):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
234
        owner, project, branch_name = parse_github_branch_url(branch)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
235
        repo = self.gh.get_repo('%s/%s' % (owner, project))
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
236
        return github_url_to_bzr_url(repo.ssh_url, branch_name)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
237
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
238
    @convert_github_error
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
239
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
240
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
241
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
242
        base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
243
        if owner is None:
244
            owner = self.gh.get_user().login
245
        if project is None:
246
            project = base_repo.name
247
        try:
248
            remote_repo = self.gh.get_repo('%s/%s' % (owner, project))
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
249
            full_url = github_url_to_bzr_url(remote_repo.ssh_url, name)
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
250
            return _mod_branch.Branch.open(full_url)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
251
        except github.UnknownObjectException:
252
            raise errors.NotBranchError('https://github.com/%s/%s' % (owner, project))
253
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
254
    @convert_github_error
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
255
    def get_proposer(self, source_branch, target_branch):
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
256
        return GitHubMergeProposalBuilder(self.gh, source_branch, target_branch)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
257
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
258
    @convert_github_error
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
259
    def iter_proposals(self, source_branch, target_branch, status='open'):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
260
        (source_owner, source_repo_name, source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
261
            parse_github_branch_url(source_branch))
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
262
        (target_owner, target_repo_name, target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
263
            parse_github_branch_url(target_branch))
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
264
        target_repo = self.gh.get_repo(
265
            "%s/%s" % (target_owner, target_repo_name))
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
266
        state = {
267
            'open': 'open',
268
            'merged': 'closed',
269
            'closed': 'closed',
270
            'all': 'all'}
271
        for pull in target_repo.get_pulls(
272
                head=target_branch_name,
273
                state=state[status]):
274
            if (status == 'closed' and pull.merged or
275
                    status == 'merged' and not pull.merged):
276
                continue
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
277
            if pull.head.ref != source_branch_name:
278
                continue
7268.4.1 by Jelmer Vernooij
Don't attempt to resolve None when repo has gone away.
279
            if pull.head.repo is None:
280
                # Repo has gone the way of the dodo
281
                continue
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
282
            if (pull.head.repo.owner.login != source_owner or
7211.13.7 by Jelmer Vernooij
Fix formatting.
283
                    pull.head.repo.name != source_repo_name):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
284
                continue
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
285
            yield GitHubMergeProposal(pull)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
286
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
287
    def hosts(self, branch):
288
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
289
            parse_github_branch_url(branch)
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
290
        except NotGitHubUrl:
291
            return False
292
        else:
293
            return True
294
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
295
    @classmethod
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
296
    def probe_from_url(cls, url):
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
297
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
298
            parse_github_url(url)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
299
        except NotGitHubUrl:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
300
            raise UnsupportedHoster(url)
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
301
        return cls()
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
302
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
303
    @classmethod
304
    def iter_instances(cls):
305
        yield cls()
306
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
307
    @convert_github_error
0.431.66 by Jelmer Vernooij
Add support for status argument.
308
    def iter_my_proposals(self, status='open'):
309
        query = ['is:pr']
310
        if status == 'open':
311
            query.append('is:open')
312
        elif status == 'closed':
313
            query.append('is:unmerged')
7268.2.1 by Jelmer Vernooij
Don't include open unmerged pull requests in 'closed'.
314
            # Also use "is:closed" otherwise unmerged open pull requests are
315
            # also included.
316
            query.append('is:closed')
0.431.66 by Jelmer Vernooij
Add support for status argument.
317
        elif status == 'merged':
318
            query.append('is:merged')
319
        query.append('author:%s' % self.gh.get_user().login)
320
        for issue in self.gh.search_issues(query=' '.join(query)):
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
321
            yield GitHubMergeProposal(issue.as_pull_request())
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
322
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
323
    @convert_github_error
324
    def get_proposal_by_url(self, url):
325
        raise UnsupportedHoster(url)
326
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
327
0.432.2 by Jelmer Vernooij
Publish command sort of works.
328
class GitHubMergeProposalBuilder(MergeProposalBuilder):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
329
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
330
    def __init__(self, gh, source_branch, target_branch):
331
        self.gh = gh
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
332
        self.source_branch = source_branch
333
        self.target_branch = target_branch
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
334
        (self.target_owner, self.target_repo_name, self.target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
335
            parse_github_branch_url(self.target_branch))
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
336
        (self.source_owner, self.source_repo_name, self.source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
337
            parse_github_branch_url(self.source_branch))
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
338
339
    def get_infotext(self):
340
        """Determine the initial comment for the merge proposal."""
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
341
        info = []
342
        info.append("Merge %s into %s:%s\n" % (
343
            self.source_branch_name, self.target_owner,
344
            self.target_branch_name))
345
        info.append("Source: %s\n" % self.source_branch.user_url)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
346
        info.append("Target: %s\n" % self.target_branch.user_url)
347
        return ''.join(info)
348
349
    def get_initial_body(self):
350
        """Get a body for the proposal for the user to modify.
351
352
        :return: a str or None.
353
        """
354
        return None
355
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
356
    def create_proposal(self, description, reviewers=None, labels=None,
357
                        prerequisite_branch=None):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
358
        """Perform the submission."""
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
359
        if prerequisite_branch is not None:
360
            raise PrerequisiteBranchUnsupported(self)
0.432.10 by Jelmer Vernooij
More test fixes.
361
        import github
0.432.7 by Jelmer Vernooij
propose works \o/
362
        # TODO(jelmer): Probe for right repo name
0.432.12 by Jelmer Vernooij
Fix .git ends.
363
        if self.target_repo_name.endswith('.git'):
364
            self.target_repo_name = self.target_repo_name[:-4]
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
365
        target_repo = self.gh.get_repo("%s/%s" % (self.target_owner, self.target_repo_name))
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
366
        # TODO(jelmer): Allow setting title explicitly?
0.431.44 by Jelmer Vernooij
Support get/set description.
367
        title = determine_title(description)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
368
        # TOOD(jelmer): Set maintainers_can_modify?
0.432.10 by Jelmer Vernooij
More test fixes.
369
        try:
370
            pull_request = target_repo.create_pull(
371
                title=title, body=description,
372
                head="%s:%s" % (self.source_owner, self.source_branch_name),
373
                base=self.target_branch_name)
374
        except github.GithubException as e:
375
            if e.status == 422:
376
                raise MergeProposalExists(self.source_branch.user_url)
377
            raise
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
378
        if reviewers:
379
            for reviewer in reviewers:
380
                pull_request.assignees.append(
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
381
                    self.gh.get_user(reviewer))
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
382
        if labels:
383
            for label in labels:
384
                pull_request.issue.labels.append(label)
0.431.44 by Jelmer Vernooij
Support get/set description.
385
        return GitHubMergeProposal(pull_request)