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),
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.'),
165
158
takes_args = ['submit_branch?']
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)
184
_check_already_merged(branch, target)
176
target = _mod_branch.Branch.open(submit_branch)
185
177
if hoster is None:
186
178
hoster = _mod_propose.get_hoster(target)
246
238
self.outf.write(gettext('Merge proposal: %s\n') % mp.url)
241
class cmd_github_login(Command):
242
__doc__ = """Log into GitHub.
244
When communicating with GitHub, some commands need to authenticate to
248
takes_args = ['username?']
250
def run(self, username=None):
251
from github import Github, GithubException
252
from breezy.config import AuthenticationConfig
253
authconfig = AuthenticationConfig()
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()
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', [])
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)
278
class cmd_gitlab_login(Command):
279
__doc__ = """Log into a GitLab instance.
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
287
Log into GNOME's GitLab (prompts for a token):
289
brz gitlab-login https://gitlab.gnome.org/
291
Log into Debian's salsa, using a token created earlier:
293
brz gitlab-login https://salsa.debian.org if4Theis6Eich7aef0zo
296
takes_args = ['url', 'private_token?']
299
Option('name', help='Name for GitLab site in configuration.',
302
"Don't check that the token is valid."),
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
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')
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)
249
325
class cmd_my_merge_proposals(Command):
250
326
__doc__ = """List all merge proposals owned by the logged-in user.
267
343
closed='Closed merge proposals')]
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)
275
'(Merging %s into %s)\n' %
276
(mp.get_source_branch_url(),
277
mp.get_target_branch_url()))
278
description = mp.get_description()
280
self.outf.writelines(
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)
352
'(Merging %s into %s)\n' %
353
(mp.get_source_branch_url(),
354
mp.get_target_branch_url()))
355
description = mp.get_description()
357
self.outf.writelines(
359
for l in description.splitlines()])
360
self.outf.write('\n')
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)
298
class cmd_hosters(Command):
299
__doc__ = """List all known hosting sites and user details."""
304
for instance in _mod_propose.iter_hoster_instances():
305
current_user = instance.get_current_user()
307
gettext('%s (%s) - user: %s (%s)\n') % (
308
instance.name, instance.base_url,
309
current_user, instance.get_user_url(current_user)))