/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,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
30
    CommitMessageUnsupported,
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
31
    UnsupportedHoster,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
32
    )
33
34
from ... import (
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
35
    branch as _mod_branch,
0.432.3 by Jelmer Vernooij
Publish command works for github.
36
    controldir,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
37
    errors,
38
    hooks,
39
    urlutils,
0.432.3 by Jelmer Vernooij
Publish command works for github.
40
    version_string as breezy_version,
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
41
    )
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
42
from ...config import AuthenticationConfig, GlobalStack, config_dir
0.431.32 by Jelmer Vernooij
Properly resolve git+ssh URLs.
43
from ...git.urls import git_url_to_bzr_url
0.432.3 by Jelmer Vernooij
Publish command works for github.
44
from ...i18n import gettext
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
45
from ...sixish import PY3
0.432.3 by Jelmer Vernooij
Publish command works for github.
46
from ...trace import note
7296.10.5 by Jelmer Vernooij
use default_user_agent function.
47
from ...transport.http import default_user_agent
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
48
from ...lazy_import import lazy_import
49
lazy_import(globals(), """
50
from github import Github
51
""")
52
53
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
54
def store_github_token(scheme, host, token):
55
    with open(os.path.join(config_dir(), 'github.conf'), 'w') as f:
56
        f.write(token)
57
58
59
def retrieve_github_token(scheme, host):
60
    path = os.path.join(config_dir(), 'github.conf')
61
    if not os.path.exists(path):
62
        return None
0.435.1 by Jelmer Vernooij
Fix reading github credentials.
63
    with open(path, 'r') as f:
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
64
        return f.read().strip()
65
66
0.431.44 by Jelmer Vernooij
Support get/set description.
67
def determine_title(description):
68
    return description.splitlines()[0]
69
70
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
71
class NotGitHubUrl(errors.BzrError):
72
73
    _fmt = "Not a GitHub URL: %(url)s"
74
75
    def __init__(self, url):
76
        errors.BzrError.__init__(self)
77
        self.url = url
78
79
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
80
class GitHubLoginRequired(HosterLoginRequired):
81
82
    _fmt = "Action requires GitHub login."
83
84
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
85
def connect_github():
7211.13.7 by Jelmer Vernooij
Fix formatting.
86
    """Connect to GitHub.
87
    """
7296.10.5 by Jelmer Vernooij
use default_user_agent function.
88
    user_agent = default_user_agent()
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
89
    auth = AuthenticationConfig()
90
91
    credentials = auth.get_credentials('https', 'github.com')
92
    if credentials is not None:
0.432.3 by Jelmer Vernooij
Publish command works for github.
93
        return Github(credentials['user'], credentials['password'],
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
94
                      user_agent=user_agent)
95
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
96
    # TODO(jelmer): token = auth.get_token('https', 'github.com')
97
    token = retrieve_github_token('https', 'github.com')
98
    if token is not None:
0.431.61 by Jelmer Vernooij
Fix token login.
99
        return Github(token, user_agent=user_agent)
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
100
    else:
101
        note('Accessing GitHub anonymously. To log in, run \'brz gh-login\'.')
102
        return Github(user_agent=user_agent)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
103
104
0.431.44 by Jelmer Vernooij
Support get/set description.
105
class GitHubMergeProposal(MergeProposal):
106
107
    def __init__(self, pr):
108
        self._pr = pr
109
110
    @property
111
    def url(self):
112
        return self._pr.html_url
113
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
114
    def _branch_from_part(self, part):
115
        return github_url_to_bzr_url(part.repo.html_url, part.ref)
116
117
    def get_source_branch_url(self):
118
        return self._branch_from_part(self._pr.head)
119
120
    def get_target_branch_url(self):
121
        return self._branch_from_part(self._pr.base)
122
0.431.44 by Jelmer Vernooij
Support get/set description.
123
    def get_description(self):
124
        return self._pr.body
125
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
126
    def get_commit_message(self):
127
        return None
128
0.431.44 by Jelmer Vernooij
Support get/set description.
129
    def set_description(self, description):
130
        self._pr.edit(body=description, title=determine_title(description))
131
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
132
    def is_merged(self):
133
        return self._pr.merged
134
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
135
    def close(self):
136
        self._pr.edit(state='closed')
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
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
180
    supports_merge_proposal_commit_message = False
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
181
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
182
    def __repr__(self):
183
        return "GitHub()"
184
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
185
    @property
186
    def base_url(self):
187
        # TODO(jelmer): Can we get the default URL from the Python API package
188
        # somehow?
189
        return "https://github.com"
190
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
191
    def __init__(self):
192
        self.gh = connect_github()
