Rev 6496: (jelmer) Lazily load launchpad plugin commands. (Jelmer Vernooij) in file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
Patch Queue Manager
pqm at pqm.ubuntu.com
Mon Mar 12 15:03:18 UTC 2012
At file:///srv/pqm.bazaar-vcs.org/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6496 [merge]
revision-id: pqm at pqm.ubuntu.com-20120312150317-nrt00el7ooyvbk94
parent: pqm at pqm.ubuntu.com-20120312133809-q6xr6ujz40gpucun
parent: jelmer at samba.org-20120312143526-wdjixe5gf6xbiair
committer: Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Mon 2012-03-12 15:03:17 +0000
message:
(jelmer) Lazily load launchpad plugin commands. (Jelmer Vernooij)
added:
bzrlib/plugins/launchpad/cmds.py cmds.py-20120310190900-ivsmwjx0w9s5gpm3-1
modified:
bzrlib/plugins/launchpad/__init__.py __init__.py-20060315182712-2d5feebd2a1032dc
=== modified file 'bzrlib/plugins/launchpad/__init__.py'
--- a/bzrlib/plugins/launchpad/__init__.py 2012-03-06 17:17:27 +0000
+++ b/bzrlib/plugins/launchpad/__init__.py 2012-03-10 19:11:06 +0000
@@ -42,420 +42,29 @@
# see http://wiki.bazaar.canonical.com/Specs/BranchRegistrationTool
-from bzrlib.lazy_import import lazy_import
-lazy_import(globals(), """
-from bzrlib import (
- ui,
- trace,
- )
-from bzrlib.i18n import gettext
-""")
-
from bzrlib import (
branch as _mod_branch,
config as _mod_config,
- controldir,
lazy_regex,
# Since we are a built-in plugin we share the bzrlib version
+ trace,
version_info,
)
from bzrlib.commands import (
- Command,
- register_command,
+ plugin_cmds,
)
from bzrlib.directory_service import directories
-from bzrlib.errors import (
- BzrCommandError,
- InvalidRevisionSpec,
- InvalidURL,
- NoPublicBranch,
- NotBranchError,
- )
from bzrlib.help_topics import topic_registry
-from bzrlib.option import (
- Option,
- ListOption,
- )
-
-
-class cmd_register_branch(Command):
- __doc__ = """Register a branch with launchpad.net.
-
- This command lists a bzr branch in the directory of branches on
- launchpad.net. Registration allows the branch to be associated with
- bugs or specifications.
-
- Before using this command you must register the project to which the
- branch belongs, and create an account for yourself on launchpad.net.
-
- arguments:
- public_url: The publicly visible url for the branch to register.
- This must be an http or https url (which Launchpad can read
- from to access the branch). Local file urls, SFTP urls, and
- bzr+ssh urls will not work.
- If no public_url is provided, bzr will use the configured
- public_url if there is one for the current branch, and
- otherwise error.
-
- example:
- bzr register-branch http://foo.com/bzr/fooproject.mine \\
- --project fooproject
- """
- takes_args = ['public_url?']
- takes_options = [
- Option('project',
- 'Launchpad project short name to associate with the branch.',
- unicode),
- Option('product',
- 'Launchpad product short name to associate with the branch.',
- unicode,
- hidden=True),
- Option('branch-name',
- 'Short name for the branch; '
- 'by default taken from the last component of the url.',
- unicode),
- Option('branch-title',
- 'One-sentence description of the branch.',
- unicode),
- Option('branch-description',
- 'Longer description of the purpose or contents of the branch.',
- unicode),
- Option('author',
- "Branch author's email address, if not yourself.",
- unicode),
- Option('link-bug',
- 'The bug this branch fixes.',
- int),
- Option('dry-run',
- 'Prepare the request but don\'t actually send it.')
- ]
-
-
- def run(self,
- public_url=None,
- project='',
- product=None,
- branch_name='',
- branch_title='',
- branch_description='',
- author='',
- link_bug=None,
- dry_run=False):
- from bzrlib.plugins.launchpad.lp_registration import (
- BranchRegistrationRequest, BranchBugLinkRequest,
- DryRunLaunchpadService, LaunchpadService)
- if public_url is None:
- try:
- b = _mod_branch.Branch.open_containing('.')[0]
- except NotBranchError:
- raise BzrCommandError(gettext(
- 'register-branch requires a public '
- 'branch url - see bzr help register-branch.'))
- public_url = b.get_public_branch()
- if public_url is None:
- raise NoPublicBranch(b)
- if product is not None:
- project = product
- trace.note(gettext(
- '--product is deprecated; please use --project.'))
-
-
- rego = BranchRegistrationRequest(branch_url=public_url,
- branch_name=branch_name,
- branch_title=branch_title,
- branch_description=branch_description,
- product_name=project,
- author_email=author,
- )
- linko = BranchBugLinkRequest(branch_url=public_url,
- bug_id=link_bug)
- if not dry_run:
- service = LaunchpadService()
- # This gives back the xmlrpc url that can be used for future
- # operations on the branch. It's not so useful to print to the
- # user since they can't do anything with it from a web browser; it
- # might be nice for the server to tell us about an html url as
- # well.
- else:
- # Run on service entirely in memory
- service = DryRunLaunchpadService()
- service.gather_user_credentials()
- rego.submit(service)
- if link_bug:
- linko.submit(service)
- print 'Branch registered.'
-
-register_command(cmd_register_branch)
-
-
-class cmd_launchpad_open(Command):
- __doc__ = """Open a Launchpad branch page in your web browser."""
-
- aliases = ['lp-open']
- takes_options = [
- Option('dry-run',
- 'Do not actually open the browser. Just say the URL we would '
- 'use.'),
- ]
- takes_args = ['location?']
-
- def _possible_locations(self, location):
- """Yield possible external locations for the branch at 'location'."""
- yield location
- try:
- branch = _mod_branch.Branch.open_containing(location)[0]
- except NotBranchError:
- return
- branch_url = branch.get_public_branch()
- if branch_url is not None:
- yield branch_url
- branch_url = branch.get_push_location()
- if branch_url is not None:
- yield branch_url
-
- def _get_web_url(self, service, location):
- from bzrlib.plugins.launchpad.lp_registration import (
- NotLaunchpadBranch)
- for branch_url in self._possible_locations(location):
- try:
- return service.get_web_url_from_branch_url(branch_url)
- except (NotLaunchpadBranch, InvalidURL):
- pass
- raise NotLaunchpadBranch(branch_url)
-
- def run(self, location=None, dry_run=False):
- from bzrlib.plugins.launchpad.lp_registration import (
- LaunchpadService)
- if location is None:
- location = u'.'
- web_url = self._get_web_url(LaunchpadService(), location)
- trace.note(gettext('Opening %s in web browser') % web_url)
- if not dry_run:
- import webbrowser # this import should not be lazy
- # otherwise bzr.exe lacks this module
- webbrowser.open(web_url)
-
-register_command(cmd_launchpad_open)
-
-
-class cmd_launchpad_login(Command):
- __doc__ = """Show or set the Launchpad user ID.
-
- When communicating with Launchpad, some commands need to know your
- Launchpad user ID. This command can be used to set or show the
- user ID that Bazaar will use for such communication.
-
- :Examples:
- Show the Launchpad ID of the current user::
-
- bzr launchpad-login
-
- Set the Launchpad ID of the current user to 'bob'::
-
- bzr launchpad-login bob
- """
- aliases = ['lp-login']
- takes_args = ['name?']
- takes_options = [
- 'verbose',
- Option('no-check',
- "Don't check that the user name is valid."),
- ]
-
- def run(self, name=None, no_check=False, verbose=False):
- # This is totally separate from any launchpadlib login system.
- from bzrlib.plugins.launchpad import account
- check_account = not no_check
-
- if name is None:
- username = account.get_lp_login()
- if username:
- if check_account:
- account.check_lp_login(username)
- if verbose:
- self.outf.write(gettext(
- "Launchpad user ID exists and has SSH keys.\n"))
- self.outf.write(username + '\n')
- else:
- self.outf.write(gettext('No Launchpad user ID configured.\n'))
- return 1
- else:
- name = name.lower()
- if check_account:
- account.check_lp_login(name)
- if verbose:
- self.outf.write(gettext(
- "Launchpad user ID exists and has SSH keys.\n"))
- account.set_lp_login(name)
- if verbose:
- self.outf.write(gettext("Launchpad user ID set to '%s'.\n") %
- (name,))
-
-register_command(cmd_launchpad_login)
-
-
-# XXX: cmd_launchpad_mirror is untested
-class cmd_launchpad_mirror(Command):
- __doc__ = """Ask Launchpad to mirror a branch now."""
-
- aliases = ['lp-mirror']
- takes_args = ['location?']
-
- def run(self, location='.'):
- from bzrlib.plugins.launchpad import lp_api
- from bzrlib.plugins.launchpad.lp_registration import LaunchpadService
- branch, _ = _mod_branch.Branch.open_containing(location)
- service = LaunchpadService()
- launchpad = lp_api.login(service)
- lp_branch = lp_api.LaunchpadBranch.from_bzr(launchpad, branch,
- create_missing=False)
- lp_branch.lp.requestMirror()
-
-
-register_command(cmd_launchpad_mirror)
-
-
-class cmd_lp_propose_merge(Command):
- __doc__ = """Propose merging a branch on Launchpad.
-
- This will open your usual editor to provide the initial comment. When it
- has created the proposal, it will open it in your default web browser.
-
- The branch will be proposed to merge into SUBMIT_BRANCH. If SUBMIT_BRANCH
- is not supplied, the remembered submit branch will be used. If no submit
- branch is remembered, the development focus will be used.
-
- By default, the SUBMIT_BRANCH's review team will be requested to review
- the merge proposal. This can be overriden by specifying --review (-R).
- The parameter the launchpad account name of the desired reviewer. This
- may optionally be followed by '=' and the review type. For example:
-
- bzr lp-propose-merge --review jrandom --review review-team=qa
-
- This will propose a merge, request "jrandom" to perform a review of
- unspecified type, and request "review-team" to perform a "qa" review.
- """
-
- takes_options = [Option('staging',
- help='Propose the merge on staging.'),
- Option('message', short_name='m', type=unicode,
- help='Commit message.'),
- Option('approve',
- help='Mark the proposal as approved immediately.'),
- Option('fixes', 'The bug this proposal fixes.', str),
- ListOption('review', short_name='R', type=unicode,
- help='Requested reviewer and optional type.')]
-
- takes_args = ['submit_branch?']
-
- aliases = ['lp-submit', 'lp-propose']
-
- def run(self, submit_branch=None, review=None, staging=False,
- message=None, approve=False, fixes=None):
- from bzrlib.plugins.launchpad import lp_propose
- tree, branch, relpath = controldir.ControlDir.open_containing_tree_or_branch(
- '.')
- if review is None:
- reviews = None
- else:
- reviews = []
- for review in review:
- if '=' in review:
- reviews.append(review.split('=', 2))
- else:
- reviews.append((review, ''))
- if submit_branch is None:
- submit_branch = branch.get_submit_branch()
- if submit_branch is None:
- target = None
- else:
- target = _mod_branch.Branch.open(submit_branch)
- proposer = lp_propose.Proposer(tree, branch, target, message,
- reviews, staging, approve=approve,
- fixes=fixes)
- proposer.check_proposal()
- proposer.create_proposal()
-
-
-register_command(cmd_lp_propose_merge)
-
-
-class cmd_lp_find_proposal(Command):
-
- __doc__ = """Find the proposal to merge this revision.
-
- Finds the merge proposal(s) that discussed landing the specified revision.
- This works only if the selected branch was the merge proposal target, and
- if the merged_revno is recorded for the merge proposal. The proposal(s)
- are opened in a web browser.
-
- Any revision involved in the merge may be specified-- the revision in
- which the merge was performed, or one of the revisions that was merged.
-
- So, to find the merge proposal that reviewed line 1 of README::
-
- bzr lp-find-proposal -r annotate:README:1
- """
-
- takes_options = ['revision']
-
- def run(self, revision=None):
- from bzrlib.plugins.launchpad import lp_api
- import webbrowser
- b = _mod_branch.Branch.open_containing('.')[0]
- pb = ui.ui_factory.nested_progress_bar()
- b.lock_read()
- try:
- revno = self._find_merged_revno(revision, b, pb)
- merged = self._find_proposals(revno, b, pb)
- if len(merged) == 0:
- raise BzrCommandError(gettext('No review found.'))
- trace.note(gettext('%d proposals(s) found.') % len(merged))
- for mp in merged:
- webbrowser.open(lp_api.canonical_url(mp))
- finally:
- b.unlock()
- pb.finished()
-
- def _find_merged_revno(self, revision, b, pb):
- if revision is None:
- return b.revno()
- pb.update(gettext('Finding revision-id'))
- revision_id = revision[0].as_revision_id(b)
- # a revno spec is necessarily on the mainline.
- if self._is_revno_spec(revision[0]):
- merging_revision = revision_id
- else:
- graph = b.repository.get_graph()
- pb.update(gettext('Finding merge'))
- merging_revision = graph.find_lefthand_merger(
- revision_id, b.last_revision())
- if merging_revision is None:
- raise InvalidRevisionSpec(revision[0].user_spec, b)
- pb.update(gettext('Finding revno'))
- return b.revision_id_to_revno(merging_revision)
-
- def _find_proposals(self, revno, b, pb):
- launchpad = lp_api.login(lp_registration.LaunchpadService())
- pb.update(gettext('Finding Launchpad branch'))
- lpb = lp_api.LaunchpadBranch.from_bzr(launchpad, b,
- create_missing=False)
- pb.update(gettext('Finding proposals'))
- return list(lpb.lp.getMergeProposals(status=['Merged'],
- merged_revnos=[revno]))
-
-
- @staticmethod
- def _is_revno_spec(spec):
- try:
- int(spec.user_spec)
- except ValueError:
- return False
- else:
- return True
-
-
-register_command(cmd_lp_find_proposal)
+
+for klsname, aliases in [
+ ("cmd_register_branch", []),
+ ("cmd_launchpad_open", ["lp-open"]),
+ ("cmd_launchpad_login", ["lp-login"]),
+ ("cmd_launchpad_mirror", ["lp-mirror"]),
+ ("cmd_lp_propose_merge", ["lp-submit", "lp-propose"]),
+ ("cmd_lp_find_proposal", [])]:
+ plugin_cmds.register_lazy(klsname, aliases,
+ "bzrlib.plugins.launchpad.cmds")
def _register_directory():
=== added file 'bzrlib/plugins/launchpad/cmds.py'
--- a/bzrlib/plugins/launchpad/cmds.py 1970-01-01 00:00:00 +0000
+++ b/bzrlib/plugins/launchpad/cmds.py 2012-03-12 14:35:26 +0000
@@ -0,0 +1,410 @@
+# Copyright (C) 2006-2012 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+"""Launchpad plugin commands."""
+
+from __future__ import absolute_import
+
+from bzrlib import (
+ branch as _mod_branch,
+ controldir,
+ trace,
+ )
+from bzrlib.commands import (
+ Command,
+ )
+from bzrlib.errors import (
+ BzrCommandError,
+ InvalidRevisionSpec,
+ InvalidURL,
+ NoPublicBranch,
+ NotBranchError,
+ )
+from bzrlib.i18n import gettext
+from bzrlib.option import (
+ Option,
+ ListOption,
+ )
+
+
+class cmd_register_branch(Command):
+ __doc__ = """Register a branch with launchpad.net.
+
+ This command lists a bzr branch in the directory of branches on
+ launchpad.net. Registration allows the branch to be associated with
+ bugs or specifications.
+
+ Before using this command you must register the project to which the
+ branch belongs, and create an account for yourself on launchpad.net.
+
+ arguments:
+ public_url: The publicly visible url for the branch to register.
+ This must be an http or https url (which Launchpad can read
+ from to access the branch). Local file urls, SFTP urls, and
+ bzr+ssh urls will not work.
+ If no public_url is provided, bzr will use the configured
+ public_url if there is one for the current branch, and
+ otherwise error.
+
+ example:
+ bzr register-branch http://foo.com/bzr/fooproject.mine \\
+ --project fooproject
+ """
+ takes_args = ['public_url?']
+ takes_options = [
+ Option('project',
+ 'Launchpad project short name to associate with the branch.',
+ unicode),
+ Option('product',
+ 'Launchpad product short name to associate with the branch.',
+ unicode,
+ hidden=True),
+ Option('branch-name',
+ 'Short name for the branch; '
+ 'by default taken from the last component of the url.',
+ unicode),
+ Option('branch-title',
+ 'One-sentence description of the branch.',
+ unicode),
+ Option('branch-description',
+ 'Longer description of the purpose or contents of the branch.',
+ unicode),
+ Option('author',
+ "Branch author's email address, if not yourself.",
+ unicode),
+ Option('link-bug',
+ 'The bug this branch fixes.',
+ int),
+ Option('dry-run',
+ 'Prepare the request but don\'t actually send it.')
+ ]
+
+
+ def run(self,
+ public_url=None,
+ project='',
+ product=None,
+ branch_name='',
+ branch_title='',
+ branch_description='',
+ author='',
+ link_bug=None,
+ dry_run=False):
+ from bzrlib.plugins.launchpad.lp_registration import (
+ BranchRegistrationRequest, BranchBugLinkRequest,
+ DryRunLaunchpadService, LaunchpadService)
+ if public_url is None:
+ try:
+ b = _mod_branch.Branch.open_containing('.')[0]
+ except NotBranchError:
+ raise BzrCommandError(gettext(
+ 'register-branch requires a public '
+ 'branch url - see bzr help register-branch.'))
+ public_url = b.get_public_branch()
+ if public_url is None:
+ raise NoPublicBranch(b)
+ if product is not None:
+ project = product
+ trace.note(gettext(
+ '--product is deprecated; please use --project.'))
+
+
+ rego = BranchRegistrationRequest(branch_url=public_url,
+ branch_name=branch_name,
+ branch_title=branch_title,
+ branch_description=branch_description,
+ product_name=project,
+ author_email=author,
+ )
+ linko = BranchBugLinkRequest(branch_url=public_url,
+ bug_id=link_bug)
+ if not dry_run:
+ service = LaunchpadService()
+ # This gives back the xmlrpc url that can be used for future
+ # operations on the branch. It's not so useful to print to the
+ # user since they can't do anything with it from a web browser; it
+ # might be nice for the server to tell us about an html url as
+ # well.
+ else:
+ # Run on service entirely in memory
+ service = DryRunLaunchpadService()
+ service.gather_user_credentials()
+ rego.submit(service)
+ if link_bug:
+ linko.submit(service)
+ self.outf.write('Branch registered.\n')
+
+
+class cmd_launchpad_open(Command):
+ __doc__ = """Open a Launchpad branch page in your web browser."""
+
+ aliases = ['lp-open']
+ takes_options = [
+ Option('dry-run',
+ 'Do not actually open the browser. Just say the URL we would '
+ 'use.'),
+ ]
+ takes_args = ['location?']
+
+ def _possible_locations(self, location):
+ """Yield possible external locations for the branch at 'location'."""
+ yield location
+ try:
+ branch = _mod_branch.Branch.open_containing(location)[0]
+ except NotBranchError:
+ return
+ branch_url = branch.get_public_branch()
+ if branch_url is not None:
+ yield branch_url
+ branch_url = branch.get_push_location()
+ if branch_url is not None:
+ yield branch_url
+
+ def _get_web_url(self, service, location):
+ from bzrlib.plugins.launchpad.lp_registration import (
+ NotLaunchpadBranch)
+ for branch_url in self._possible_locations(location):
+ try:
+ return service.get_web_url_from_branch_url(branch_url)
+ except (NotLaunchpadBranch, InvalidURL):
+ pass
+ raise NotLaunchpadBranch(branch_url)
+
+ def run(self, location=None, dry_run=False):
+ from bzrlib.plugins.launchpad.lp_registration import (
+ LaunchpadService)
+ if location is None:
+ location = u'.'
+ web_url = self._get_web_url(LaunchpadService(), location)
+ trace.note(gettext('Opening %s in web browser') % web_url)
+ if not dry_run:
+ import webbrowser # this import should not be lazy
+ # otherwise bzr.exe lacks this module
+ webbrowser.open(web_url)
+
+
+class cmd_launchpad_login(Command):
+ __doc__ = """Show or set the Launchpad user ID.
+
+ When communicating with Launchpad, some commands need to know your
+ Launchpad user ID. This command can be used to set or show the
+ user ID that Bazaar will use for such communication.
+
+ :Examples:
+ Show the Launchpad ID of the current user::
+
+ bzr launchpad-login
+
+ Set the Launchpad ID of the current user to 'bob'::
+
+ bzr launchpad-login bob
+ """
+ aliases = ['lp-login']
+ takes_args = ['name?']
+ takes_options = [
+ 'verbose',
+ Option('no-check',
+ "Don't check that the user name is valid."),
+ ]
+
+ def run(self, name=None, no_check=False, verbose=False):
+ # This is totally separate from any launchpadlib login system.
+ from bzrlib.plugins.launchpad import account
+ check_account = not no_check
+
+ if name is None:
+ username = account.get_lp_login()
+ if username:
+ if check_account:
+ account.check_lp_login(username)
+ if verbose:
+ self.outf.write(gettext(
+ "Launchpad user ID exists and has SSH keys.\n"))
+ self.outf.write(username + '\n')
+ else:
+ self.outf.write(gettext('No Launchpad user ID configured.\n'))
+ return 1
+ else:
+ name = name.lower()
+ if check_account:
+ account.check_lp_login(name)
+ if verbose:
+ self.outf.write(gettext(
+ "Launchpad user ID exists and has SSH keys.\n"))
+ account.set_lp_login(name)
+ if verbose:
+ self.outf.write(gettext("Launchpad user ID set to '%s'.\n") %
+ (name,))
+
+
+# XXX: cmd_launchpad_mirror is untested
+class cmd_launchpad_mirror(Command):
+ __doc__ = """Ask Launchpad to mirror a branch now."""
+
+ aliases = ['lp-mirror']
+ takes_args = ['location?']
+
+ def run(self, location='.'):
+ from bzrlib.plugins.launchpad import lp_api
+ from bzrlib.plugins.launchpad.lp_registration import LaunchpadService
+ branch, _ = _mod_branch.Branch.open_containing(location)
+ service = LaunchpadService()
+ launchpad = lp_api.login(service)
+ lp_branch = lp_api.LaunchpadBranch.from_bzr(launchpad, branch,
+ create_missing=False)
+ lp_branch.lp.requestMirror()
+
+
+class cmd_lp_propose_merge(Command):
+ __doc__ = """Propose merging a branch on Launchpad.
+
+ This will open your usual editor to provide the initial comment. When it
+ has created the proposal, it will open it in your default web browser.
+
+ The branch will be proposed to merge into SUBMIT_BRANCH. If SUBMIT_BRANCH
+ is not supplied, the remembered submit branch will be used. If no submit
+ branch is remembered, the development focus will be used.
+
+ By default, the SUBMIT_BRANCH's review team will be requested to review
+ the merge proposal. This can be overriden by specifying --review (-R).
+ The parameter the launchpad account name of the desired reviewer. This
+ may optionally be followed by '=' and the review type. For example:
+
+ bzr lp-propose-merge --review jrandom --review review-team=qa
+
+ This will propose a merge, request "jrandom" to perform a review of
+ unspecified type, and request "review-team" to perform a "qa" review.
+ """
+
+ takes_options = [Option('staging',
+ help='Propose the merge on staging.'),
+ Option('message', short_name='m', type=unicode,
+ help='Commit message.'),
+ Option('approve',
+ help='Mark the proposal as approved immediately.'),
+ Option('fixes', 'The bug this proposal fixes.', str),
+ ListOption('review', short_name='R', type=unicode,
+ help='Requested reviewer and optional type.')]
+
+ takes_args = ['submit_branch?']
+
+ aliases = ['lp-submit', 'lp-propose']
+
+ def run(self, submit_branch=None, review=None, staging=False,
+ message=None, approve=False, fixes=None):
+ from bzrlib.plugins.launchpad import lp_propose
+ tree, branch, relpath = controldir.ControlDir.open_containing_tree_or_branch(
+ '.')
+ if review is None:
+ reviews = None
+ else:
+ reviews = []
+ for review in review:
+ if '=' in review:
+ reviews.append(review.split('=', 2))
+ else:
+ reviews.append((review, ''))
+ if submit_branch is None:
+ submit_branch = branch.get_submit_branch()
+ if submit_branch is None:
+ target = None
+ else:
+ target = _mod_branch.Branch.open(submit_branch)
+ proposer = lp_propose.Proposer(tree, branch, target, message,
+ reviews, staging, approve=approve,
+ fixes=fixes)
+ proposer.check_proposal()
+ proposer.create_proposal()
+
+
+class cmd_lp_find_proposal(Command):
+
+ __doc__ = """Find the proposal to merge this revision.
+
+ Finds the merge proposal(s) that discussed landing the specified revision.
+ This works only if the selected branch was the merge proposal target, and
+ if the merged_revno is recorded for the merge proposal. The proposal(s)
+ are opened in a web browser.
+
+ Any revision involved in the merge may be specified-- the revision in
+ which the merge was performed, or one of the revisions that was merged.
+
+ So, to find the merge proposal that reviewed line 1 of README::
+
+ bzr lp-find-proposal -r annotate:README:1
+ """
+
+ takes_options = ['revision']
+
+ def run(self, revision=None):
+ from bzrlib import ui
+ from bzrlib.plugins.launchpad import lp_api
+ import webbrowser
+ b = _mod_branch.Branch.open_containing('.')[0]
+ pb = ui.ui_factory.nested_progress_bar()
+ b.lock_read()
+ try:
+ revno = self._find_merged_revno(revision, b, pb)
+ merged = self._find_proposals(revno, b, pb)
+ if len(merged) == 0:
+ raise BzrCommandError(gettext('No review found.'))
+ trace.note(gettext('%d proposals(s) found.') % len(merged))
+ for mp in merged:
+ webbrowser.open(lp_api.canonical_url(mp))
+ finally:
+ b.unlock()
+ pb.finished()
+
+ def _find_merged_revno(self, revision, b, pb):
+ if revision is None:
+ return b.revno()
+ pb.update(gettext('Finding revision-id'))
+ revision_id = revision[0].as_revision_id(b)
+ # a revno spec is necessarily on the mainline.
+ if self._is_revno_spec(revision[0]):
+ merging_revision = revision_id
+ else:
+ graph = b.repository.get_graph()
+ pb.update(gettext('Finding merge'))
+ merging_revision = graph.find_lefthand_merger(
+ revision_id, b.last_revision())
+ if merging_revision is None:
+ raise InvalidRevisionSpec(revision[0].user_spec, b)
+ pb.update(gettext('Finding revno'))
+ return b.revision_id_to_revno(merging_revision)
+
+ def _find_proposals(self, revno, b, pb):
+ from bzrlib.plugins.launchpad import (lp_api, lp_registration)
+ launchpad = lp_api.login(lp_registration.LaunchpadService())
+ pb.update(gettext('Finding Launchpad branch'))
+ lpb = lp_api.LaunchpadBranch.from_bzr(launchpad, b,
+ create_missing=False)
+ pb.update(gettext('Finding proposals'))
+ return list(lpb.lp.getMergeProposals(status=['Merged'],
+ merged_revnos=[revno]))
+
+
+ @staticmethod
+ def _is_revno_spec(spec):
+ try:
+ int(spec.user_spec)
+ except ValueError:
+ return False
+ else:
+ return True
+
+
+
More information about the bazaar-commits
mailing list