/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.431.1 by Jelmer Vernooij
Start work on propose command.
1
# Copyright (C) 2018 Jelmer Vernooij <jelmer@jelmer.uk>
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
17
"""Propose command implementations."""
18
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
19
from io import StringIO
20
0.431.1 by Jelmer Vernooij
Start work on propose command.
21
from ... import (
22
    branch as _mod_branch,
23
    controldir,
24
    errors,
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
25
    log as _mod_log,
26
    missing as _mod_missing,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
27
    msgeditor,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
28
    urlutils,
0.431.1 by Jelmer Vernooij
Start work on propose command.
29
    )
30
from ...i18n import gettext
31
from ...commands import Command
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
32
from ...option import (
33
    ListOption,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
34
    Option,
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
35
    RegistryOption,
36
    )
7490.115.1 by Jelmer Vernooij
Raise UnexpectedHttpStatus rather than InvalidHttpResponse.
37
from ...trace import note, warning
7408.3.1 by Jelmer Vernooij
Move propose module into core.
38
from ... import (
0.431.1 by Jelmer Vernooij
Start work on propose command.
39
    propose as _mod_propose,
40
    )
41
42
0.432.2 by Jelmer Vernooij
Publish command sort of works.
43
def branch_name(branch):
44
    if branch.name:
45
        return branch.name
46
    return urlutils.basename(branch.user_url)
47
48
7490.54.2 by Jelmer Vernooij
Also run checks in 'brz publish'.
49
def _check_already_merged(branch, target):
50
    # TODO(jelmer): Check entire ancestry rather than just last revision?
51
    if branch.last_revision() == target.last_revision():
7490.61.1 by Jelmer Vernooij
Rename BzrCommandError to CommandError.
52
        raise errors.CommandError(gettext(
7490.54.2 by Jelmer Vernooij
Also run checks in 'brz publish'.
53
            'All local changes are already present in target.'))
54
55
0.431.18 by Jelmer Vernooij
Rename 'brz publish' to 'brz publish-derived'.
56
class cmd_publish_derived(Command):
57
    __doc__ = """Publish a derived branch.
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
58
0.431.18 by Jelmer Vernooij
Rename 'brz publish' to 'brz publish-derived'.
59
    Try to create a public copy of a local branch on a hosting site,
60
    derived from the specified base branch.
0.432.2 by Jelmer Vernooij
Publish command sort of works.
61
62
    Reasonable defaults are picked for owner name, branch name and project
63
    name, but they can also be overridden from the command-line.
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
64
    """
65
0.432.2 by Jelmer Vernooij
Publish command sort of works.
66
    takes_options = [
7211.13.7 by Jelmer Vernooij
Fix formatting.
67
        'directory',
68
        Option('owner', help='Owner of the new remote branch.', type=str),
69
        Option('project', help='Project name for the new remote branch.',
70
               type=str),
71
        Option('name', help='Name of the new remote branch.', type=str),
72
        Option('no-allow-lossy',
73
               help='Allow fallback to lossy push, if necessary.'),
74
        Option('overwrite', help="Overwrite existing commits."),
75
        ]
0.432.2 by Jelmer Vernooij
Publish command sort of works.
76
    takes_args = ['submit_branch?']
77
78
    def run(self, submit_branch=None, owner=None, name=None, project=None,
0.431.52 by Jelmer Vernooij
Add --overwrite flag to 'brz publish'.
79
            no_allow_lossy=False, overwrite=False, directory='.'):
0.432.2 by Jelmer Vernooij
Publish command sort of works.
80
        local_branch = _mod_branch.Branch.open_containing(directory)[0]
81
        self.add_cleanup(local_branch.lock_write().unlock)
82
        if submit_branch is None:
83
            submit_branch = local_branch.get_submit_branch()
