/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.434.1 by Jelmer Vernooij
Use absolute_import.
19
from __future__ import absolute_import
20
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
21
from io import StringIO
22
0.431.1 by Jelmer Vernooij
Start work on propose command.
23
from ... import (
24
    branch as _mod_branch,
25
    controldir,
26
    errors,
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
27
    log as _mod_log,
28
    missing as _mod_missing,
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
29
    msgeditor,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
30
    urlutils,
0.431.1 by Jelmer Vernooij
Start work on propose command.
31
    )
32
from ...i18n import gettext
33
from ...commands import Command
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
34
from ...option import (
35
    ListOption,
0.432.2 by Jelmer Vernooij
Publish command sort of works.
36
    Option,
0.431.6 by Jelmer Vernooij
Initial gitlab support works.
37
    RegistryOption,
38
    )
0.432.2 by Jelmer Vernooij
Publish command sort of works.
39
from ...trace import note
7408.3.1 by Jelmer Vernooij
Move propose module into core.
40
from ... import (
0.431.1 by Jelmer Vernooij
Start work on propose command.
41
    propose as _mod_propose,
42
    )
43
44
0.432.2 by Jelmer Vernooij
Publish command sort of works.
45
def branch_name(branch):
46
    if branch.name:
47
        return branch.name
48
    return urlutils.basename(branch.user_url)
49
50
0.431.18 by Jelmer Vernooij
Rename 'brz publish' to 'brz publish-derived'.
51
class cmd_publish_derived(Command):
52
    __doc__ = """Publish a derived branch.
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
53
0.431.18 by Jelmer Vernooij
Rename 'brz publish' to 'brz publish-derived'.
54
    Try to create a public copy of a local branch on a hosting site,
55
    derived from the specified base branch.
0.432.2 by Jelmer Vernooij
Publish command sort of works.
56
57
    Reasonable defaults are picked for owner name, branch name and project
58
    name, but they can also be overridden from the command-line.
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
59
    """
60
0.432.2 by Jelmer Vernooij
Publish command sort of works.
61
    takes_options = [
7211.13.7 by Jelmer Vernooij
Fix formatting.
62
        'directory',
63
        Option('owner', help='Owner of the new remote branch.', type=str),
64
        Option('project', help='Project name for the new remote branch.',
65
               type=str),
66
        Option('name', help='Name of the new remote branch.', type=str),
67
        Option('no-allow-lossy',
68
               help='Allow fallback to lossy push, if necessary.'),
69
        Option('overwrite', help="Overwrite existing commits."),
70
        ]
0.432.2 by Jelmer Vernooij
Publish command sort of works.
71
    takes_args = ['submit_branch?']
72
73
    def run(self, submit_branch=None, owner=None, name=None, project=None,
0.431.52 by Jelmer Vernooij
Add --overwrite flag to 'brz publish'.
74
            no_allow_lossy=False, overwrite=False, directory='.'):
0.432.2 by Jelmer Vernooij
Publish command sort of works.
75
        local_branch = _mod_branch.Branch.open_containing(directory)[0]
76
        self.add_cleanup(local_branch.lock_write().unlock)
77
        if submit_branch is None:
78
            submit_branch = local_branch.get_submit_branch()
79
            note(gettext('Using submit branch %s') % submit_branch)
0.431.22 by Jelmer Vernooij
Add Hoster.get_derived_branch.
80
        if submit_branch is None:
81
            submit_branch = local_branch.get_parent()
82
            note(gettext('Using parent branch %s') % submit_branch)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
83
        submit_branch = _mod_branch.Branch.open(submit_branch)
84
        if name is None:
85
            name = branch_name(local_branch)
86
        hoster = _mod_propose.get_hoster(submit_branch)
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
87
        remote_branch, public_url = hoster.publish_derived(
7211.13.7 by Jelmer Vernooij
Fix formatting.
88
            local_branch, submit_branch, name=name, project=project,
89
            owner=owner, allow_lossy=not no_allow_lossy,
90
            overwrite=overwrite)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
