/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
1
# Copyright (C) 2010, 2011 Canonical Ltd
0.431.27 by Jelmer Vernooij
Catch 503 errors.
2
# Copyright (C) 2018 Breezy Developers
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
0.434.1 by Jelmer Vernooij
Use absolute_import.
18
"""Support for Launchpad."""
19
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
20
import re
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
21
import shutil
22
import tempfile
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
23
7408.3.1 by Jelmer Vernooij
Move propose module into core.
24
from ...propose import (
0.432.2 by Jelmer Vernooij
Publish command sort of works.
25
    Hoster,
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
26
    LabelsUnsupported,
0.431.3 by Jelmer Vernooij
Add a MergeProposal object.
27
    MergeProposal,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
28
    MergeProposalBuilder,
0.431.3 by Jelmer Vernooij
Add a MergeProposal object.
29
    MergeProposalExists,
0.431.12 by Jelmer Vernooij
Fix Launchpad probing.
30
    UnsupportedHoster,
0.431.3 by Jelmer Vernooij
Add a MergeProposal object.
31
    )
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
32
33
from ... import (
0.432.2 by Jelmer Vernooij
Publish command sort of works.
34
    branch as _mod_branch,
35
    controldir,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
36
    errors,
37
    hooks,
38
    urlutils,
39
    )
7408.2.1 by Jelmer Vernooij
Use standard functions for creating Git URLs.
40
from ...git.urls import git_url_to_bzr_url
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
41
from ...lazy_import import lazy_import
42
lazy_import(globals(), """
43
from breezy.plugins.launchpad import (
44
    lp_api,
7464.2.1 by Jelmer Vernooij
Fix finding merge proposals by URL.
45
    uris as lp_uris,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
46
    )
7253 by Jelmer Vernooij
Fix default launchpadlib API URL.
47
48
from launchpadlib import uris
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
49
""")
0.432.2 by Jelmer Vernooij
Publish command sort of works.
50
from ...transport import get_transport
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
51
52
0.431.4 by Jelmer Vernooij
Add basic GitHub support.
53
# TODO(jelmer): Make selection of launchpad staging a configuration option.
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
54
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
55
def status_to_lp_mp_statuses(status):
56
    statuses = []
57
    if status in ('open', 'all'):
58
        statuses.extend([
59
            'Work in progress',
60
            'Needs review',
61
            'Approved',
62
            'Code failed to merge',
63
            'Queued'])
64
    if status in ('closed', 'all'):
65
        statuses.extend(['Rejected', 'Superseded'])
66
    if status in ('merged', 'all'):
67
        statuses.append('Merged')
68
    return statuses
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
69
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
70
71
def plausible_launchpad_url(url):
72
    if url is None:
73
        return False
74
    if url.startswith('lp:'):
75
        return True
7322.2.1 by Martin
Fix invalid escape sequence warnings in regexps
76
    regex = re.compile(r'([a-z]*\+)*(bzr\+ssh|http|ssh|git|https)'
77
                       r'://(bazaar|git).*\.launchpad\.net')
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
78
    return bool(regex.match(url))
79
80
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
81
class WebserviceFailure(Exception):
82
83
    def __init__(self, message):
84
        self.message = message
85
86
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
87
def _call_webservice(call, *args, **kwargs):
88
    """Make a call to the webservice, wrapping failures.
89
90
    :param call: The call to make.
91
    :param *args: *args for the call.
92
    :param **kwargs: **kwargs for the call.
93
    :return: The result of calling call(*args, *kwargs).
94
    """
95
    from lazr.restfulclient import errors as restful_errors
96
    try:
97
        return call(*args, **kwargs)
98
    except restful_errors.HTTPError as e:
99
        error_lines = []
100
        for line in e.content.splitlines():
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
101
            if line.startswith(b'Traceback (most recent call last):'):
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
102
                break
103
            error_lines.append(line)
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
104
        raise WebserviceFailure(b''.join(error_lines))
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
105
106
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
107
class LaunchpadMergeProposal(MergeProposal):
108
109
    def __init__(self, mp):
110
        self._mp = mp
111
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
112
    def get_source_branch_url(self):
113
        if self._mp.source_branch:
114
            return self._mp.source_branch.bzr_identity
115
        else:
7408.2.1 by Jelmer Vernooij
Use standard functions for creating Git URLs.
116
            return git_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
117
                self._mp.source_git_repository.git_identity,
7408.2.1 by Jelmer Vernooij
Use standard functions for creating Git URLs.
118
                ref=self._mp.source_git_path.encode('utf-8'))
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
119
7490.65.1 by Jelmer Vernooij
Add functions fo retrieving merge proposal source revision.
120
    def get_source_revision(self):
121
        if self._mp.source_branch:
122
            last_scanned_id = self._mp.source_branch.last_scanned_id
123
            if last_scanned_id:
124
                return last_scanned_id.encode('utf-8')
125
            else:
126
                return None
127
        else:
128
            from breezy.git.mapping import default_mapping
