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