91
        local_branch.set_push_location(remote_branch.user_url)
92
        local_branch.set_public_branch(public_url)
7342.1.2 by Jelmer Vernooij
Set the submit branch after 'brz publish' / 'brz propose'
93
        local_branch.set_submit_branch(submit_branch.user_url)
0.432.2 by Jelmer Vernooij
Publish command sort of works.
94
        note(gettext("Pushed to %s") % public_url)
0.432.1 by Jelmer Vernooij
Initial work on hoster support.
95
96
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
97
def summarize_unmerged(local_branch, remote_branch, target,
98
                       prerequisite_branch=None):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
99
    """Generate a text description of the unmerged revisions in branch.
100
101
    :param branch: The proposed branch
102
    :param target: Target branch
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
103
    :param prerequisite_branch: Optional prerequisite branch
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
104
    :return: A string
105
    """
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
106
    log_format = _mod_log.log_formatter_registry.get_default(local_branch)
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
107
    to_file = StringIO()
108
    lf = log_format(to_file=to_file, show_ids=False, show_timezone='original')
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
109
    if prerequisite_branch:
110
        local_extra = _mod_missing.find_unmerged(
111
            remote_branch, prerequisite_branch, restrict='local')[0]
112
    else:
113
        local_extra = _mod_missing.find_unmerged(
114
            remote_branch, target, restrict='local')[0]
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
115
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
116
    if remote_branch.supports_tags():
117
        rev_tag_dict = remote_branch.tags.get_reverse_tag_dict()
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
118
    else:
119
        rev_tag_dict = {}
120
121
    for revision in _mod_missing.iter_log_revisions(
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
122
            local_extra, local_branch.repository, False, rev_tag_dict):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
123
        lf.log_revision(revision)
124
    return to_file.getvalue()
125
126
0.431.1 by Jelmer Vernooij
Start work on propose command.
127
class cmd_propose_merge(Command):
128
    __doc__ = """Propose a branch for merging.
129
130
    This command creates a merge proposal for the local
131
    branch to the target branch. The format of the merge
132
    proposal depends on the submit branch.
133
    """
134
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
135
    takes_options = [
7211.13.7 by Jelmer Vernooij
Fix formatting.
136
        'directory',
137
        RegistryOption(
138
            'hoster',
139
            help='Use the hoster.',
140
            lazy_registry=('breezy.plugins.propose.propose', 'hosters')),
7479.2.1 by Jelmer Vernooij
Drop python2 support.
141
        ListOption('reviewers', short_name='R', type=str,
7211.13.7 by Jelmer Vernooij
Fix formatting.
142
                   help='Requested reviewers.'),
143
        Option('name', help='Name of the new remote branch.', type=str),
144
        Option('description', help='Description of the change.', type=str),
145
        Option('prerequisite', help='Prerequisite branch.', type=str),
7467.3.2 by Jelmer Vernooij
Add --wip flag for 'brz propose'.
146
        Option('wip', help='Mark merge request as work-in-progress'),
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
147
        Option(
148
            'commit-message',
149
            help='Set commit message for merge, if supported', type=str),
7479.2.1 by Jelmer Vernooij
Drop python2 support.
150
        ListOption('labels', short_name='l', type=str,
7211.13.7 by Jelmer Vernooij
Fix formatting.
151
                   help='Labels to apply.'),
152
        Option('no-allow-lossy',
153
               help='Allow fallback to lossy push, if necessary.'),
154
        ]
0.431.1 by Jelmer Vernooij
Start work on propose command.
155
    takes_args = ['submit_branch?']
156
157
    aliases = ['propose']
158
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
159
    def run(self, submit_branch=None, directory='.', hoster=None,
160
            reviewers=None, name=None, no_allow_lossy=False, description=None,
7467.3.2 by Jelmer Vernooij
Add --wip flag for 'brz propose'.
161
            labels=None, prerequisite=None, commit_message=None, wip=False):
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
162
        tree, branch, relpath = (
163
            controldir.ControlDir.open_containing_tree_or_branch(directory))
