159
170
def run(self, submit_branch=None, directory='.', hoster=None,
160
171
reviewers=None, name=None, no_allow_lossy=False, description=None,
161
172
labels=None, prerequisite=None, commit_message=None, wip=False,
162
allow_collaboration=False):
173
allow_collaboration=False, allow_empty=False, overwrite=False):
163
174
tree, branch, relpath = (
164
175
controldir.ControlDir.open_containing_tree_or_branch(directory))
165
176
if submit_branch is None:
167
178
if submit_branch is None:
168
179
submit_branch = branch.get_parent()
169
180
if submit_branch is None:
170
raise errors.BzrCommandError(
181
raise errors.CommandError(
171
182
gettext("No target location specified or remembered"))
173
target = _mod_branch.Branch.open(submit_branch)
183
target = _mod_branch.Branch.open(submit_branch)
185
_check_already_merged(branch, target)
174
186
if hoster is None:
175
187
hoster = _mod_propose.get_hoster(target)
179
191
name = branch_name(branch)
180
192
remote_branch, public_branch_url = hoster.publish_derived(
181
branch, target, name=name, allow_lossy=not no_allow_lossy)
193
branch, target, name=name, allow_lossy=not no_allow_lossy,
182
195
branch.set_push_location(remote_branch.user_url)
183
196
branch.set_submit_branch(target.user_url)
184
197
note(gettext('Published branch to %s') % public_branch_url)
235
248
self.outf.write(gettext('Merge proposal: %s\n') % mp.url)
238
class cmd_github_login(Command):
239
__doc__ = """Log into GitHub.
241
When communicating with GitHub, some commands need to authenticate to
245
takes_args = ['username?']
247
def run(self, username=None):
248
from github import Github, GithubException
249
from breezy.config import AuthenticationConfig
250
authconfig = AuthenticationConfig()
252
username = authconfig.get_user(
253
'https', 'github.com', prompt=u'GitHub username', ask=True)
254
password = authconfig.get_password('https', 'github.com', username)
255
client = Github(username, password)
256
user = client.get_user()
258
authorization = user.create_authorization(
259
scopes=['user', 'repo', 'delete_repo'], note='Breezy',
260
note_url='https://github.com/breezy-team/breezy')
261
except GithubException as e:
262
errs = e.data.get('errors', [])
264
err_code = errs[0].get('code')
265
if err_code == u'already_exists':
266
raise errors.BzrCommandError('token already exists')
267
raise errors.BzrCommandError(e.data['message'])
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)
275
class cmd_gitlab_login(Command):
276
__doc__ = """Log into a GitLab instance.
278
This command takes a GitLab instance URL (e.g. https://gitlab.com)
279
as well as an optional private token. Private tokens can be created via the
284
Log into GNOME's GitLab (prompts for a token):
286
brz gitlab-login https://gitlab.gnome.org/
288
Log into Debian's salsa, using a token created earlier:
290
brz gitlab-login https://salsa.debian.org if4Theis6Eich7aef0zo
293
takes_args = ['url', 'private_token?']
296
Option('name', help='Name for GitLab site in configuration.',
299
"Don't check that the token is valid."),
302
def run(self, url, private_token=None, name=None, no_check=False):
303
from breezy import ui
304
from .gitlabs import store_gitlab_token
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')
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')
316
from breezy.transport import get_transport
317
from .gitlabs import GitLab
318
GitLab(get_transport(url), private_token=private_token)
319
store_gitlab_token(name=name, url=url, private_token=private_token)
322
251
class cmd_my_merge_proposals(Command):
323
252
__doc__ = """List all merge proposals owned by the logged-in user.
337
267
all='All merge proposals',
338
268
open='Open merge proposals',
339
269
merged='Merged merge proposals',
340
closed='Closed merge proposals')]
342
def run(self, status='open', verbose=False):
343
for name, hoster_cls in _mod_propose.hosters.items():
344
for instance in hoster_cls.iter_instances():
270
closed='Closed merge proposals'),
273
help='Use the hoster.',
274
lazy_registry=('breezy.propose', 'hosters')),
277
def run(self, status='open', verbose=False, hoster=None, base_url=None):
279
for instance in _mod_propose.iter_hoster_instances(hoster=hoster):
280
if base_url is not None and instance.base_url != base_url:
345
283
for mp in instance.iter_my_proposals(status=status):
346
284
self.outf.write('%s\n' % mp.url)
349
'(Merging %s into %s)\n' %
350
(mp.get_source_branch_url(),
351
mp.get_target_branch_url()))
286
source_branch_url = mp.get_source_branch_url()
287
if source_branch_url:
289
'(Merging %s into %s)\n' %
291
mp.get_target_branch_url()))
294
'(Merging into %s)\n' %
295
mp.get_target_branch_url())
352
296
description = mp.get_description()
354
298
self.outf.writelines(
356
300
for l in description.splitlines()])
357
301
self.outf.write('\n')
302
except _mod_propose.HosterLoginRequired as e:
303
warning('Skipping %r, login required.', instance)
360
306
class cmd_land_merge_proposal(Command):
367
313
def run(self, url, message=None):
368
314
proposal = _mod_propose.get_proposal_by_url(url)
369
315
proposal.merge(commit_message=message)
318
class cmd_hosters(Command):
319
__doc__ = """List all known hosting sites and user details."""
324
for instance in _mod_propose.iter_hoster_instances():
325
current_user = instance.get_current_user()
326
if current_user is not None:
327
current_user_url = instance.get_user_url(current_user)
328
if current_user_url is not None:
330
gettext('%s (%s) - user: %s (%s)\n') % (
331
instance.name, instance.base_url,
332
current_user, current_user_url))
335
gettext('%s (%s) - user: %s\n') % (
336
instance.name, instance.base_url,
340
gettext('%s (%s) - not logged in\n') % (
341
instance.name, instance.base_url))