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