84
            note(gettext('Using submit branch %s') % submit_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
85
        if submit_branch is None:
86
            submit_branch = local_branch.get_parent()
87
            note(gettext('Using parent branch %s') % submit_branch)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
88
        submit_branch = _mod_branch.Branch.open(submit_branch)
7490.54.2 by Jelmer Vernooij
Also run checks in 'brz publish'.
89
        _check_already_merged(local_branch, submit_branch)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
90
        if name is None:
91
            name = branch_name(local_branch)
92
        hoster = _mod_propose.get_hoster(submit_branch)
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
93
        remote_branch, public_url = hoster.publish_derived(
7211.13.7 by Jelmer Vernooij
Fix formatting.
94
            local_branch, submit_branch, name=name, project=project,
95
            owner=owner, allow_lossy=not no_allow_lossy,
96
            overwrite=overwrite)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
97
        local_branch.set_push_location(remote_branch.user_url)
98
        local_branch.set_public_branch(public_url)
7342.1.2 by Jelmer Vernooij
Set the submit branch after 'brz publish' / 'brz propose'
99
        local_branch.set_submit_branch(submit_branch.user_url)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
100
        note(gettext("Pushed to %s") % public_url)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
101
102
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
103
def summarize_unmerged(local_branch, remote_branch, target,
104
                       prerequisite_branch=None):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
105
    """Generate a text description of the unmerged revisions in branch.
106
107
    :param branch: The proposed branch
108
    :param target: Target branch
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
109
    :param prerequisite_branch: Optional prerequisite branch
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
110
    :return: A string
111
    """
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
112
    log_format = _mod_log.log_formatter_registry.get_default(local_branch)
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
113
    to_file = StringIO()
114
    lf = log_format(to_file=to_file, show_ids=False, show_timezone='original')
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
115
    if prerequisite_branch:
116
        local_extra = _mod_missing.find_unmerged(
117
            remote_branch, prerequisite_branch, restrict='local')[0]
118
    else:
119
        local_extra = _mod_missing.find_unmerged(
120
            remote_branch, target, restrict='local')[0]
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
121
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
122
    if remote_branch.supports_tags():
123
        rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
124
    else:
125
        rev_tag_dict = {}
126
127
    for revision in _mod_missing.iter_log_revisions(
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
128
            local_extra, local_branch.repository, False, rev_tag_dict):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
129
        lf.log_revision(revision)
130
    return to_file.getvalue()
131
132
0.431.1 by Jelmer Vernooij
Start work on propose command.
133
class cmd_propose_merge(Command):
134
    __doc__ = """Propose a branch for merging.
135
136
    This command creates a merge proposal for the local
137
    branch to the target branch. The format of the merge
138
    proposal depends on the submit branch.
139
    """
140
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
141
    takes_options = [
7211.13.7 by Jelmer Vernooij
Fix formatting.
142
        'directory',
143
        RegistryOption(
144
            'hoster',
145
            help='Use the hoster.',
7490.138.2 by Jelmer Vernooij
Add Proposal.update.
146
            lazy_registry=('breezy.propose', 'hosters')),
7479.2.1 by Jelmer Vernooij
Drop python2 support.
147
        ListOption('reviewers', short_name='R', type=str,
7211.13.7 by Jelmer Vernooij
Fix formatting.
148
                   help='Requested reviewers.'),
149
        Option('name', help='Name of the new remote branch.', type=str),
150
        Option('description', help='Description of the change.', type=str),
151
        Option('prerequisite', help='Prerequisite branch.', type=str),
7467.3.2 by Jelmer Vernooij
Add --wip flag for 'brz propose'.
152
        Option('wip', help='Mark merge request as work-in-progress'),
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
153
        Option(
154
            'commit-message',
155
            help='Set commit message for merge, if supported', type=str),
7479.2.1 by Jelmer Vernooij
Drop python2 support.
156
        ListOption('labels', short_name='l', type=str,
7211.13.7 by Jelmer Vernooij
Fix formatting.
157
                   help='Labels to apply.'),
158
        Option('no-allow-lossy',
159
               help='Allow fallback to lossy push, if necessary.'),
7490.6.1 by Jelmer Vernooij
Add allow-collaboration flag.
160
        Option('allow-collaboration',
161
               help='Allow collaboration from target branch maintainer(s)'),
7490.54.1 by Jelmer Vernooij
Prevent empty proposals.
162
        Option('allow-empty',
163
               help='Do not prevent empty merge proposals.'),
7490.136.1 by Jelmer Vernooij
Add overwrite argument to 'brz propose'.
164
        Option('overwrite', help="Overwrite existing commits."),
7211.13.7 by Jelmer Vernooij
Fix formatting.
165
        ]
0.431.1 by Jelmer Vernooij
Start work on propose command.
166
    takes_args = ['submit_branch?']
167
168
    aliases = ['propose']
169
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
170
    def run(self, submit_branch=None, directory='.', hoster=None,
171
            reviewers=None, name=None, no_allow_lossy=False, description=None,
7490.6.1 by Jelmer Vernooij
Add allow-collaboration flag.
172
            labels=None, prerequisite=None, commit_message=None, wip=False,
7490.136.1 by Jelmer Vernooij
Add overwrite argument to 'brz propose'.
173
            allow_collaboration=False, allow_empty=False, overwrite=False):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
174
        tree, branch, relpath = (
175
            controldir.ControlDir.open_containing_tree_or_branch(directory))
0.431.1 by Jelmer Vernooij
Start work on propose command.
176
        if submit_branch is None:
177
            submit_branch = branch.get_submit_branch()
178
        if submit_branch is None:
0.432.7 by Jelmer Vernooij
propose works \o/
179
            submit_branch = branch.get_parent()
180
        if submit_branch is None:
7490.61.1 by Jelmer Vernooij
Rename BzrCommandError to CommandError.
181
            raise errors.CommandError(
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
182
                gettext("No target location specified or remembered"))
7490.54.1 by Jelmer Vernooij
Prevent empty proposals.
183
        target = _mod_branch.Branch.open(submit_branch)
7490.54.2 by Jelmer Vernooij
Also run checks in 'brz publish'.
184
        if not allow_empty:
185
            _check_already_merged(branch, target)
0.432.7 by Jelmer Vernooij
propose works \o/
186
        if hoster is None:
187
            hoster = _mod_propose.get_hoster(target)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
188
        else:
0.432.7 by Jelmer Vernooij
propose works \o/
189
            hoster = hoster.probe(target)
190
        if name is None:
191
            name = branch_name(branch)
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
192
        remote_branch, public_branch_url = hoster.publish_derived(
7490.136.1 by Jelmer Vernooij
Add overwrite argument to 'brz propose'.
193
            branch, target, name=name, allow_lossy=not no_allow_lossy,
194
            overwrite=overwrite)
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
195
        branch.set_push_location(remote_branch.user_url)
7342.1.2 by Jelmer Vernooij
Set the submit branch after 'brz publish' / 'brz propose'
196
        branch.set_submit_branch(target.user_url)
0.432.7 by Jelmer Vernooij
propose works \o/
197
        note(gettext('Published branch to %s') % public_branch_url)
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
198
        if prerequisite is not None:
199
            prerequisite_branch = _mod_branch.Branch.open(prerequisite)
200
        else:
201
            prerequisite_branch = None
0.432.7 by Jelmer Vernooij
propose works \o/
202
        proposal_builder = hoster.get_proposer(remote_branch, target)
0.432.10 by Jelmer Vernooij
More test fixes.
203
        if description is None:
204
            body = proposal_builder.get_initial_body()
205
            info = proposal_builder.get_infotext()
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
206
            info += "\n\n" + summarize_unmerged(
207
                branch, remote_branch, target, prerequisite_branch)
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
208
            description = msgeditor.edit_commit_message(
209
                info, start_message=body)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
210
        try:
0.432.7 by Jelmer Vernooij
propose works \o/
211
            proposal = proposal_builder.create_proposal(
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
212
                description=description, reviewers=reviewers,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
213
                prerequisite_branch=prerequisite_branch, labels=labels,
7467.3.2 by Jelmer Vernooij
Add --wip flag for 'brz propose'.
214
                commit_message=commit_message,
7490.6.1 by Jelmer Vernooij
Add allow-collaboration flag.
215
                work_in_progress=wip, allow_collaboration=allow_collaboration)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
216
        except _mod_propose.MergeProposalExists as e:
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
217
            note(gettext('There is already a branch merge proposal: %s'), e.url)
218
        else:
219
            note(gettext('Merge proposal created: %s') % proposal.url)
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
220
221
222
class cmd_find_merge_proposal(Command):
223
    __doc__ = """Find a merge proposal.
224
225
    """
226
227
    takes_options = ['directory']
228
    takes_args = ['submit_branch?']
229
    aliases = ['find-proposal']
230
231
    def run(self, directory='.', submit_branch=None):
232
        tree, branch, relpath = controldir.ControlDir.open_containing_tree_or_branch(
233
            directory)
234
        public_location = branch.get_public_branch()
235
        if public_location:
236
            branch = _mod_branch.Branch.open(public_location)
237
        if submit_branch is None:
238
            submit_branch = branch.get_submit_branch()
239
        if submit_branch is None:
240
            submit_branch = branch.get_parent()
241
        if submit_branch is None:
7490.61.1 by Jelmer Vernooij
Rename BzrCommandError to CommandError.
242
            raise errors.CommandError(
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
243
                gettext("No target location specified or remembered"))
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
244
        else:
245
            target = _mod_branch.Branch.open(submit_branch)
246
        hoster = _mod_propose.get_hoster(branch)
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
247
        for mp in hoster.iter_proposals(branch, target):
248
            self.outf.write(gettext('Merge proposal: %s\n') % mp.url)
0.431.47 by Jelmer Vernooij
Add github login command.
249
250
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
251
class cmd_my_merge_proposals(Command):
0.431.66 by Jelmer Vernooij
Add support for status argument.
252
    __doc__ = """List all merge proposals owned by the logged-in user.
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
253
254
    """
255
0.431.69 by Jelmer Vernooij
Make 'brz my-proposals' hidden for the moment.
256
    hidden = True
257
7490.138.2 by Jelmer Vernooij
Add Proposal.update.
258
    takes_args = ['base-url?']
0.431.66 by Jelmer Vernooij
Add support for status argument.
259
    takes_options = [
7296.10.3 by Jelmer Vernooij
More fixes.
260
        'verbose',
0.431.66 by Jelmer Vernooij
Add support for status argument.
261
        RegistryOption.from_kwargs(
262
            'status',
263
            title='Proposal Status',
264
            help='Only include proposals with specified status.',
265
            value_switches=True,
266
            enum_switch=True,
267
            all='All merge proposals',
268
            open='Open merge proposals',
269
            merged='Merged merge proposals',
7490.138.1 by Jelmer Vernooij
Allow iterating over merge proposals by hoster.
270
            closed='Closed merge proposals'),
7490.138.2 by Jelmer Vernooij
Add Proposal.update.
271
        RegistryOption(
272
            'hoster',
273
            help='Use the hoster.',
274
            lazy_registry=('breezy.propose', 'hosters')),
7490.138.1 by Jelmer Vernooij
Allow iterating over merge proposals by hoster.
275
        ]
0.431.66 by Jelmer Vernooij
Add support for status argument.
276
7490.138.2 by Jelmer Vernooij
Add Proposal.update.
277
    def run(self, status='open', verbose=False, hoster=None, base_url=None):
278
279
        for instance in _mod_propose.iter_hoster_instances(hoster=hoster):
280
            if base_url is not None and instance.base_url != base_url:
7490.138.1 by Jelmer Vernooij
Allow iterating over merge proposals by hoster.
281
                continue
7490.115.1 by Jelmer Vernooij
Raise UnexpectedHttpStatus rather than InvalidHttpResponse.
282
            try:
283
                for mp in instance.iter_my_proposals(status=status):
284
                    self.outf.write('%s\n' % mp.url)
285
                    if verbose:
7490.138.1 by Jelmer Vernooij
Allow iterating over merge proposals by hoster.
286
                        source_branch_url = mp.get_source_branch_url()
287
                        if source_branch_url:
288
                            self.outf.write(
289
                                '(Merging %s into %s)\n' %
290
                                (source_branch_url,
291
                                 mp.get_target_branch_url()))
292
                        else:
293
                            self.outf.write(
294
                                '(Merging into %s)\n' %
295
                                mp.get_target_branch_url())
7490.115.1 by Jelmer Vernooij
Raise UnexpectedHttpStatus rather than InvalidHttpResponse.
296
                        description = mp.get_description()
297
                        if description:
298
                            self.outf.writelines(
299
                                ['\t%s\n' % l
300
                                 for l in description.splitlines()])
301
                        self.outf.write('\n')
302
            except _mod_propose.HosterLoginRequired as e:
303
                warning('Skipping %r, login required.', instance)
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
304
305
306
class cmd_land_merge_proposal(Command):
307
    __doc__ = """Land a merge proposal."""
308
309
    takes_args = ['url']
310
    takes_options = [
311
        Option('message', help='Commit message to use.', type=str)]
312
313
    def run(self, url, message=None):
7408.3.1 by Jelmer Vernooij
Move propose module into core.
314
        proposal = _mod_propose.get_proposal_by_url(url)
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
315
        proposal.merge(commit_message=message)
7490.105.1 by Jelmer Vernooij
Add some hoster metadata fields.
316
317
318
class cmd_hosters(Command):
319
    __doc__ = """List all known hosting sites and user details."""
320
321
    hidden = True
322
323
    def run(self):
324
        for instance in _mod_propose.iter_hoster_instances():
325
            current_user = instance.get_current_user()
7490.114.1 by Jelmer Vernooij
Print hoster instances with credentials.
326
            if current_user is not None:
7490.138.2 by Jelmer Vernooij
Add Proposal.update.
327
                current_user_url = instance.get_user_url(current_user)
328
                if current_user_url is not None:
329
                    self.outf.write(
330
                        gettext('%s (%s) - user: %s (%s)\n') % (
331
                            instance.name, instance.base_url,
332
                            current_user, current_user_url))
333
                else:
334
                    self.outf.write(
335
                        gettext('%s (%s) - user: %s\n') % (
336
                            instance.name, instance.base_url,
337
                            current_user))
7490.114.1 by Jelmer Vernooij
Print hoster instances with credentials.
338
            else:
339
                self.outf.write(
340
                    gettext('%s (%s) - not logged in\n') % (
341
                        instance.name, instance.base_url))