129
            git_repo = self._mp.source_git_repository
7490.65.2 by Jelmer Vernooij
Fix bugs, add release note.
130
            git_ref = git_repo.getRefByPath(path=self._mp.source_git_path)
131
            sha = git_ref.commit_sha1
7490.65.1 by Jelmer Vernooij
Add functions fo retrieving merge proposal source revision.
132
            if sha is None:
133
                return None
134
            return default_mapping.revision_id_foreign_to_bzr(
135
                sha.encode('ascii'))
136
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
137
    def get_target_branch_url(self):
138
        if self._mp.target_branch:
139
            return self._mp.target_branch.bzr_identity
140
        else:
7408.2.1 by Jelmer Vernooij
Use standard functions for creating Git URLs.
141
            return git_url_to_bzr_url(
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
142
                self._mp.target_git_repository.git_identity,
7408.2.1 by Jelmer Vernooij
Use standard functions for creating Git URLs.
143
                ref=self._mp.target_git_path.encode('utf-8'))
0.431.64 by Jelmer Vernooij
Add get_source_branch_url/get_target_branch_url methods.
144
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
145
    @property
146
    def url(self):
147
        return lp_api.canonical_url(self._mp)
148
149
    def is_merged(self):
150
        return (self._mp.queue_status == 'Merged')
151
7381.5.1 by Jelmer Vernooij
Several more fixes for merge proposals. Add functions for reopening merge proposals.
152
    def is_closed(self):
153
        return (self._mp.queue_status in ('Rejected', 'Superseded'))
154
155
    def reopen(self):
156
        self._mp.setStatus(status='Needs review')
157
0.431.70 by Jelmer Vernooij
Implement get_description/set_description for LaunchpadMergeProposal.
158
    def get_description(self):
159
        return self._mp.description
160
161
    def set_description(self, description):
162
        self._mp.description = description
7290.5.1 by Jelmer Vernooij
Actually send API call to Launchpad when updating description.
163
        self._mp.lp_save()
0.431.70 by Jelmer Vernooij
Implement get_description/set_description for LaunchpadMergeProposal.
164
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
165
    def get_commit_message(self):
166
        return self._mp.commit_message
167
168
    def set_commit_message(self, commit_message):
169
        self._mp.commit_message = commit_message
170
        self._mp.lp_save()
171
7260.2.1 by Jelmer Vernooij
Implement .close on merge proposals.
172
    def close(self):
173
        self._mp.setStatus(status='Rejected')
174
7381.2.1 by Jelmer Vernooij
Implement LaunchpadMergeProposal.can_be_merged.
175
    def can_be_merged(self):
176
        if not self._mp.preview_diff:
177
            # Maybe?
178
            return True
179
        return not bool(self._mp.preview_diff.conflicts)
180
7414.4.1 by Jelmer Vernooij
Add a MergeProposal.get_merged_by method.
181
    def get_merged_by(self):
182
        merge_reporter = self._mp.merge_reporter
183
        if merge_reporter is None:
184
            return None
185
        return merge_reporter.name
186
7414.4.3 by Jelmer Vernooij
Add MergeProposal.get_merged_at.
187
    def get_merged_at(self):
188
        return self._mp.date_merged
189
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
190
    def merge(self, commit_message=None):
191
        target_branch = _mod_branch.Branch.open(
192
            self.get_target_branch_url())
193
        source_branch = _mod_branch.Branch.open(
194
            self.get_source_branch_url())
195
        # TODO(jelmer): Ideally this would use a memorytree, but merge doesn't
196
        # support that yet.
197
        # tree = target_branch.create_memorytree()
198
        tmpdir = tempfile.mkdtemp()
199
        try:
200
            tree = target_branch.create_checkout(
201
                to_location=tmpdir, lightweight=True)
202
            tree.merge_from_branch(source_branch)
203
            tree.commit(commit_message or self._mp.commit_message)
204
        finally:
205
            shutil.rmtree(tmpdir)
206
7490.52.1 by Jelmer Vernooij
Add MergeProposal.post_comment.
207
    def post_comment(self, body):
208
        self._mp.createComment(content=body)
209
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
210
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
211
class Launchpad(Hoster):
212
    """The Launchpad hosting service."""
213
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
214
    name = 'launchpad'
215
0.431.29 by Jelmer Vernooij
Fix github branch name, add bug URL.
216
    # https://bugs.launchpad.net/launchpad/+bug/397676
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
217
    supports_merge_proposal_labels = False
218
7296.8.2 by Jelmer Vernooij
Add feature flag for commit message.
219
    supports_merge_proposal_commit_message = True
220
7490.3.9 by Jelmer Vernooij
Add supports_allow_collaboration flag.
221
    supports_allow_collaboration = False
222
7445.1.1 by Jelmer Vernooij
Add Hoster.merge_proposal_description_format and common function for determining title.
223
    merge_proposal_description_format = 'plain'
