/brz/remove-bazaar

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