0.431.1 by Jelmer Vernooij
Start work on propose command.
164
        if submit_branch is None:
165
            submit_branch = branch.get_submit_branch()
166
        if submit_branch is None:
0.432.7 by Jelmer Vernooij
propose works \o/
167
            submit_branch = branch.get_parent()
168
        if submit_branch is None:
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
169
            raise errors.BzrCommandError(
170
                gettext("No target location specified or remembered"))
0.431.1 by Jelmer Vernooij
Start work on propose command.
171
        else:
172
            target = _mod_branch.Branch.open(submit_branch)
0.432.7 by Jelmer Vernooij
propose works \o/
173
        if hoster is None:
174
            hoster = _mod_propose.get_hoster(target)
0.431.5 by Jelmer Vernooij
Initial work on gitlab support.
175
        else:
0.432.7 by Jelmer Vernooij
propose works \o/
176
            hoster = hoster.probe(target)
177
        if name is None:
178
            name = branch_name(branch)
0.431.20 by Jelmer Vernooij
publish -> publish_derived.
179
        remote_branch, public_branch_url = hoster.publish_derived(
7211.13.7 by Jelmer Vernooij
Fix formatting.
180
            branch, target, name=name, allow_lossy=not no_allow_lossy)
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
181
        branch.set_push_location(remote_branch.user_url)
7342.1.2 by Jelmer Vernooij
Set the submit branch after 'brz publish' / 'brz propose'
182
        branch.set_submit_branch(target.user_url)
0.432.7 by Jelmer Vernooij
propose works \o/
183
        note(gettext('Published branch to %s') % public_branch_url)
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
184
        if prerequisite is not None:
185
            prerequisite_branch = _mod_branch.Branch.open(prerequisite)
186
        else:
187
            prerequisite_branch = None
0.432.7 by Jelmer Vernooij
propose works \o/
188
        proposal_builder = hoster.get_proposer(remote_branch, target)
0.432.10 by Jelmer Vernooij
More test fixes.
189
        if description is None:
190
            body = proposal_builder.get_initial_body()
191
            info = proposal_builder.get_infotext()
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
192
            info += "\n\n" + summarize_unmerged(
193
                branch, remote_branch, target, prerequisite_branch)
0.431.54 by Jelmer Vernooij
Include commit data in 'brz propose'.
194
            description = msgeditor.edit_commit_message(
195
                info, start_message=body)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
196
        try:
0.432.7 by Jelmer Vernooij
propose works \o/
197
            proposal = proposal_builder.create_proposal(
0.431.56 by Jelmer Vernooij
Add support for prerequisite branches.
198
                description=description, reviewers=reviewers,
7296.8.1 by Jelmer Vernooij
Add commit-message option to 'brz propose'.
199
                prerequisite_branch=prerequisite_branch, labels=labels,
7467.3.2 by Jelmer Vernooij
Add --wip flag for 'brz propose'.
200
                commit_message=commit_message,
201
                work_in_progress=wip)
0.431.2 by Jelmer Vernooij
Add launchpad implementation.
202
        except _mod_propose.MergeProposalExists as e:
7359.1.3 by Jelmer Vernooij
Fix GitHub API interaction.
203
            note(gettext('There is already a branch merge proposal: %s'), e.url)
204
        else:
205
            note(gettext('Merge proposal created: %s') % proposal.url)
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
206
207
208
class cmd_find_merge_proposal(Command):
209
    __doc__ = """Find a merge proposal.
210
211
    """
212
213
    takes_options = ['directory']
214
    takes_args = ['submit_branch?']
215
    aliases = ['find-proposal']
216
217
    def run(self, directory='.', submit_branch=None):
218
        tree, branch, relpath = controldir.ControlDir.open_containing_tree_or_branch(
219
            directory)
220
        public_location = branch.get_public_branch()
221
        if public_location:
