Rev 5549: Add lp-find-proposal command. in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Nov 23 16:54:51 GMT 2010


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5549 [merge]
revision-id: pqm at pqm.ubuntu.com-20101123165450-bmll7p8fjng1d8xy
parent: pqm at pqm.ubuntu.com-20101122222758-wr1j89eb778ypclt
parent: aaron at aaronbentley.com-20101123145433-i231qdd7v9t6yf5t
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2010-11-23 16:54:50 +0000
message:
  Add lp-find-proposal command.
modified:
  bzrlib/plugins/launchpad/__init__.py __init__.py-20060315182712-2d5feebd2a1032dc
  bzrlib/plugins/launchpad/lp_api.py lp_api.py-20090704082908-79il6zl4gugwl3wz-1
  bzrlib/plugins/launchpad/lp_propose.py lp_submit.py-20100120065117-penrmqruf596pui6-1
=== modified file 'bzrlib/plugins/launchpad/__init__.py'
--- a/bzrlib/plugins/launchpad/__init__.py	2010-10-11 14:10:29 +0000
+++ b/bzrlib/plugins/launchpad/__init__.py	2010-11-23 14:54:33 +0000
@@ -47,6 +47,8 @@
 lazy_import(globals(), """
 from bzrlib import (
     branch as _mod_branch,
+    errors,
+    ui,
     trace,
     )
 """)
@@ -367,6 +369,84 @@
 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('No review found.')
+            trace.note('%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('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('Finding merge')
+            merging_revision = graph.find_lefthand_merger(
+                revision_id, b.last_revision())
+            if merging_revision is None:
+                raise errors.InvalidRevisionSpec(revision[0].user_spec, b)
+        pb.update('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('Finding Launchpad branch')
+        lpb = lp_api.LaunchpadBranch.from_bzr(launchpad, b,
+                                              create_missing=False)
+        pb.update('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)
+
+
 def _register_directory():
     directories.register_lazy('lp:', 'bzrlib.plugins.launchpad.lp_directory',
                               'LaunchpadDirectory',

=== modified file 'bzrlib/plugins/launchpad/lp_api.py'
--- a/bzrlib/plugins/launchpad/lp_api.py	2010-03-05 08:55:12 +0000
+++ b/bzrlib/plugins/launchpad/lp_api.py	2010-11-23 14:54:33 +0000
@@ -23,6 +23,7 @@
 
 import os
 import re
+import urlparse
 
 from bzrlib import (
     branch,
@@ -47,6 +48,10 @@
     STAGING_SERVICE_ROOT,
     Launchpad,
     )
+try:
+    from launchpadlib.uris import LPNET_SERVICE_ROOT
+except ImportError:
+    LPNET_SERVICE_ROOT = 'https://api.launchpad.net/beta/'
 
 
 # Declare the minimum version of launchpadlib that we need in order to work.
@@ -75,7 +80,7 @@
 
 
 LAUNCHPAD_API_URLS = {
-    'production': 'https://api.launchpad.net/beta/',
+    'production': LPNET_SERVICE_ROOT,
     'edge': EDGE_SERVICE_ROOT,
     'staging': STAGING_SERVICE_ROOT,
     'dev': 'https://api.launchpad.dev/beta/',
@@ -101,6 +106,13 @@
         raise InvalidLaunchpadInstance(lp_instance)
 
 
+class NoLaunchpadBranch(errors.BzrError):
+    _fmt = 'No launchpad branch could be found for branch "%(url)s".'
+
+    def __init__(self, branch):
+        errors.BzrError.__init__(self, branch=branch, url=branch.base)
+
+
 def login(service, timeout=None, proxy_info=None):
     """Log in to the Launchpad API.
 
@@ -187,7 +199,7 @@
                            'bazaar.staging.launchpad.net')
 
     @classmethod
-    def from_bzr(cls, launchpad, bzr_branch):
+    def from_bzr(cls, launchpad, bzr_branch, create_missing=True):
         """Find a Launchpad branch from a bzr branch."""
         check_update = True
         for url in cls.candidate_urls(bzr_branch):
@@ -198,6 +210,8 @@
             if lp_branch is not None:
                 break
         else:
+            if not create_missing:
+                raise NoLaunchpadBranch(bzr_branch)
             lp_branch = cls.create_now(launchpad, bzr_branch)
             check_update = False
         return cls(lp_branch, bzr_branch.base, bzr_branch, check_update)
@@ -280,3 +294,13 @@
         if lp_branch:
             return lp_branch
     raise NotLaunchpadBranch(url)
+
+
+def canonical_url(object):
+    """Return the canonical URL for a branch."""
+    scheme, netloc, path, params, query, fragment = urlparse.urlparse(
+        str(object.self_link))
+    path = '/'.join(path.split('/')[2:])
+    netloc = netloc.replace('api.', 'code.')
+    return urlparse.urlunparse((scheme, netloc, path, params, query,
+                                fragment))

=== modified file 'bzrlib/plugins/launchpad/lp_propose.py'
--- a/bzrlib/plugins/launchpad/lp_propose.py	2010-08-25 10:20:41 +0000
+++ b/bzrlib/plugins/launchpad/lp_propose.py	2010-11-23 14:54:33 +0000
@@ -15,7 +15,6 @@
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
 
-import urlparse
 import webbrowser
 
 from bzrlib import (
@@ -27,6 +26,7 @@
     lp_api,
     lp_registration,
 )
+from bzrlib.plugins.launchpad.lp_api import canonical_url
 
 from lazr.restfulclient import errors as restful_errors
 
@@ -217,13 +217,3 @@
         old_tree):
         if c and k == 'file':
             yield str(path)
-
-
-def canonical_url(object):
-    """Return the canonical URL for a branch."""
-    scheme, netloc, path, params, query, fragment = urlparse.urlparse(
-        str(object.self_link))
-    path = '/'.join(path.split('/')[2:])
-    netloc = netloc.replace('api.', 'code.')
-    return urlparse.urlunparse((scheme, netloc, path, params, query,
-                                fragment))




More information about the bazaar-commits mailing list