224
7254.1.2 by Jelmer Vernooij
Fix propose Launchpad.
225
    def __init__(self, staging=False):
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
226
        self._staging = staging
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
227
        if staging:
7253 by Jelmer Vernooij
Fix default launchpadlib API URL.
228
            lp_base_url = uris.STAGING_SERVICE_ROOT
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
229
        else:
7253 by Jelmer Vernooij
Fix default launchpadlib API URL.
230
            lp_base_url = uris.LPNET_SERVICE_ROOT
7371.4.4 by Jelmer Vernooij
Pull in more fixes from janitor.
231
        self.launchpad = lp_api.connect_launchpad(lp_base_url, version='devel')
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
232
7260.1.1 by Jelmer Vernooij
Add .base_url property to Hoster.
233
    @property
234
    def base_url(self):
235
        return lp_api.uris.web_root_for_service_root(
236
            str(self.launchpad._root_uri))
237
0.433.1 by Jelmer Vernooij
Add Hoster.hosts.
238
    def __repr__(self):
239
        return "Launchpad(staging=%s)" % self._staging
240
241
    def hosts(self, branch):
242
        # TODO(jelmer): staging vs non-staging?
243
        return plausible_launchpad_url(branch.user_url)
244
0.432.2 by Jelmer Vernooij
Publish command sort of works.
245
    @classmethod
7296.10.1 by Jelmer Vernooij
Initial work making gitlab just directly use ReST.
246
    def probe_from_url(cls, url, possible_transports=None):
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
247
        if plausible_launchpad_url(url):
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
248
            return Launchpad()
7268.12.1 by Jelmer Vernooij
Split out probe_from_url.
249
        raise UnsupportedHoster(url)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
250
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
251
    def _get_lp_git_ref_from_branch(self, branch):
252
        url, params = urlutils.split_segment_parameters(branch.user_url)
253
        (scheme, user, password, host, port, path) = urlutils.parse_url(
254
            url)
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
255
        repo_lp = self.launchpad.git_repositories.getByPath(
256
            path=path.strip('/'))
0.431.26 by Jelmer Vernooij
Fix handling of proposals for Launchapd Git URLs.
257
        try:
258
            ref_path = params['ref']
259
        except KeyError:
260
            branch_name = params.get('branch', branch.name)
261
            if branch_name:
262
                ref_path = 'refs/heads/%s' % branch_name
263
            else:
264
                ref_path = repo_lp.default_branch
265
        ref_lp = repo_lp.getRefByPath(path=ref_path)
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
266
        return (repo_lp, ref_lp)
267
268
    def _get_lp_bzr_branch_from_branch(self, branch):
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
269
        return self.launchpad.branches.getByUrl(
270
            url=urlutils.unescape(branch.user_url))
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
271
0.431.23 by Jelmer Vernooij
Launchpad fixes.
272
    def _get_derived_git_path(self, base_path, owner, project):
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
273
        base_repo = self.launchpad.git_repositories.getByPath(path=base_path)
274
        if project is None:
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
275
            project = urlutils.parse_url(base_repo.git_ssh_url)[-1].strip('/')
276
        if project.startswith('~'):
277
            project = '/'.join(base_path.split('/')[1:])
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
278
        # TODO(jelmer): Surely there is a better way of creating one of these
279
        # URLs?
0.431.23 by Jelmer Vernooij
Launchpad fixes.
280
        return "~%s/%s" % (owner, project)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
281
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
282
    def _publish_git(self, local_branch, base_path, name, owner, project=None,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
283
                     revision_id=None, overwrite=False, allow_lossy=True,
284
                     tag_selector=None):
0.431.23 by Jelmer Vernooij
Launchpad fixes.
285
        to_path = self._get_derived_git_path(base_path, owner, project)
286
        to_transport = get_transport("git+ssh://git.launchpad.net/" + to_path)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
287
        try:
288
            dir_to = controldir.ControlDir.open_from_transport(to_transport)
289
        except errors.NotBranchError:
290
            # Didn't find anything
291
            dir_to = None
292
293
        if dir_to is None:
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
294
            try:
295
                br_to = local_branch.create_clone_on_transport(
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
296
                    to_transport, revision_id=revision_id, name=name,
297
                    tag_selector=tag_selector)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
298
            except errors.NoRoundtrippingSupport:
299
                br_to = local_branch.create_clone_on_transport(
7211.13.7 by Jelmer Vernooij
Fix formatting.
300
                    to_transport, revision_id=revision_id, name=name,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
301
                    lossy=True, tag_selector=tag_selector)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
302
        else:
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
303
            try:
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
304
                dir_to = dir_to.push_branch(
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
305
                    local_branch, revision_id, overwrite=overwrite, name=name,
306
                    tag_selector=tag_selector)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
307
            except errors.NoRoundtrippingSupport:
308
                if not allow_lossy:
309
                    raise
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
310
                dir_to = dir_to.push_branch(
311
                    local_branch, revision_id, overwrite=overwrite, name=name,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
312
                    lossy=True, tag_selector=tag_selector)