222
            branch = _mod_branch.Branch.open(public_location)
223
        if submit_branch is None:
224
            submit_branch = branch.get_submit_branch()
225
        if submit_branch is None:
226
            submit_branch = branch.get_parent()
227
        if submit_branch is None:
0.431.55 by Jelmer Vernooij
Cope with lossy pushes better in `brz propose` texts.
228
            raise errors.BzrCommandError(
229
                gettext("No target location specified or remembered"))
0.431.37 by Jelmer Vernooij
add a find-merge-proposal command.
230
        else:
231
            target = _mod_branch.Branch.open(submit_branch)
232
        hoster = _mod_propose.get_hoster(branch)
0.431.67 by Jelmer Vernooij
Support multiple merge proposals per branch.
233
        for mp in hoster.iter_proposals(branch, target):
234
            self.outf.write(gettext('Merge proposal: %s\n') % mp.url)
0.431.47 by Jelmer Vernooij
Add github login command.
235
236
237
class cmd_github_login(Command):
238
    __doc__ = """Log into GitHub.
239
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
240
    When communicating with GitHub, some commands need to authenticate to
241
    GitHub.
0.431.47 by Jelmer Vernooij
Add github login command.
242
    """
243
244
    takes_args = ['username?']
245
246
    def run(self, username=None):
247
        from github import Github, GithubException
248
        from breezy.config import AuthenticationConfig
249
        authconfig = AuthenticationConfig()
250
        if username is None:
251
            username = authconfig.get_user(
7211.13.7 by Jelmer Vernooij
Fix formatting.
252
                'https', 'github.com', prompt=u'GitHub username', ask=True)
0.431.47 by Jelmer Vernooij
Add github login command.
253
        password = authconfig.get_password('https', 'github.com', username)
254
        client = Github(username, password)
255
        user = client.get_user()
256
        try:
257
            authorization = user.create_authorization(
7211.13.7 by Jelmer Vernooij
Fix formatting.
258
                scopes=['user', 'repo', 'delete_repo'], note='Breezy',
259
                note_url='https://github.com/breezy-team/breezy')
0.431.47 by Jelmer Vernooij
Add github login command.
260
        except GithubException as e:
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
261
            errs = e.data.get('errors', [])
262
            if errs:
263
                err_code = errs[0].get('code')
264
                if err_code == u'already_exists':
265
                    raise errors.BzrCommandError('token already exists')
0.431.47 by Jelmer Vernooij
Add github login command.
266
            raise errors.BzrCommandError(e.data['message'])
0.431.49 by Jelmer Vernooij
Store GitHub tokens in a magic file, for now.
267
        # TODO(jelmer): This should really use something in
268
        # AuthenticationConfig
269
        from .github import store_github_token
270
        store_github_token(scheme='https', host='github.com',
271
                           token=authorization.token)
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
272
273
274
class cmd_gitlab_login(Command):
275
    __doc__ = """Log into a GitLab instance.
276
277
    This command takes a GitLab instance URL (e.g. https://gitlab.com)
7241.1.2 by Jelmer Vernooij
Update help.
278
    as well as an optional private token. Private tokens can be created via the
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
279
    web UI.
280
281
    :Examples:
282
7241.1.2 by Jelmer Vernooij
Update help.
283
      Log into GNOME's GitLab (prompts for a token):
284
285
         brz gitlab-login https://gitlab.gnome.org/
286
287
      Log into Debian's salsa, using a token created earlier:
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
288
289
         brz gitlab-login https://salsa.debian.org if4Theis6Eich7aef0zo
290
    """
291
7241.1.1 by Jelmer Vernooij
Support interactive login for GitLab sites.
292
    takes_args = ['url', 'private_token?']
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
293
294
    takes_options = [
7211.13.7 by Jelmer Vernooij
Fix formatting.
295
        Option('name', help='Name for GitLab site in configuration.',
296
               type=str),
297
        Option('no-check',
298
               "Don't check that the token is valid."),
299
        ]
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
300
7241.1.1 by Jelmer Vernooij
Support interactive login for GitLab sites.
301
    def run(self, url, private_token=None, name=None, no_check=False):
