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