0.431.51 by Jelmer Vernooij
Allow fallback to lossy by default.
313
            br_to = dir_to.target_branch
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
314
        return br_to, (
315
            "https://git.launchpad.net/%s/+ref/%s" % (to_path, name))
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
316
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
317
    def _get_derived_bzr_path(self, base_branch, name, owner, project):
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
318
        if project is None:
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
319
            base_branch_lp = self._get_lp_bzr_branch_from_branch(base_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
320
            project = '/'.join(base_branch_lp.unique_name.split('/')[1:-1])
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
321
        # TODO(jelmer): Surely there is a better way of creating one of these
322
        # URLs?
0.431.23 by Jelmer Vernooij
Launchpad fixes.
323
        return "~%s/%s/%s" % (owner, project, name)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
324
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
325
    def get_push_url(self, branch):
326
        (vcs, user, password, path, params) = self._split_url(branch.user_url)
327
        if vcs == 'bzr':
328
            branch_lp = self._get_lp_bzr_branch_from_branch(branch)
329
            return branch_lp.bzr_identity
330
        elif vcs == 'git':
331
            return urlutils.join_segment_parameters(
332
                "git+ssh://git.launchpad.net/" + path, params)
333
        else:
334
            raise AssertionError
335
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
336
    def _publish_bzr(self, local_branch, base_branch, name, owner,
337
                     project=None, revision_id=None, overwrite=False,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
338
                     allow_lossy=True, tag_selector=None):
0.431.25 by Jelmer Vernooij
Fix launchpad URL unescaping.
339
        to_path = self._get_derived_bzr_path(base_branch, name, owner, project)
0.431.23 by Jelmer Vernooij
Launchpad fixes.
340
        to_transport = get_transport("lp:" + to_path)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
341
        try:
342
            dir_to = controldir.ControlDir.open_from_transport(to_transport)
343
        except errors.NotBranchError:
344
            # Didn't find anything
345
            dir_to = None
346
347
        if dir_to is None:
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
348
            br_to = local_branch.create_clone_on_transport(
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
349
                to_transport, revision_id=revision_id, tag_selector=tag_selector)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
350
        else:
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
351
            br_to = dir_to.push_branch(
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
352
                local_branch, revision_id, overwrite=overwrite,
353
                tag_selector=tag_selector).target_branch
0.431.23 by Jelmer Vernooij
Launchpad fixes.
354
        return br_to, ("https://code.launchpad.net/" + to_path)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
355
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
356
    def _split_url(self, url):
357
        url, params = urlutils.split_segment_parameters(url)
358
        (scheme, user, password, host, port, path) = urlutils.parse_url(url)
359
        path = path.strip('/')
360
        if host.startswith('bazaar.'):
361
            vcs = 'bzr'
362
        elif host.startswith('git.'):
363
            vcs = 'git'
364
        else:
365
            raise ValueError("unknown host %s" % host)
366
        return (vcs, user, password, path, params)
367
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
368
    def publish_derived(self, local_branch, base_branch, name, project=None,
369
                        owner=None, revision_id=None, overwrite=False,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
370
                        allow_lossy=True, tag_selector=None):
0.432.2 by Jelmer Vernooij
Publish command sort of works.
371
        """Publish a branch to the site, derived from base_branch.
372
373
        :param base_branch: branch to derive the new branch from
374
        :param new_branch: branch to publish
375
        :param name: Name of the new branch on the remote host
376
        :param project: Optional project name
377
        :param owner: Optional owner
378
        :return: resulting branch
379
        """
380
        if owner is None:
0.432.9 by Jelmer Vernooij
Drop is_compatible nonesense.
381
            owner = self.launchpad.me.name
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
382
        (base_vcs, base_user, base_password, base_path,
383
            base_params) = self._split_url(base_branch.user_url)
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
384
        # TODO(jelmer): Prevent publishing to development focus
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
385
        if base_vcs == 'bzr':
7211.13.7 by Jelmer Vernooij
Fix formatting.
386
            return self._publish_bzr(
387
                local_branch, base_branch, name, project=project, owner=owner,
388
                revision_id=revision_id, overwrite=overwrite,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
389
                allow_lossy=allow_lossy, tag_selector=tag_selector)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
390
        elif base_vcs == 'git':
7211.13.7 by Jelmer Vernooij
Fix formatting.
391
            return self._publish_git(
392
                local_branch, base_path, name, project=project, owner=owner,
393
                revision_id=revision_id, overwrite=overwrite,
7489.4.2 by Jelmer Vernooij
Plumb through tag_selector.
394
                allow_lossy=allow_lossy, tag_selector=tag_selector)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
395
        else:
0.431.15 by Jelmer Vernooij
Initial work on support for git branches in launchpad.
396
            raise AssertionError('not a valid Launchpad URL')
0.432.2 by Jelmer Vernooij
Publish command sort of works.
397
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
398
    def get_derived_branch(self, base_branch, name, project=None, owner=None):
399
        if owner is None:
400
            owner = self.launchpad.me.name
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
401
        (base_vcs, base_user, base_password, base_path,
402
            base_params) = self._split_url(base_branch.user_url)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
403
        if base_vcs == 'bzr':
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
404
            to_path = self._get_derived_bzr_path(
405
                base_branch, name, owner, project)
0.431.23 by Jelmer Vernooij
Launchpad fixes.
406
            return _mod_branch.Branch.open("lp:" + to_path)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
407
        elif base_vcs == 'git':
7211.13.7 by Jelmer Vernooij
Fix formatting.
408
            to_path = self._get_derived_git_path(
409
                base_path.strip('/'), owner, project)
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
410
            to_url = urlutils.join_segment_parameters(
7240.4.1 by Jelmer Vernooij
Merge lp:brz-propose.
411
                "git+ssh://git.launchpad.net/" + to_path,
412
                {'branch': name})
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
413
            return _mod_branch.Branch.open(to_url)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
414
        else:
415
            raise AssertionError('not a valid Launchpad URL')
416
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
417
    def iter_proposals(self, source_branch, target_branch, status='open'):
418
        (base_vcs, base_user, base_password, base_path,
419
            base_params) = self._split_url(target_branch.user_url)
420
        statuses = status_to_lp_mp_statuses(status)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
421
        if base_vcs == 'bzr':
7211.13.7 by Jelmer Vernooij
Fix formatting.
422
            target_branch_lp = self.launchpad.branches.getByUrl(
423
                url=target_branch.user_url)
424
            source_branch_lp = self.launchpad.branches.getByUrl(
425
                url=source_branch.user_url)
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
426
            for mp in target_branch_lp.getMergeProposals(status=statuses):
427
                if mp.source_branch_link != source_branch_lp.self_link:
428
                    continue
429
                yield LaunchpadMergeProposal(mp)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
430
        elif base_vcs == 'git':
7211.13.7 by Jelmer Vernooij
Fix formatting.
431
            (source_repo_lp, source_branch_lp) = (
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
432
                self._get_lp_git_ref_from_branch(source_branch))
7211.13.7 by Jelmer Vernooij
Fix formatting.
433
            (target_repo_lp, target_branch_lp) = (
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
434
                self._get_lp_git_ref_from_branch(target_branch))
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
435
            for mp in target_branch_lp.getMergeProposals(status=statuses):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
436
                if (target_branch_lp.path != mp.target_git_path or
7211.13.7 by Jelmer Vernooij
Fix formatting.
437
                        target_repo_lp != mp.target_git_repository or
438
                        source_branch_lp.path != mp.source_git_path or
439
                        source_repo_lp != mp.source_git_repository):
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
440
                    continue
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
441
                yield LaunchpadMergeProposal(mp)
0.431.35 by Jelmer Vernooij
Add Hoster.get_proposal.
442
        else:
443
            raise AssertionError('not a valid Launchpad URL')
444
0.432.2 by Jelmer Vernooij
Publish command sort of works.
445
    def get_proposer(self, source_branch, target_branch):
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
446
        (base_vcs, base_user, base_password, base_path,
447
            base_params) = self._split_url(target_branch.user_url)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
448
        if base_vcs == 'bzr':
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
449
            return LaunchpadBazaarMergeProposalBuilder(
7211.13.7 by Jelmer Vernooij
Fix formatting.
450
                self, source_branch, target_branch)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
451
        elif base_vcs == 'git':
0.431.24 by Jelmer Vernooij
Support git merge proposals.
452
            return LaunchpadGitMergeProposalBuilder(
7211.13.7 by Jelmer Vernooij
Fix formatting.
453
                self, source_branch, target_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
454
        else:
455
            raise AssertionError('not a valid Launchpad URL')
0.432.2 by Jelmer Vernooij
Publish command sort of works.
456
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
457
    @classmethod
458
    def iter_instances(cls):
459
        yield cls()
460
0.431.66 by Jelmer Vernooij
Add support for status argument.
461
    def iter_my_proposals(self, status='open'):
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
462
        statuses = status_to_lp_mp_statuses(status)
0.431.66 by Jelmer Vernooij
Add support for status argument.
463
        for mp in self.launchpad.me.getMergeProposals(status=statuses):
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
464
            yield LaunchpadMergeProposal(mp)
465
7414.5.2 by Jelmer Vernooij
Change iter_my_projects to iter_my_forks.
466
    def iter_my_forks(self):
467
        # Launchpad doesn't really have the concept of "forks"
7414.5.1 by Jelmer Vernooij
Add functions for managing projects.
468
        return iter([])
469
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
470
    def get_proposal_by_url(self, url):
471
        # Launchpad doesn't have a way to find a merge proposal by URL.
472
        (scheme, user, password, host, port, path) = urlutils.parse_url(
473
            url)
7296.9.2 by Jelmer Vernooij
Fix detection of launchpad hosts.
474
        LAUNCHPAD_CODE_DOMAINS = [
7464.2.1 by Jelmer Vernooij
Fix finding merge proposals by URL.
475
            ('code.%s' % domain) for domain in lp_uris.LAUNCHPAD_DOMAINS.values()]
7296.9.2 by Jelmer Vernooij
Fix detection of launchpad hosts.
476
        if host not in LAUNCHPAD_CODE_DOMAINS:
477
            raise UnsupportedHoster(url)
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
478
        # TODO(jelmer): Check if this is a launchpad URL. Otherwise, raise
479
        # UnsupportedHoster
480
        # See https://api.launchpad.net/devel/#branch_merge_proposal
481
        # the syntax is:
482
        # https://api.launchpad.net/devel/~<author.name>/<project.name>/<branch.name>/+merge/<id>
483
        api_url = str(self.launchpad._root_uri) + path
484
        mp = self.launchpad.load(api_url)
485
        return LaunchpadMergeProposal(mp)
486
0.432.2 by Jelmer Vernooij
Publish command sort of works.
487
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
488
class LaunchpadBazaarMergeProposalBuilder(MergeProposalBuilder):
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
489
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
490
    def __init__(self, lp_host, source_branch, target_branch,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
491
                 staging=None, approve=None, fixes=None):
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
492
        """Constructor.
493
494
        :param source_branch: The branch to propose for merging.
495
        :param target_branch: The branch to merge into.
496
        :param staging: If True, propose the merge against staging instead of
497
            production.
498
        :param approve: If True, mark the new proposal as approved immediately.
499
            This is useful when a project permits some things to be approved
500
            by the submitter (e.g. merges between release and deployment
501
            branches).
502
        """
0.431.26 by Jelmer Vernooij
Fix handling of proposals for Launchapd Git URLs.
503
        self.lp_host = lp_host
504
        self.launchpad = lp_host.launchpad
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
505
        self.source_branch = source_branch
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
506
        self.source_branch_lp = self.launchpad.branches.getByUrl(
507
            url=source_branch.user_url)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
508
        if target_branch is None:
0.431.24 by Jelmer Vernooij
Support git merge proposals.
509
            self.target_branch_lp = self.source_branch_lp.get_target()
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
510
            self.target_branch = _mod_branch.Branch.open(
511
                self.target_branch_lp.bzr_identity)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
512
        else:
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
513
            self.target_branch = target_branch
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
514
            self.target_branch_lp = self.launchpad.branches.getByUrl(
515
                url=target_branch.user_url)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
516
        self.approve = approve
517
        self.fixes = fixes
518
519
    def get_infotext(self):
520
        """Determine the initial comment for the merge proposal."""
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
521
        info = ["Source: %s\n" % self.source_branch_lp.bzr_identity]
522
        info.append("Target: %s\n" % self.target_branch_lp.bzr_identity)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
523
        return ''.join(info)
524
525
    def get_initial_body(self):
526
        """Get a body for the proposal for the user to modify.
527
528
        :return: a str or None.
529
        """
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
530
        if not self.hooks['merge_proposal_body']:
531
            return None
532
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
533
        def list_modified_files():
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
534
            lca_tree = self.source_branch_lp.find_lca_tree(
535
                self.target_branch_lp)
536
            source_tree = self.source_branch.basis_tree()
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
537
            files = modified_files(lca_tree, source_tree)
538
            return list(files)
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
539
        with self.target_branch.lock_read(), \
540
                self.source_branch.lock_read():
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
541
            body = None
542
            for hook in self.hooks['merge_proposal_body']:
543
                body = hook({
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
544
                    'target_branch': self.target_branch_lp.bzr_identity,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
545
                    'modified_files_callback': list_modified_files,
546
                    'old_body': body,
547
                })
548
            return body
549
550
    def check_proposal(self):
551
        """Check that the submission is sensible."""
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
552
        if self.source_branch_lp.self_link == self.target_branch_lp.self_link:
7490.61.1 by Jelmer Vernooij
Rename BzrCommandError to CommandError.
553
            raise errors.CommandError(
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
554
                'Source and target branches must be different.')
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
555
        for mp in self.source_branch_lp.landing_targets:
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
556
            if mp.queue_status in ('Merged', 'Rejected'):
557
                continue
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
558
            if mp.target_branch.self_link == self.target_branch_lp.self_link:
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
559
                raise MergeProposalExists(lp_api.canonical_url(mp))
560
561
    def approve_proposal(self, mp):
0.431.11 by Jelmer Vernooij
Fix launchpad handling.
562
        with self.source_branch.lock_read():
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
563
            _call_webservice(
564
                mp.createComment,
565
                vote=u'Approve',
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
566
                subject='',  # Use the default subject.
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
567
                content=u"Rubberstamp! Proposer approves of own proposal.")
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
568
            _call_webservice(mp.setStatus, status=u'Approved',
569
                             revid=self.source_branch.last_revision())
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
570
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
571
    def create_proposal(self, description, reviewers=None, labels=None,
7467.3.1 by Jelmer Vernooij
Add a work_in_progress flag.
572
                        prerequisite_branch=None, commit_message=None,
7490.6.1 by Jelmer Vernooij
Add allow-collaboration flag.
573
                        work_in_progress=False, allow_collaboration=False):
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
574
        """Perform the submission."""
0.431.13 by Jelmer Vernooij
Add support for labels on merge proposals.
575
        if labels:
7295.2.1 by Jelmer Vernooij
Fix some issues reported by lgtm.com.
576
            raise LabelsUnsupported(self)
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
577
        if prerequisite_branch is not None:
578
            prereq = self.launchpad.branches.getByUrl(
579
                url=prerequisite_branch.user_url)
580
        else:
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
581
            prereq = None
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
582
        if reviewers is None:
7381.5.1 by Jelmer Vernooij
Several more fixes for merge proposals. Add functions for reopening merge proposals.
583
            reviewer_objs = []
584
        else:
585
            reviewer_objs = []
586
            for reviewer in reviewers:
587
                if '@' in reviewer:
588
                    reviewer_obj = self.launchpad.people.getByEmail(email=reviewer)
589
                else:
590
                    reviewer_obj = self.launchpad.people[reviewer]
591
                reviewer_objs.append(reviewer_obj)
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
592
        try:
593
            mp = _call_webservice(
594
                self.source_branch_lp.createMergeProposal,
595
                target_branch=self.target_branch_lp,
596
                prerequisite_branch=prereq,
0.431.42 by Jelmer Vernooij
Remove unnecessary encode (breaks on Python 3).
597
                initial_comment=description.strip(),
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
598
                commit_message=commit_message,
7467.3.1 by Jelmer Vernooij
Add a work_in_progress flag.
599
                needs_review=(not work_in_progress),
7381.5.5 by Jelmer Vernooij
Review feedback.
600
                reviewers=[reviewer.self_link for reviewer in reviewer_objs],
601
                review_types=['' for reviewer in reviewer_objs])
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
602
        except WebserviceFailure as e:
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
603
            # Urgh.
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
604
            if (b'There is already a branch merge proposal '
7211.13.7 by Jelmer Vernooij
Fix formatting.
605
                    b'registered for branch ') in e.message:
0.431.28 by Jelmer Vernooij
Implement Hoster.get_push_url.
606
                raise MergeProposalExists(self.source_branch.user_url)
607
            raise
608
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
609
        if self.approve:
610
            self.approve_proposal(mp)
611
        if self.fixes:
612
            if self.fixes.startswith('lp:'):
613
                self.fixes = self.fixes[3:]
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
614
            _call_webservice(
615
                mp.linkBug,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
616
                bug=self.launchpad.bugs[int(self.fixes)])
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
617
        return LaunchpadMergeProposal(mp)
0.431.24 by Jelmer Vernooij
Support git merge proposals.
618
619
620
class LaunchpadGitMergeProposalBuilder(MergeProposalBuilder):
621
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
622
    def __init__(self, lp_host, source_branch, target_branch,
0.431.24 by Jelmer Vernooij
Support git merge proposals.
623
                 staging=None, approve=None, fixes=None):
624
        """Constructor.
625
626
        :param source_branch: The branch to propose for merging.
627
        :param target_branch: The branch to merge into.
628
        :param staging: If True, propose the merge against staging instead of
629
            production.
630
        :param approve: If True, mark the new proposal as approved immediately.
631
            This is useful when a project permits some things to be approved
632
            by the submitter (e.g. merges between release and deployment
633
            branches).
634
        """
0.431.26 by Jelmer Vernooij
Fix handling of proposals for Launchapd Git URLs.
635
        self.lp_host = lp_host
636
        self.launchpad = lp_host.launchpad
0.431.24 by Jelmer Vernooij
Support git merge proposals.
637
        self.source_branch = source_branch
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
638
        (self.source_repo_lp,
639
            self.source_branch_lp) = self.lp_host._get_lp_git_ref_from_branch(
640
                source_branch)
0.431.24 by Jelmer Vernooij
Support git merge proposals.
641
        if target_branch is None:
642
            self.target_branch_lp = self.source_branch.get_target()
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
643
            self.target_branch = _mod_branch.Branch.open(
644
                self.target_branch_lp.git_https_url)
0.431.24 by Jelmer Vernooij
Support git merge proposals.
645
        else:
646
            self.target_branch = target_branch
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
647
            (self.target_repo_lp, self.target_branch_lp) = (
648
                self.lp_host._get_lp_git_ref_from_branch(target_branch))
0.431.24 by Jelmer Vernooij
Support git merge proposals.
649
        self.approve = approve
650
        self.fixes = fixes
651
652
    def get_infotext(self):
653
        """Determine the initial comment for the merge proposal."""
654
        info = ["Source: %s\n" % self.source_branch.user_url]
655
        info.append("Target: %s\n" % self.target_branch.user_url)
656
        return ''.join(info)
657
658
    def get_initial_body(self):
659
        """Get a body for the proposal for the user to modify.
660
661
        :return: a str or None.
662
        """
663
        if not self.hooks['merge_proposal_body']:
664
            return None
665
666
        def list_modified_files():
667
            lca_tree = self.source_branch_lp.find_lca_tree(
668
                self.target_branch_lp)
669
            source_tree = self.source_branch.basis_tree()
670
            files = modified_files(lca_tree, source_tree)
671
            return list(files)
672
        with self.target_branch.lock_read(), \
673
                self.source_branch.lock_read():
674
            body = None
675
            for hook in self.hooks['merge_proposal_body']:
676
                body = hook({
677
                    'target_branch': self.target_branch,
678
                    'modified_files_callback': list_modified_files,
679
                    'old_body': body,
680
                })
681
            return body
682
683
    def check_proposal(self):
684
        """Check that the submission is sensible."""
685
        if self.source_branch_lp.self_link == self.target_branch_lp.self_link:
7490.61.1 by Jelmer Vernooij
Rename BzrCommandError to CommandError.
686
            raise errors.CommandError(
0.431.24 by Jelmer Vernooij
Support git merge proposals.
687
                'Source and target branches must be different.')
688
        for mp in self.source_branch_lp.landing_targets:
689
            if mp.queue_status in ('Merged', 'Rejected'):
690
                continue
691
            if mp.target_branch.self_link == self.target_branch_lp.self_link:
692
                raise MergeProposalExists(lp_api.canonical_url(mp))
693
694
    def approve_proposal(self, mp):
695
        with self.source_branch.lock_read():
696
            _call_webservice(
697
                mp.createComment,
698
                vote=u'Approve',
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
699
                subject='',  # Use the default subject.
0.431.24 by Jelmer Vernooij
Support git merge proposals.
700
                content=u"Rubberstamp! Proposer approves of own proposal.")
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
701
            _call_webservice(
702
                mp.setStatus, status=u'Approved',
703
                revid=self.source_branch.last_revision())
0.431.24 by Jelmer Vernooij
Support git merge proposals.
704
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
705
    def create_proposal(self, description, reviewers=None, labels=None,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
706
                        prerequisite_branch=None, commit_message=None):
0.431.24 by Jelmer Vernooij
Support git merge proposals.
707
        """Perform the submission."""
708
        if labels:
7295.2.1 by Jelmer Vernooij
Fix some issues reported by lgtm.com.
709
            raise LabelsUnsupported(self)
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
710
        if prerequisite_branch is not None:
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
711
            (prereq_repo_lp, prereq_branch_lp) = (
712
                self.lp_host._get_lp_git_ref_from_branch(prerequisite_branch))
0.431.24 by Jelmer Vernooij
Support git merge proposals.
713
        else:
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
714
            prereq_branch_lp = None
0.431.24 by Jelmer Vernooij
Support git merge proposals.
715
        if reviewers is None:
716
            reviewers = []
717
        try:
718
            mp = _call_webservice(
719
                self.source_branch_lp.createMergeProposal,
720
                merge_target=self.target_branch_lp,
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
721
                merge_prerequisite=prereq_branch_lp,
0.431.71 by Jelmer Vernooij
Some fixes for Git on Launchpad.
722
                initial_comment=description.strip(),
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
723
                commit_message=commit_message,
0.431.24 by Jelmer Vernooij
Support git merge proposals.
724
                needs_review=True,
725
                reviewers=[self.launchpad.people[reviewer].self_link
726
                           for reviewer in reviewers],
727
                review_types=[None for reviewer in reviewers])
0.431.58 by Jelmer Vernooij
Fix python3 compatibility.
728
        except WebserviceFailure as e:
0.431.24 by Jelmer Vernooij
Support git merge proposals.
729
            # Urgh.
730
            if ('There is already a branch merge proposal '
7211.13.7 by Jelmer Vernooij
Fix formatting.
731
                    'registered for branch ') in e.message:
0.431.24 by Jelmer Vernooij
Support git merge proposals.
732
                raise MergeProposalExists(self.source_branch.user_url)
733
            raise
734
        if self.approve:
735
            self.approve_proposal(mp)
736
        if self.fixes:
737
            if self.fixes.startswith('lp:'):
738
                self.fixes = self.fixes[3:]
739
            _call_webservice(
740
                mp.linkBug,
741
                bug=self.launchpad.bugs[int(self.fixes)])
0.431.46 by Jelmer Vernooij
Add MergeProposal.is_merged.
742
        return LaunchpadMergeProposal(mp)
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
743
744
745
def modified_files(old_tree, new_tree):
746
    """Return a list of paths in the new tree with modified contents."""
7322.1.6 by Jelmer Vernooij
Use the new attributes on TreeChange.
747
    for change in new_tree.iter_changes(old_tree):
748
        if change.changed_content and change.kind[1] == 'file':
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
749
            yield str(path)