/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/plugins/propose/cmds.py

  • Committer: Jelmer Vernooij
  • Date: 2020-03-22 20:02:36 UTC
  • mto: (7490.7.7 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200322200236-fsbl91ktcn6fcbdd
Fix tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Propose command implementations."""
18
18
 
 
19
from __future__ import absolute_import
 
20
 
19
21
from io import StringIO
20
22
 
21
23
from ... import (
34
36
    Option,
35
37
    RegistryOption,
36
38
    )
 
39
from ...sixish import text_type
37
40
from ...trace import note
38
41
from ... import (
39
42
    propose as _mod_propose,
46
49
    return urlutils.basename(branch.user_url)
47
50
 
48
51
 
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():
52
 
        raise errors.CommandError(gettext(
53
 
            'All local changes are already present in target.'))
54
 
 
55
 
 
56
52
class cmd_publish_derived(Command):
57
53
    __doc__ = """Publish a derived branch.
58
54
 
86
82
            submit_branch = local_branch.get_parent()
87
83
            note(gettext('Using parent branch %s') % submit_branch)
88
84
        submit_branch = _mod_branch.Branch.open(submit_branch)
89
 
        _check_already_merged(local_branch, submit_branch)
90
85
        if name is None:
91
86
            name = branch_name(local_branch)
92
87
        hoster = _mod_propose.get_hoster(submit_branch)
144
139
            'hoster',
145
140
            help='Use the hoster.',
146
141
            lazy_registry=('breezy.plugins.propose.propose', 'hosters')),
147
 
        ListOption('reviewers', short_name='R', type=str,
 
142
        ListOption('reviewers', short_name='R', type=text_type,
148
143
                   help='Requested reviewers.'),
149
144
        Option('name', help='Name of the new remote branch.', type=str),
150
145
        Option('description', help='Description of the change.', type=str),
153
148
        Option(
154
149
            'commit-message',
155
150
            help='Set commit message for merge, if supported', type=str),
156
 
        ListOption('labels', short_name='l', type=str,
 
151
        ListOption('labels', short_name='l', type=text_type,
157
152
                   help='Labels to apply.'),
158
153
        Option('no-allow-lossy',
159
154
               help='Allow fallback to lossy push, if necessary.'),
160
155
        Option('allow-collaboration',
161
156
               help='Allow collaboration from target branch maintainer(s)'),
162
 
        Option('allow-empty',
163
 
               help='Do not prevent empty merge proposals.'),
164
157
        ]
165
158
    takes_args = ['submit_branch?']
166
159
 
169
162
    def run(self, submit_branch=None, directory='.', hoster=None,
170
163
            reviewers=None, name=None, no_allow_lossy=False, description=None,
171
164
            labels=None, prerequisite=None, commit_message=None, wip=False,
172
 
            allow_collaboration=False, allow_empty=False):
 
165
            allow_collaboration=False):
173
166
        tree, branch, relpath = (
174
167
            controldir.ControlDir.open_containing_tree_or_branch(directory))
175
168
        if submit_branch is None:
177
170
        if submit_branch is None:
178
171
            submit_branch = branch.get_parent()
179
172
        if submit_branch is None:
180
 
            raise errors.CommandError(
 
173
            raise errors.BzrCommandError(
181
174
                gettext("No target location specified or remembered"))
182
 
        target = _mod_branch.Branch.open(submit_branch)
183
 
        if not allow_empty:
184
 
            _check_already_merged(branch, target)
 
175
        else:
 
176
            target = _mod_branch.Branch.open(submit_branch)
185
177
        if hoster is None:
186
178
            hoster = _mod_propose.get_hoster(target)
187
179
        else:
237
229
        if submit_branch is None:
238
230
            submit_branch = branch.get_parent()
239
231
        if submit_branch is None:
240
 
            raise errors.CommandError(
 
232
            raise errors.BzrCommandError(
241
233
                gettext("No target location specified or remembered"))
242
234
        else:
243
235
            target = _mod_branch.Branch.open(submit_branch)
246
238
            self.outf.write(gettext('Merge proposal: %s\n') % mp.url)
247
239
 
248
240
 
 
241
class cmd_github_login(Command):
 
242
    __doc__ = """Log into GitHub.
 
243
 
 
244
    When communicating with GitHub, some commands need to authenticate to
 
245
    GitHub.
 
246
    """
 
247
 
 
248
    takes_args = ['username?']
 
249
 
 
250
    def run(self, username=None):
 
251
        from github import Github, GithubException
 
252
        from breezy.config import AuthenticationConfig
 
253
        authconfig = AuthenticationConfig()
 
254
        if username is None:
 
255
            username = authconfig.get_user(
 
256
                'https', 'github.com', prompt=u'GitHub username', ask=True)
 
257
        password = authconfig.get_password('https', 'github.com', username)
 
258
        client = Github(username, password)
 
259
        user = client.get_user()
 
260
        try:
 
261
            authorization = user.create_authorization(
 
262
                scopes=['user', 'repo', 'delete_repo'], note='Breezy',
 
263
                note_url='https://github.com/breezy-team/breezy')
 
264
        except GithubException as e:
 
265
            errs = e.data.get('errors', [])
 
266
            if errs:
 
267
                err_code = errs[0].get('code')
 
268
                if err_code == u'already_exists':
 
269
                    raise errors.BzrCommandError('token already exists')
 
270
            raise errors.BzrCommandError(e.data['message'])
 
271
        # TODO(jelmer): This should really use something in
 
272
        # AuthenticationConfig
 
273
        from .github import store_github_token
 
274
        store_github_token(scheme='https', host='github.com',
 
275
                           token=authorization.token)
 
276
 
 
277
 
 
278
class cmd_gitlab_login(Command):
 
279
    __doc__ = """Log into a GitLab instance.
 
280
 
 
281
    This command takes a GitLab instance URL (e.g. https://gitlab.com)
 
282
    as well as an optional private token. Private tokens can be created via the
 
283
    web UI.
 
284
 
 
285
    :Examples:
 
286
 
 
287
      Log into GNOME's GitLab (prompts for a token):
 
288
 
 
289
         brz gitlab-login https://gitlab.gnome.org/
 
290
 
 
291
      Log into Debian's salsa, using a token created earlier:
 
292
 
 
293
         brz gitlab-login https://salsa.debian.org if4Theis6Eich7aef0zo
 
294
    """
 
295
 
 
296
    takes_args = ['url', 'private_token?']
 
297
 
 
298
    takes_options = [
 
299
        Option('name', help='Name for GitLab site in configuration.',
 
300
               type=str),
 
301
        Option('no-check',
 
302
               "Don't check that the token is valid."),
 
303
        ]
 
304
 
 
305
    def run(self, url, private_token=None, name=None, no_check=False):
 
306
        from breezy import ui
 
307
        from .gitlabs import store_gitlab_token
 
308
        if name is None:
 
309
            try:
 
310
                name = urlutils.parse_url(url)[3].split('.')[-2]
 
311
            except (ValueError, IndexError):
 
312
                raise errors.BzrCommandError(
 
313
                    'please specify a site name with --name')
 
314
        if private_token is None:
 
315
            note("Please visit %s to obtain a private token.",
 
316
                 urlutils.join(url, "profile/personal_access_tokens"))
 
317
            private_token = ui.ui_factory.get_password(u'Private token')
 
318
        if not no_check:
 
319
            from breezy.transport import get_transport
 
320
            from .gitlabs import GitLab
 
321
            GitLab(get_transport(url), private_token=private_token)
 
322
        store_gitlab_token(name=name, url=url, private_token=private_token)
 
323
 
 
324
 
249
325
class cmd_my_merge_proposals(Command):
250
326
    __doc__ = """List all merge proposals owned by the logged-in user.
251
327
 
267
343
            closed='Closed merge proposals')]
268
344
 
269
345
    def run(self, status='open', verbose=False):
270
 
        for instance in _mod_propose.iter_hoster_instances():
271
 
            for mp in instance.iter_my_proposals(status=status):
272
 
                self.outf.write('%s\n' % mp.url)
273
 
                if verbose:
274
 
                    self.outf.write(
275
 
                        '(Merging %s into %s)\n' %
276
 
                        (mp.get_source_branch_url(),
277
 
                         mp.get_target_branch_url()))
278
 
                    description = mp.get_description()
279
 
                    if description:
280
 
                        self.outf.writelines(
281
 
                            ['\t%s\n' % l
282
 
                             for l in description.splitlines()])
283
 
                    self.outf.write('\n')
 
346
        for name, hoster_cls in _mod_propose.hosters.items():
 
347
            for instance in hoster_cls.iter_instances():
 
348
                for mp in instance.iter_my_proposals(status=status):
 
349
                    self.outf.write('%s\n' % mp.url)
 
350
                    if verbose:
 
351
                        self.outf.write(
 
352
                            '(Merging %s into %s)\n' %
 
353
                            (mp.get_source_branch_url(),
 
354
                             mp.get_target_branch_url()))
 
355
                        description = mp.get_description()
 
356
                        if description:
 
357
                            self.outf.writelines(
 
358
                                ['\t%s\n' % l
 
359
                                 for l in description.splitlines()])
 
360
                        self.outf.write('\n')
284
361
 
285
362
 
286
363
class cmd_land_merge_proposal(Command):
293
370
    def run(self, url, message=None):
294
371
        proposal = _mod_propose.get_proposal_by_url(url)
295
372
        proposal.merge(commit_message=message)
296
 
 
297
 
 
298
 
class cmd_hosters(Command):
299
 
    __doc__ = """List all known hosting sites and user details."""
300
 
 
301
 
    hidden = True
302
 
 
303
 
    def run(self):
304
 
        for instance in _mod_propose.iter_hoster_instances():
305
 
            current_user = instance.get_current_user()
306
 
            self.outf.write(
307
 
                gettext('%s (%s) - user: %s (%s)\n') % (
308
 
                    instance.name, instance.base_url,
309
 
                    current_user, instance.get_user_url(current_user)))