/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.4 by Jelmer Vernooij
Some work on gitlab.
27
from ...config import AuthenticationConfig
0.432.5 by Jelmer Vernooij
Fix publishing to gitlab.
28
from ...git.urls import git_url_to_bzr_url
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
29
from ...sixish import PY3
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
30
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
31
from .propose import (
0.432.2 by Jelmer Vernooij
Publish command sort of works.
32
    Hoster,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
33
    MergeProposal,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
34
    MergeProposalBuilder,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
35
    MergeProposalExists,
0.431.38 by Jelmer Vernooij
Add NoSuchProject.
36
    NoSuchProject,
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
37
    PrerequisiteBranchUnsupported,
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
38
    UnsupportedHoster,
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
39
    )
40
0.431.68 by Jelmer Vernooij
Add status to other Hosters.
41
def mp_status_to_status(status):
42
    return {
43
        'all': 'all',
44
        'open': 'opened',
45
        'merged': 'merged',
46
        'closed': 'closed'}[status]
47
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
48
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
49
class NotGitLabUrl(errors.BzrError):
50
51
    _fmt = "Not a GitLab URL: %(url)s"
52
53
    def __init__(self, url):
54
        errors.BzrError.__init__(self)
55
        self.url = url
56
57
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
58
class DifferentGitLabInstances(errors.BzrError):
59
60
    _fmt = ("Can't create merge proposals across GitLab instances: "
61
            "%(source_host)s and %(target_host)s")
62
63
    def __init__(self, source_host, target_host):
64
        self.source_host = source_host
65
        self.target_host = target_host
66
67
0.432.10 by Jelmer Vernooij
More test fixes.
68
class GitLabLoginMissing(errors.BzrError):
69
70
    _fmt = ("Please log into GitLab")
71
72
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
73
def default_config_path():
74
    from breezy.config import config_dir
75
    import os
76
    return os.path.join(config_dir(), 'gitlab.conf')
77
78
79
def store_gitlab_token(name, url, private_token):
80
    """Store a GitLab token in a configuration file."""
81
    import configparser
82
    config = configparser.ConfigParser()
83
    path = default_config_path()
84
    config.read([path])
85
    config.add_section(name)
86
    config[name]['url'] = url
87
    config[name]['private_token'] = private_token
88
    with open(path, 'w') as f:
89
        config.write(f)
90
91
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
92
def iter_tokens():
93
    import configparser
94
    from gitlab.config import _DEFAULT_FILES
95
    config = configparser.ConfigParser()
96
    config.read(_DEFAULT_FILES + [default_config_path()])
97
    for name, section in config.items():
98
        yield name, section
99
100
0.432.10 by Jelmer Vernooij
More test fixes.
101
def connect_gitlab(host):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
102
    from gitlab import Gitlab, GitlabGetError
0.432.4 by Jelmer Vernooij
Some work on gitlab.
103
    auth = AuthenticationConfig()
104
0.432.10 by Jelmer Vernooij
More test fixes.
105
    url = 'https://%s' % host
106
    credentials = auth.get_credentials('https', host)
0.432.4 by Jelmer Vernooij
Some work on gitlab.
107
    if credentials is None:
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
108
        for name, section in iter_tokens():
0.432.10 by Jelmer Vernooij
More test fixes.
109
            if section.get('url') == url:
110
                credentials = section
111
                break
112
        else:
0.431.10 by Jelmer Vernooij
Various other fixes.
113
            try:
114
                return Gitlab(url)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
115
            except GitlabGetError:
0.431.10 by Jelmer Vernooij
Various other fixes.
116
                raise GitLabLoginMissing()
0.432.10 by Jelmer Vernooij
More test fixes.
117
    else:
118
        credentials['url'] = url
119
    return Gitlab(**credentials)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
120
121
122
def parse_gitlab_url(branch):
123
    url = urlutils.split_segment_parameters(branch.user_url)[0]
124
    (scheme, user, password, host, port, path) = urlutils.parse_url(
125
        url)
0.431.17 by Jelmer Vernooij
Try harder to avoid detecting any URL as a GitLab URL.
126
    if scheme not in ('git+ssh', 'https', 'http'):
127
        raise NotGitLabUrl(branch.user_url)
128
    if not host:
129
        raise NotGitLabUrl(branch.user_url)
0.432.10 by Jelmer Vernooij
More test fixes.
130
    path = path.strip('/')
0.432.11 by Jelmer Vernooij
Fix some tests.
131
    if path.endswith('.git'):
132
        path = path[:-4]
0.432.10 by Jelmer Vernooij
More test fixes.
133
    return host, path, branch.name
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
134
135
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
136
class GitLabMergeProposal(MergeProposal):
137
138
    def __init__(self, mr):
139
        self._mr = mr
140
141
    @property
142
    def url(self):
143
        return self._mr.web_url
144
145
    def get_description(self):
146
        return self._mr.description
147
148
    def set_description(self, description):
149
        self._mr.description = description
150
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
151
    def _branch_url_from_project(self, project_id, branch_name):
152
        project = self._mr.manager.gitlab.projects.get(project_id)
153
        return gitlab_url_to_bzr_url(project.http_url_to_repo, branch_name)
154
155
    def get_source_branch_url(self):
156
        return self._branch_url_from_project(
157
            self._mr.source_project_id, self._mr.source_branch)
158
159
    def get_target_branch_url(self):
160
        return self._branch_url_from_project(
161
            self._mr.target_project_id, self._mr.target_branch)
162
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
163
    def is_merged(self):
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
164
        return (self._mr.state == 'merged')
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
165
0.431.39 by Jelmer Vernooij
Extend the merge proposal abstraction a bit.
166
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
167
def gitlab_url_to_bzr_url(url, name):
168
    if not PY3:
169
        name = name.encode('utf-8')
170
    return urlutils.join_segment_parameters(
7211.13.7 by Jelmer Vernooij
Fix formatting.
171
        git_url_to_bzr_url(url), {"branch": name})
0.433.3 by Jelmer Vernooij
Some python 3 compatibility.
172
173
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
174
class GitLab(Hoster):
175
    """GitLab hoster implementation."""
176
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
177
    supports_merge_proposal_labels = True
178
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
179
    def __repr__(self):
180
        return "<GitLab(%r)>" % 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}'))