302
        from breezy import ui
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
303
        from .gitlabs import store_gitlab_token
304
        if name is None:
305
            try:
306
                name = urlutils.parse_url(url)[3].split('.')[-2]
307
            except (ValueError, IndexError):
308
                raise errors.BzrCommandError(
309
                    'please specify a site name with --name')
7241.1.1 by Jelmer Vernooij
Support interactive login for GitLab sites.
310
        if private_token is None:
311
            note("Please visit %s to obtain a private token.",
312
                 urlutils.join(url, "profile/personal_access_tokens"))
313
            private_token = ui.ui_factory.get_password(u'Private token')
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
314
        if not no_check:
7296.10.1 by Jelmer Vernooij
Initial work making gitlab just directly use ReST.
315
            from breezy.transport import get_transport
316
            from .gitlabs import GitLab
317
            GitLab(get_transport(url), private_token=private_token)
0.431.59 by Jelmer Vernooij
Add gitlab-login command.
318
        store_gitlab_token(name=name, url=url, private_token=private_token)
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
319
320
321
class cmd_my_merge_proposals(Command):
0.431.66 by Jelmer Vernooij
Add support for status argument.
322
    __doc__ = """List all merge proposals owned by the logged-in user.
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
323
324
    """
325
0.431.69 by Jelmer Vernooij
Make 'brz my-proposals' hidden for the moment.
326
    hidden = True
327
0.431.66 by Jelmer Vernooij
Add support for status argument.
328
    takes_options = [
7296.10.3 by Jelmer Vernooij
More fixes.
329
        'verbose',
0.431.66 by Jelmer Vernooij
Add support for status argument.
330
        RegistryOption.from_kwargs(
331
            'status',
332
            title='Proposal Status',
333
            help='Only include proposals with specified status.',
334
            value_switches=True,
335
            enum_switch=True,
336
            all='All merge proposals',
337
            open='Open merge proposals',
338
            merged='Merged merge proposals',
339
            closed='Closed merge proposals')]
340
7296.10.3 by Jelmer Vernooij
More fixes.
341
    def run(self, status='open', verbose=False):
7408.3.1 by Jelmer Vernooij
Move propose module into core.
342
        for name, hoster_cls in _mod_propose.hosters.items():
0.431.63 by Jelmer Vernooij
Add 'brz my-proposals' command.
343
            for instance in hoster_cls.iter_instances():
0.431.66 by Jelmer Vernooij
Add support for status argument.
344
                for mp in instance.iter_my_proposals(status=status):
0.431.65 by Jelmer Vernooij
Avoid print.
345
                    self.outf.write('%s\n' % mp.url)
7296.10.3 by Jelmer Vernooij
More fixes.
346
                    if verbose:
347
                        self.outf.write(
348
                            '(Merging %s into %s)\n' %
349
                            (mp.get_source_branch_url(),
350
                             mp.get_target_branch_url()))
7360.1.2 by Jelmer Vernooij
Cope with description being None.
351
                        description = mp.get_description()
352
                        if description:
353
                            self.outf.writelines(
354
                                ['\t%s\n' % l
355
                                 for l in description.splitlines()])
7296.10.3 by Jelmer Vernooij
More fixes.
356
                        self.outf.write('\n')
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
357
358
359
class cmd_land_merge_proposal(Command):
360
    __doc__ = """Land a merge proposal."""
361
362
    takes_args = ['url']
363
    takes_options = [
364
        Option('message', help='Commit message to use.', type=str)]
365
366
    def run(self, url, message=None):
7408.3.1 by Jelmer Vernooij
Move propose module into core.
367
        proposal = _mod_propose.get_proposal_by_url(url)
7296.9.1 by Jelmer Vernooij
Add 'brz land' subcommand.
368
        proposal.merge(commit_message=message)