193
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
194
    @convert_github_error
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
195
    def publish_derived(self, local_branch, base_branch, name, project=None,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
196
                        owner=None, revision_id=None, overwrite=False,
197
                        allow_lossy=True):
0.432.12 by Jelmer Vernooij
Fix .git ends.
198
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
199
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
200
        base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
0.432.3 by Jelmer Vernooij
Publish command works for github.
201
        if owner is None:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
202
            owner = self.gh.get_user().login
0.432.3 by Jelmer Vernooij
Publish command works for github.
203
        if project is None:
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
204
            project = base_repo.name
0.432.3 by Jelmer Vernooij
Publish command works for github.
205
        try:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
206
            remote_repo = self.gh.get_repo('%s/%s' % (owner, project))
0.432.12 by Jelmer Vernooij
Fix .git ends.
207
            remote_repo.id
208
        except github.UnknownObjectException:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
209
            base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
210
            if owner == self.gh.get_user().login:
211
                owner_obj = self.gh.get_user()
0.432.3 by Jelmer Vernooij
Publish command works for github.
212
            else:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
213
                owner_obj = self.gh.get_organization(owner)
0.432.12 by Jelmer Vernooij
Fix .git ends.
214
            remote_repo = owner_obj.create_fork(base_repo)
0.432.3 by Jelmer Vernooij
Publish command works for github.
215
            note(gettext('Forking new repository %s from %s') %
7211.13.7 by Jelmer Vernooij
Fix formatting.
216
                 (remote_repo.html_url, base_repo.html_url))
0.432.3 by Jelmer Vernooij
Publish command works for github.
217
        else:
218
            note(gettext('Reusing existing repository %s') % remote_repo.html_url)
0.431.32 by Jelmer Vernooij
Properly resolve git+ssh URLs.
219
        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.
220
        try:
7211.13.7 by Jelmer Vernooij
Fix formatting.
221
            push_result = remote_dir.push_branch(
222
                local_branch, revision_id=revision_id, overwrite=overwrite,
223
                name=name)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
224
        except errors.NoRoundtrippingSupport:
225
            if not allow_lossy:
226
                raise
7211.13.7 by Jelmer Vernooij
Fix formatting.
227
            push_result = remote_dir.push_branch(
228
                local_branch, revision_id=revision_id,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
229
                overwrite=overwrite, name=name, lossy=True)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
230
        return push_result.target_branch, github_url_to_bzr_url(
7211.13.7 by Jelmer Vernooij
Fix formatting.
231
            remote_repo.html_url, name)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
232
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
233
    @convert_github_error
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
234
    def get_push_url(self, branch):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
235
        owner, project, branch_name = parse_github_branch_url(branch)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
236
        repo = self.gh.get_repo('%s/%s' % (owner, project))
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
237
        return github_url_to_bzr_url(repo.ssh_url, branch_name)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
