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