/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.431.5 by Jelmer Vernooij
Initial work on gitlab 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 GitLab."""
18
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
19
from __future__ import absolute_import
20
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
21
from ... import (
0.431.33 by Jelmer Vernooij
Fix URLs from gitlab.
22
    branch as _mod_branch,
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
23
    controldir,
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
24
    errors,
25
    urlutils,
26
    )
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
27
from ...git.urls import git_url_to_bzr_url
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
28
from ...sixish import PY3
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
29
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
30
from .propose import (
0.432.2 by Jelmer Vernooij
Publish command sort of works.
31
    Hoster,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
32
    MergeProposal,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
33
    MergeProposalBuilder,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
34
    MergeProposalExists,
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
35
    NoSuchProject,
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
36
    PrerequisiteBranchUnsupported,
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
37
    UnsupportedHoster,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
38
    )
39
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
40
def mp_status_to_status(status):
41
    return {
42
        'all': 'all',
43
        'open': 'opened',
44
        'merged': 'merged',
45
        'closed': 'closed'}[status]
46
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
47
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
48
class NotGitLabUrl(errors.BzrError):
49
50
    _fmt = "Not a GitLab URL: %(url)s"
51
52
    def __init__(self, url):
53
        errors.BzrError.__init__(self)
54
        self.url = url
55
56
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
57
class DifferentGitLabInstances(errors.BzrError):
58
59
    _fmt = ("Can't create merge proposals across GitLab instances: "
60
            "%(source_host)s and %(target_host)s")
61
62
    def __init__(self, source_host, target_host):
63
        self.source_host = source_host
64
        self.target_host = target_host
65
66
0.432.10 by Jelmer Vernooij
More test fixes.
67
class GitLabLoginMissing(errors.BzrError):
68
69
    _fmt = ("Please log into GitLab")
70
71
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
72
def default_config_path():
73
    from breezy.config import config_dir
74
    import os
75
    return os.path.join(config_dir(), 'gitlab.conf')
76
77
78
def store_gitlab_token(name, url, private_token):
79
    """Store a GitLab token in a configuration file."""
80
    import configparser
81
    config = configparser.ConfigParser()
82
    path = default_config_path()
83
    config.read([path])
84
    config.add_section(name)
85
    config[name]['url'] = url
86
    config[name]['private_token'] = private_token
87
    with open(path, 'w') as f:
88
        config.write(f)
89
90
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
91
def iter_tokens():
92
    import configparser
93
    from gitlab.config import _DEFAULT_FILES
94
    config = configparser.ConfigParser()
95
    config.read(_DEFAULT_FILES + [default_config_path()])
96
    for name, section in config.items():
97
        yield name, section
98
99
0.432.10 by Jelmer Vernooij
More test fixes.
100
def connect_gitlab(host):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
101
    from gitlab import Gitlab, GitlabGetError
0.432.10 by Jelmer Vernooij
More test fixes.
102
    url = 'https://%s' % host
7268.3.1 by Jelmer Vernooij
Drop support for getting gitlab authentication from authentication.conf.
103
    for name, section in iter_tokens():
104
        if section.get('url') == url:
105
            return Gitlab(**section)
0.432.10 by Jelmer Vernooij
More test fixes.
106
    else:
7268.3.1 by Jelmer Vernooij
Drop support for getting gitlab authentication from authentication.conf.
107
        try:
108
            return Gitlab(url)
109
        except GitlabGetError:
110
            raise GitLabLoginMissing()
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
111
112
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
113
def parse_gitlab_url(url):
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
114
    (scheme, user, password, host, port, path) = urlutils.parse_url(
115
        url)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
116
    if scheme not in ('git+ssh', 'https', 'http'):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
117
        raise NotGitLabUrl(url)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
118
    if not host:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
119
        raise NotGitLabUrl(url)
0.432.10 by Jelmer Vernooij
More test fixes.
120
    path = path.strip('/')
0.432.11 by Jelmer Vernooij
Fix some tests.
121
    if path.endswith('.git'):
122
        path = path[:-4]
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
123
    return host, path
124
125
126
def parse_gitlab_branch_url(branch):
127
    url = urlutils.split_segment_parameters(branch.user_url)[0]
128
    host, path = parse_gitlab_url(url)
0.432.10 by Jelmer Vernooij
More test fixes.
129
    return host, path, branch.name
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
130
131
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
132
class GitLabMergeProposal(MergeProposal):
133
134
    def __init__(self, mr):
135
        self._mr = mr
136
137
    @property
138
    def url(self):
139
        return self._mr.web_url
140
141
    def get_description(self):
142
        return self._mr.description
143
144
    def set_description(self, description):
145
        self._mr.description = description
7265.1.1 by Jelmer Vernooij
Fix setting of merge proposal descriptions on gitlab.
146
        self._mr.save()
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
147
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
148
    def _branch_url_from_project(self, project_id, branch_name):
149
        project = self._mr.manager.gitlab.projects.get(project_id)
150
        return gitlab_url_to_bzr_url(project.http_url_to_repo, branch_name)
151
152
    def get_source_branch_url(self):
153
        return self._branch_url_from_project(
154
            self._mr.source_project_id, self._mr.source_branch)
155
156
    def get_target_branch_url(self):
157
        return self._branch_url_from_project(
158
            self._mr.target_project_id, self._mr.target_branch)
159
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
160
    def is_merged(self):
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
161
        return (self._mr.state == 'merged')
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
162
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
163
    def close(self):
164
        self._mr.state_event = 'close'
165
        self._mr.save()
166
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
167
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
168
def gitlab_url_to_bzr_url(url, name):
169
    if not PY3:
170
        name = name.encode('utf-8')
171
    return urlutils.join_segment_parameters(
7211.13.7 by Jelmer Vernooij
Fix formatting.
172
        git_url_to_bzr_url(url), {"branch": name})
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
173
174
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
175
class GitLab(Hoster):
176
    """GitLab hoster implementation."""
177
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
178
    supports_merge_proposal_labels = True
179
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
180
    def __repr__(self):
181
        return "<GitLab(%r)>" % self.gl.url
182
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
183
    @property
184
    def base_url(self):
185
        return self.gl.url
186
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
187
    def __init__(self, gl):
188
        self.gl = gl
189
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
190
    def get_push_url(self, branch):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
191
        (host, project_name, branch_name) = parse_gitlab_branch_url(branch)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
192
        project = self.gl.projects.get(project_name)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
193
        return gitlab_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
194
            project.ssh_url_to_repo, branch_name)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
195
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
196
    def publish_derived(self, local_branch, base_branch, name, project=None,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
197
                        owner=None, revision_id=None, overwrite=False,
198
                        allow_lossy=True):
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
199
        import gitlab
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
200
        (host, base_project, base_branch_name) = parse_gitlab_branch_url(base_branch)
0.432.10 by Jelmer Vernooij
More test fixes.
201
        self.gl.auth()
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
202
        try:
203
            base_project = self.gl.projects.get(base_project)
204
        except gitlab.GitlabGetError as e:
205
            if e.response_code == 404:
206
                raise NoSuchProject(base_project)
207
            else:
208
                raise
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
209
        if owner is None:
0.432.10 by Jelmer Vernooij
More test fixes.
210
            owner = self.gl.user.username
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
211
        if project is None:
0.431.30 by Jelmer Vernooij
s/name/path.
212
            project = base_project.path
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
213
        try:
0.432.10 by Jelmer Vernooij
More test fixes.
214
            target_project = self.gl.projects.get('%s/%s' % (owner, project))
0.431.30 by Jelmer Vernooij
s/name/path.
215
        except gitlab.GitlabGetError as e:
216
            if e.response_code == 404:
217
                target_project = base_project.forks.create({})
218
            else:
219
                raise
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
220
        remote_repo_url = git_url_to_bzr_url(target_project.ssh_url_to_repo)
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
221
        remote_dir = controldir.ControlDir.open(remote_repo_url)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
222
        try:
7211.13.7 by Jelmer Vernooij
Fix formatting.
223
            push_result = remote_dir.push_branch(
224
                local_branch, revision_id=revision_id, overwrite=overwrite,
225
                name=name)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
226
        except errors.NoRoundtrippingSupport:
227
            if not allow_lossy:
228
                raise
7211.13.7 by Jelmer Vernooij
Fix formatting.
229
            push_result = remote_dir.push_branch(
230
                local_branch, revision_id=revision_id, overwrite=overwrite,
231
                name=name, lossy=True)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
232
        public_url = gitlab_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
233
            target_project.http_url_to_repo, name)
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
234
        return push_result.target_branch, public_url
0.432.4 by Jelmer Vernooij
Some work on gitlab.
235
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
236
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
237
        import gitlab
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
238
        (host, base_project, base_branch_name) = parse_gitlab_branch_url(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
239
        self.gl.auth()
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
240
        try:
241
            base_project = self.gl.projects.get(base_project)
242
        except gitlab.GitlabGetError as e:
243
            if e.response_code == 404:
244
                raise NoSuchProject(base_project)
245
            else:
246
                raise
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
247
        if owner is None:
248
            owner = self.gl.user.username
249
        if project is None:
0.431.30 by Jelmer Vernooij
s/name/path.
250
            project = base_project.path
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
251
        try:
252
            target_project = self.gl.projects.get('%s/%s' % (owner, project))
253
        except gitlab.GitlabGetError as e:
254
            if e.response_code == 404:
255
                raise errors.NotBranchError('%s/%s/%s' % (self.gl.url, owner, project))
256
            raise
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
257
        return _mod_branch.Branch.open(gitlab_url_to_bzr_url(
7233.3.2 by Jelmer Vernooij
Merge lp:brz-propose.
258
            target_project.ssh_url_to_repo, name))
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
259
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
260
    def get_proposer(self, source_branch, target_branch):
261
        return GitlabMergeProposalBuilder(self.gl, source_branch, target_branch)
262
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
263
    def iter_proposals(self, source_branch, target_branch, status):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
264
        import gitlab
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
265
        (source_host, source_project_name, source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
266
            parse_gitlab_branch_url(source_branch))
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
267
        (target_host, target_project_name, target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
268
            parse_gitlab_branch_url(target_branch))
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
269
        if source_host != target_host:
270
            raise DifferentGitLabInstances(source_host, target_host)
271
        self.gl.auth()
272
        source_project = self.gl.projects.get(source_project_name)
273
        target_project = self.gl.projects.get(target_project_name)
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
274
        state = mp_status_to_status(status)
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
275
        try:
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
276
            for mr in target_project.mergerequests.list(state=state):
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
277
                if (mr.source_project_id != source_project.id or
7233.3.2 by Jelmer Vernooij
Merge lp:brz-propose.
278
                        mr.source_branch != source_branch_name or
279
                        mr.target_project_id != target_project.id or
280
                        mr.target_branch != target_branch_name):
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
281
                    continue
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
282
                yield GitLabMergeProposal(mr)
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
283
        except gitlab.GitlabListError as e:
284
            if e.response_code == 403:
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
285
                raise errors.PermissionDenied(e.error_message)
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
            (host, project, branch_name) = parse_gitlab_branch_url(branch)
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
290
        except NotGitLabUrl:
291
            return False
292
        return (self.gl.url == ('https://%s' % host))
293
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
294
    @classmethod
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
295
    def probe_from_url(cls, url):
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
296
        try:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
297
            (host, project) = parse_gitlab_url(url)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
298
        except NotGitLabUrl:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
299
            raise UnsupportedHoster(url)
0.432.4 by Jelmer Vernooij
Some work on gitlab.
300
        import gitlab
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
301
        import requests.exceptions
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
302
        try:
0.432.4 by Jelmer Vernooij
Some work on gitlab.
303
            gl = connect_gitlab(host)
0.431.10 by Jelmer Vernooij
Various other fixes.
304
            gl.auth()
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
305
        except requests.exceptions.SSLError:
7211.13.7 by Jelmer Vernooij
Fix formatting.
306
            # Well, I guess it could be..
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
307
            raise UnsupportedHoster(url)
0.432.4 by Jelmer Vernooij
Some work on gitlab.
308
        except gitlab.GitlabGetError:
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
309
            raise UnsupportedHoster(url)
0.431.10 by Jelmer Vernooij
Various other fixes.
310
        except gitlab.GitlabHttpError as e:
0.431.27 by Jelmer Vernooij
Catch 503 errors.
311
            if e.response_code in (404, 405, 503):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
312
                raise UnsupportedHoster(url)
0.431.10 by Jelmer Vernooij
Various other fixes.
313
            else:
314
                raise
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
315
        return cls(gl)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
316
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
317
    @classmethod
318
    def iter_instances(cls):
319
        from gitlab import Gitlab
320
        for name, credentials in iter_tokens():
321
            if 'url' not in credentials:
322
                continue
323
            gl = Gitlab(**credentials)
324
            yield cls(gl)
325
0.431.66 by Jelmer Vernooij
Add support for status argument.
326
    def iter_my_proposals(self, status='open'):
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
327
        state = mp_status_to_status(status)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
328
        self.gl.auth()
0.431.66 by Jelmer Vernooij
Add support for status argument.
329
        for mp in self.gl.mergerequests.list(
330
                owner=self.gl.user.username, state=state):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
331
            yield GitLabMergeProposal(mp)
332
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
333
0.432.2 by Jelmer Vernooij
Publish command sort of works.
334
class GitlabMergeProposalBuilder(MergeProposalBuilder):
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
335
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
336
    def __init__(self, gl, source_branch, target_branch):
337
        self.gl = gl
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
338
        self.source_branch = source_branch
339
        (self.source_host, self.source_project_name, self.source_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
340
            parse_gitlab_branch_url(source_branch))
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
341
        self.target_branch = target_branch
342
        (self.target_host, self.target_project_name, self.target_branch_name) = (
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
343
            parse_gitlab_branch_url(target_branch))
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
344
        if self.source_host != self.target_host:
345
            raise DifferentGitLabInstances(self.source_host, self.target_host)
346
347
    def get_infotext(self):
348
        """Determine the initial comment for the merge proposal."""
349
        info = []
350
        info.append("Gitlab instance: %s\n" % self.target_host)
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
351
        info.append("Source: %s\n" % self.source_branch.user_url)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
352
        info.append("Target: %s\n" % self.target_branch.user_url)
353
        return ''.join(info)
354
355
    def get_initial_body(self):
356
        """Get a body for the proposal for the user to modify.
