/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
113
def parse_gitlab_url(branch):
114
    url = urlutils.split_segment_parameters(branch.user_url)[0]
115
    (scheme, user, password, host, port, path) = urlutils.parse_url(
116
        url)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
117
    if scheme not in ('git+ssh', 'https', 'http'):
118
        raise NotGitLabUrl(branch.user_url)
119
    if not host:
120
        raise NotGitLabUrl(branch.user_url)
0.432.10 by Jelmer Vernooij
More test fixes.
121
    path = path.strip('/')
0.432.11 by Jelmer Vernooij
Fix some tests.
122
    if path.endswith('.git'):
123
        path = path[:-4]
0.432.10 by Jelmer Vernooij
More test fixes.
124
    return host, path, branch.name
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
125
126
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
127
class GitLabMergeProposal(MergeProposal):
128
129
    def __init__(self, mr):
130
        self._mr = mr
131
132
    @property
133
    def url(self):
134
        return self._mr.web_url
135
136
    def get_description(self):
137
        return self._mr.description
138
139
    def set_description(self, description):
140
        self._mr.description = description
7265.1.1 by Jelmer Vernooij
Fix setting of merge proposal descriptions on gitlab.
141
        self._mr.save()
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
142
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
143
    def _branch_url_from_project(self, project_id, branch_name):
144
        project = self._mr.manager.gitlab.projects.get(project_id)
145
        return gitlab_url_to_bzr_url(project.http_url_to_repo, branch_name)
146
147
    def get_source_branch_url(self):
148
        return self._branch_url_from_project(
149
            self._mr.source_project_id, self._mr.source_branch)
150
151
    def get_target_branch_url(self):
152
        return self._branch_url_from_project(
153
            self._mr.target_project_id, self._mr.target_branch)
154
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
155
    def is_merged(self):
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
156
        return (self._mr.state == 'merged')
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
157
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
158
    def close(self):
159
        self._mr.state_event = 'close'
160
        self._mr.save()
161
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
162
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
163
def gitlab_url_to_bzr_url(url, name):
164
    if not PY3:
165
        name = name.encode('utf-8')
166
    return urlutils.join_segment_parameters(
7211.13.7 by Jelmer Vernooij
Fix formatting.
167
        git_url_to_bzr_url(url), {"branch": name})
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
168
169
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
170
class GitLab(Hoster):
171
    """GitLab hoster implementation."""
172
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
173
    supports_merge_proposal_labels = True
174
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
175
    def __repr__(self):
176
        return "<GitLab(%r)>" % self.gl.url
177
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
178
    @property
179
    def base_url(self):
180
        return self.gl.url
181
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
182
    def __init__(self, gl):
183
        self.gl = gl
184
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
185
    def get_push_url(self, branch):
186
        (host, project_name, branch_name) = parse_gitlab_url(branch)
187
        project = self.gl.projects.get(project_name)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
188
        return gitlab_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
189
            project.ssh_url_to_repo, branch_name)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
190
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
191
    def publish_derived(self, local_branch, base_branch, name, project=None,
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
192
                        owner=None, revision_id=None, overwrite=False,
193
                        allow_lossy=True):
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
194
        import gitlab
0.432.4 by Jelmer Vernooij
Some work on gitlab.
195
        (host, base_project, base_branch_name) = parse_gitlab_url(base_branch)
0.432.10 by Jelmer Vernooij
More test fixes.
196
        self.gl.auth()
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
197
        try:
198
            base_project = self.gl.projects.get(base_project)
199
        except gitlab.GitlabGetError as e:
200
            if e.response_code == 404:
201
                raise NoSuchProject(base_project)
202
            else:
203
                raise
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
204
        if owner is None:
0.432.10 by Jelmer Vernooij
More test fixes.
205
            owner = self.gl.user.username
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
206
        if project is None:
0.431.30 by Jelmer Vernooij
s/name/path.
207
            project = base_project.path
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
208
        try:
0.432.10 by Jelmer Vernooij
More test fixes.
209
            target_project = self.gl.projects.get('%s/%s' % (owner, project))
0.431.30 by Jelmer Vernooij
s/name/path.
210
        except gitlab.GitlabGetError as e:
211
            if e.response_code == 404:
212
                target_project = base_project.forks.create({})
213
            else:
214
                raise
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
215
        remote_repo_url = git_url_to_bzr_url(target_project.ssh_url_to_repo)
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
216
        remote_dir = controldir.ControlDir.open(remote_repo_url)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
217
        try:
7211.13.7 by Jelmer Vernooij
Fix formatting.
218
            push_result = remote_dir.push_branch(
219
                local_branch, revision_id=revision_id, overwrite=overwrite,
220
                name=name)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
221
        except errors.NoRoundtrippingSupport:
222
            if not allow_lossy:
223
                raise
7211.13.7 by Jelmer Vernooij
Fix formatting.
224
            push_result = remote_dir.push_branch(
225
                local_branch, revision_id=revision_id, overwrite=overwrite,
226
                name=name, lossy=True)
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
227
        public_url = gitlab_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
228
            target_project.http_url_to_repo, name)
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
229
        return push_result.target_branch, public_url
0.432.4 by Jelmer Vernooij
Some work on gitlab.
230
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
231
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
232
        import gitlab
233
        (host, base_project, base_branch_name) = parse_gitlab_url(base_branch)
234
        self.gl.auth()
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
235
        try:
236
            base_project = self.gl.projects.get(base_project)
237
        except gitlab.GitlabGetError as e:
238
            if e.response_code == 404:
239
                raise NoSuchProject(base_project)
240
            else:
241
                raise
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
242
        if owner is None:
243
            owner = self.gl.user.username
244
        if project is None:
0.431.30 by Jelmer Vernooij
s/name/path.
245
            project = base_project.path
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
246
        try:
247
            target_project = self.gl.projects.get('%s/%s' % (owner, project))
248
        except gitlab.GitlabGetError as e:
249
            if e.response_code == 404:
250
                raise errors.NotBranchError('%s/%s/%s' % (self.gl.url, owner, project))
251
            raise
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
252
        return _mod_branch.Branch.open(gitlab_url_to_bzr_url(
7233.3.2 by Jelmer Vernooij
Merge lp:brz-propose.
253
            target_project.ssh_url_to_repo, name))
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
254
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
255
    def get_proposer(self, source_branch, target_branch):
256
        return GitlabMergeProposalBuilder(self.gl, source_branch, target_branch)
257
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
258
    def iter_proposals(self, source_branch, target_branch, status):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
259
        import gitlab
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
260
        (source_host, source_project_name, source_branch_name) = (
261
            parse_gitlab_url(source_branch))
262
        (target_host, target_project_name, target_branch_name) = (
263
            parse_gitlab_url(target_branch))
264
        if source_host != target_host:
265
            raise DifferentGitLabInstances(source_host, target_host)
266
        self.gl.auth()
267
        source_project = self.gl.projects.get(source_project_name)
268
        target_project = self.gl.projects.get(target_project_name)
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
269
        state = mp_status_to_status(status)
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
270
        try:
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
271
            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.
272
                if (mr.source_project_id != source_project.id or
7233.3.2 by Jelmer Vernooij
Merge lp:brz-propose.
273
                        mr.source_branch != source_branch_name or
274
                        mr.target_project_id != target_project.id or
275
                        mr.target_branch != target_branch_name):
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
276
                    continue
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
277
                yield GitLabMergeProposal(mr)
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
278
        except gitlab.GitlabListError as e:
279
            if e.response_code == 403:
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
280
                raise errors.PermissionDenied(e.error_message)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
281
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
282
    def hosts(self, branch):
283
        try:
284
            (host, project, branch_name) = parse_gitlab_url(branch)
285
        except NotGitLabUrl:
286
            return False
287
        return (self.gl.url == ('https://%s' % host))
288
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
289
    @classmethod
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
290
    def probe(cls, branch):
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
291
        try:
292
            (host, project, branch_name) = parse_gitlab_url(branch)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
293
        except NotGitLabUrl:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
294
            raise UnsupportedHoster(branch)
0.432.4 by Jelmer Vernooij
Some work on gitlab.
295
        import gitlab
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
296
        import requests.exceptions
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
297
        try:
0.432.4 by Jelmer Vernooij
Some work on gitlab.
298
            gl = connect_gitlab(host)
0.431.10 by Jelmer Vernooij
Various other fixes.
299
            gl.auth()
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
300
        except requests.exceptions.SSLError:
7211.13.7 by Jelmer Vernooij
Fix formatting.
301
            # Well, I guess it could be..
0.431.43 by Jelmer Vernooij
Handle 403s during proposal listing.
302
            raise UnsupportedHoster(branch)
0.432.4 by Jelmer Vernooij
Some work on gitlab.
303
        except gitlab.GitlabGetError:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
304
            raise UnsupportedHoster(branch)
0.431.10 by Jelmer Vernooij
Various other fixes.
305
        except gitlab.GitlabHttpError as e:
0.431.27 by Jelmer Vernooij
Catch 503 errors.
306
            if e.response_code in (404, 405, 503):
0.431.10 by Jelmer Vernooij
Various other fixes.
307
                raise UnsupportedHoster(branch)
308
            else:
309
                raise
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
310
        return cls(gl)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
311
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
312
    @classmethod
313
    def iter_instances(cls):
314
        from gitlab import Gitlab
315
        for name, credentials in iter_tokens():
316
            if 'url' not in credentials:
317
                continue
318
            gl = Gitlab(**credentials)
319
            yield cls(gl)
320
0.431.66 by Jelmer Vernooij
Add support for status argument.
321
    def iter_my_proposals(self, status='open'):
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
322
        state = mp_status_to_status(status)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
323
        self.gl.auth()
0.431.66 by Jelmer Vernooij
Add support for status argument.
324
        for mp in self.gl.mergerequests.list(
325
                owner=self.gl.user.username, state=state):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
326
            yield GitLabMergeProposal(mp)
327
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
328
0.432.2 by Jelmer Vernooij
Publish command sort of works.
329
class GitlabMergeProposalBuilder(MergeProposalBuilder):
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
330
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
331
    def __init__(self, gl, source_branch, target_branch):
332
        self.gl = gl
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
333
        self.source_branch = source_branch
334
        (self.source_host, self.source_project_name, self.source_branch_name) = (
335
            parse_gitlab_url(source_branch))
336
        self.target_branch = target_branch
337
        (self.target_host, self.target_project_name, self.target_branch_name) = (
338
            parse_gitlab_url(target_branch))
339
        if self.source_host != self.target_host:
340
            raise DifferentGitLabInstances(self.source_host, self.target_host)
341
342
    def get_infotext(self):
343
        """Determine the initial comment for the merge proposal."""
344
        info = []
345
        info.append("Gitlab instance: %s\n" % self.target_host)
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
346
        info.append("Source: %s\n" % self.source_branch.user_url)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
347
        info.append("Target: %s\n" % self.target_branch.user_url)
348
        return ''.join(info)
349
350
    def get_initial_body(self):
351
        """Get a body for the proposal for the user to modify.
352
353
        :return: a str or None.
354
        """
355
        return None
356
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
357
    def create_proposal(self, description, reviewers=None, labels=None,
358
                        prerequisite_branch=None):
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
359
        """Perform the submission."""
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
360
        if prerequisite_branch is not None:
361
            raise PrerequisiteBranchUnsupported(self)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
362
        import gitlab
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
363
        # TODO(jelmer): Support reviewers
0.432.10 by Jelmer Vernooij
More test fixes.
364
        self.gl.auth()
365
        source_project = self.gl.projects.get(self.source_project_name)
366
        target_project = self.gl.projects.get(self.target_project_name)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
367
        # TODO(jelmer): Allow setting title explicitly
368
        title = description.splitlines()[0]
369
        # TODO(jelmer): Allow setting allow_collaboration field
370
        # TODO(jelmer): Allow setting milestone field
371
        # TODO(jelmer): Allow setting squash field
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
372
        kwargs = {
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
373
            'title': title,
374
            'target_project_id': target_project.id,
375
            'source_branch': self.source_branch_name,
376
            'target_branch': self.target_branch_name,
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
377
            'description': description}
378
        if labels:
379
            kwargs['labels'] = ','.join(labels)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
380
        try:
381
            merge_request = source_project.mergerequests.create(kwargs)
382
        except gitlab.GitlabCreateError as e:
0.431.34 by Jelmer Vernooij
Cope with gitlab 403.
383
            if e.response_code == 403:
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
384
                raise errors.PermissionDenied(e.error_message)
0.431.16 by Jelmer Vernooij
gitlab: Report when a merge proposal already exists.
385
            if e.response_code == 409:
386
                raise MergeProposalExists(self.source_branch.user_url)
387
            raise
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
388
        return GitLabMergeProposal(merge_request)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
389
390
391
def register_gitlab_instance(shortname, url):
392
    """Register a gitlab instance.
393
394
    :param shortname: Short name (e.g. "gitlab")
395
    :param url: URL to the gitlab instance
396
    """
397
    from breezy.bugtracker import (
398
        tracker_registry,
399
        ProjectIntegerBugTracker,
400
        )
401
    tracker_registry.register(
402
        shortname, ProjectIntegerBugTracker(
403
            shortname, url + '/{project}/issues/{id}'))