238
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
239
    @convert_github_error
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
240
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
241
        import github
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
242
        base_owner, base_project, base_branch_name = parse_github_branch_url(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
243
        base_repo = self.gh.get_repo('%s/%s' % (base_owner, base_project))
244
        if owner is None:
245
            owner = self.gh.get_user().login
246
        if project is None:
247
            project = base_repo.name
248
        try:
249
            remote_repo = self.gh.get_repo('%s/%s' % (owner, project))
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
250
            full_url = github_url_to_bzr_url(remote_repo.ssh_url, name)
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
251
            return _mod_branch.Branch.open(full_url)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
252
        except github.UnknownObjectException:
253
            raise errors.NotBranchError('https://github.com/%s/%s' % (owner, project))
254
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
255
    @convert_github_error
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
256
    def get_proposer(self, source_branch, target_branch):
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
257
        return GitHubMergeProposalBuilder(self.gh, source_branch, target_branch)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
258
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
259
    @convert_github_error
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
260
    def iter_proposals(self, source_branch, target_branch, status='open'):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
261
        (source_owner, source_repo_name, source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
262
            parse_github_branch_url(source_branch))
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
263
        (target_owner, target_repo_name, target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
264
            parse_github_branch_url(target_branch))
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
265
        target_repo = self.gh.get_repo(
266
            "%s/%s" % (target_owner, target_repo_name))
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
267
        state = {
268
            'open': 'open',
269
            'merged': 'closed',
270
            'closed': 'closed',
271
            'all': 'all'}
272
        for pull in target_repo.get_pulls(
273
                head=target_branch_name,
274
                state=state[status]):
275
            if (status == 'closed' and pull.merged or
276
                    status == 'merged' and not pull.merged):
277
                continue
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
278
            if pull.head.ref != source_branch_name:
279
                continue
7268.4.1 by Jelmer Vernooij
Don't attempt to resolve None when repo has gone away.
280
            if pull.head.repo is None:
281
                # Repo has gone the way of the dodo
282
                continue
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
283
            if (pull.head.repo.owner.login != source_owner or
7211.13.7 by Jelmer Vernooij
Fix formatting.
284
                    pull.head.repo.name != source_repo_name):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
285
                continue
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
286
            yield GitHubMergeProposal(pull)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
287
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
288
    def hosts(self, branch):
289
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
290
            parse_github_branch_url(branch)
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
291
        except NotGitHubUrl:
292
            return False
293
        else:
294
            return True
295
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
296
    @classmethod
7296.10.1 by Jelmer Vernooij
Initial work making gitlab just directly use ReST.
297
    def probe_from_url(cls, url, possible_transports=None):
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
298
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
299
            parse_github_url(url)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
300
        except NotGitHubUrl:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
301
            raise UnsupportedHoster(url)
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
302
        return cls()
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
303
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
304
    @classmethod
305
    def iter_instances(cls):
306
        yield cls()
307
7268.8.2 by Jelmer Vernooij
Handle GitHub errors.
308
    @convert_github_error
0.431.66 by Jelmer Vernooij
Add support for status argument.
309
    def iter_my_proposals(self, status='open'):
310
        query = ['is:pr']
311
        if status == 'open':
312
            query.append('is:open')
313
        elif status == 'closed':
314
            query.append('is:unmerged')
7268.2.1 by Jelmer Vernooij
Don't include open unmerged pull requests in 'closed'.
315
            # Also use "is:closed" otherwise unmerged open pull requests are
316
            # also included.
317
            query.append('is:closed')
0.431.66 by Jelmer Vernooij
Add support for status argument.
318
        elif status == 'merged':
319
            query.append('is:merged')
320
        query.append('author:%s' % self.gh.get_user().login)
321
        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.
322
            yield GitHubMergeProposal(issue.as_pull_request())
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
323
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
324
0.432.2 by Jelmer Vernooij
Publish command sort of works.
325
class GitHubMergeProposalBuilder(MergeProposalBuilder):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
326
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
327
    def __init__(self, gh, source_branch, target_branch):
328
        self.gh = gh
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
329
        self.source_branch = source_branch
330
        self.target_branch = target_branch
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
331
        (self.target_owner, self.target_repo_name, self.target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
332
            parse_github_branch_url(self.target_branch))
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
333
        (self.source_owner, self.source_repo_name, self.source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
334
            parse_github_branch_url(self.source_branch))
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
335
336
    def get_infotext(self):
337
        """Determine the initial comment for the merge proposal."""
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
338
        info = []
339
        info.append("Merge %s into %s:%s\n" % (
340
            self.source_branch_name, self.target_owner,
341
            self.target_branch_name))
342
        info.append("Source: %s\n" % self.source_branch.user_url)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
343
        info.append("Target: %s\n" % self.target_branch.user_url)
344
        return ''.join(info)
345
346
    def get_initial_body(self):
347
        """Get a body for the proposal for the user to modify.
348
349
        :return: a str or None.
350
        """
351
        return None
352
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
353
    def create_proposal(self, description, reviewers=None, labels=None,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
354
                        prerequisite_branch=None, commit_message=None):
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
355
        """Perform the submission."""
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
356
        if prerequisite_branch is not None:
357
            raise PrerequisiteBranchUnsupported(self)
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
358
        # Note that commit_message is ignored, since github doesn't support it.
0.432.10 by Jelmer Vernooij
More test fixes.
359
        import github
0.432.7 by Jelmer Vernooij
propose works \o/
360
        # TODO(jelmer): Probe for right repo name
0.432.12 by Jelmer Vernooij
Fix .git ends.
361
        if self.target_repo_name.endswith('.git'):
362
            self.target_repo_name = self.target_repo_name[:-4]
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
363
        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.
364
        # TODO(jelmer): Allow setting title explicitly?
0.431.44 by Jelmer Vernooij
Support get/set description.
365
        title = determine_title(description)
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
366
        # TOOD(jelmer): Set maintainers_can_modify?
0.432.10 by Jelmer Vernooij
More test fixes.
367
        try:
368
            pull_request = target_repo.create_pull(
369
                title=title, body=description,
370
                head="%s:%s" % (self.source_owner, self.source_branch_name),
371
                base=self.target_branch_name)
372
        except github.GithubException as e:
373
            if e.status == 422:
374
                raise MergeProposalExists(self.source_branch.user_url)
375
            raise
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
376
        if reviewers:
377
            for reviewer in reviewers:
378
                pull_request.assignees.append(
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
379
                    self.gh.get_user(reviewer))
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
380
        if labels:
381
            for label in labels:
382
                pull_request.issue.labels.append(label)
0.431.44 by Jelmer Vernooij
Support get/set description.
383
        return GitHubMergeProposal(pull_request)