357
358
        :return: a str or None.
359
        """
360
        return None
361
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
362
    def create_proposal(self, description, reviewers=None, labels=None,
363
                        prerequisite_branch=None):
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
364
        """Perform the submission."""
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
365
        if prerequisite_branch is not None:
366
            raise PrerequisiteBranchUnsupported(self)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
367
        import gitlab
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
368
        # TODO(jelmer): Support reviewers
0.432.10 by Jelmer Vernooij
More test fixes.
369
        self.gl.auth()
370
        source_project = self.gl.projects.get(self.source_project_name)
371
        target_project = self.gl.projects.get(self.target_project_name)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
372
        # TODO(jelmer): Allow setting title explicitly
373
        title = description.splitlines()[0]
374
        # TODO(jelmer): Allow setting allow_collaboration field
375
        # TODO(jelmer): Allow setting milestone field
376
        # TODO(jelmer): Allow setting squash field
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
377
        kwargs = {
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
378
            'title': title,
379
            'target_project_id': target_project.id,
380
            'source_branch': self.source_branch_name,
381
            'target_branch': self.target_branch_name,
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
382
            'description': description}
383
        if labels:
384
            kwargs['labels'] = ','.join(labels)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
385
        try:
386
            merge_request = source_project.mergerequests.create(kwargs)
387
        except gitlab.GitlabCreateError as e:
0.431.34 by Jelmer Vernooij
Cope with gitlab 403.
388
            if e.response_code == 403:
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
389
                raise errors.PermissionDenied(e.error_message)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
390
            if e.response_code == 409:
391
                raise MergeProposalExists(self.source_branch.user_url)
392
            raise
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
393
        return GitLabMergeProposal(merge_request)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
394
395
396
def register_gitlab_instance(shortname, url):
397
    """Register a gitlab instance.
398
399
    :param shortname: Short name (e.g. "gitlab")
400
    :param url: URL to the gitlab instance
401
    """
402
    from breezy.bugtracker import (
403
        tracker_registry,
404
        ProjectIntegerBugTracker,
405
        )
406
    tracker_registry.register(
407
        shortname, ProjectIntegerBugTracker(
408
            shortname, url + '/{project}/issues/{id}'))