/brz/remove-bazaar

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