hgext/phabricator.py
changeset 43857 70060915c3f2
parent 43847 16b607e9f714
child 43858 79c0121220e3
equal deleted inserted replaced
43856:a47ccdcce4f9 43857:70060915c3f2
     8 
     8 
     9 This extension provides a ``phabsend`` command which sends a stack of
     9 This extension provides a ``phabsend`` command which sends a stack of
    10 changesets to Phabricator, and a ``phabread`` command which prints a stack of
    10 changesets to Phabricator, and a ``phabread`` command which prints a stack of
    11 revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command
    11 revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command
    12 to update statuses in batch.
    12 to update statuses in batch.
       
    13 
       
    14 A "phabstatus" view for :hg:`show` is also provided; it displays status
       
    15 information of Phabricator differentials associated with unfinished
       
    16 changesets.
    13 
    17 
    14 By default, Phabricator requires ``Test Plan`` which might prevent some
    18 By default, Phabricator requires ``Test Plan`` which might prevent some
    15 changeset from being sent. The requirement could be disabled by changing
    19 changeset from being sent. The requirement could be disabled by changing
    16 ``differential.require-test-plan-field`` config server side.
    20 ``differential.require-test-plan-field`` config server side.
    17 
    21 
    58     cmdutil,
    62     cmdutil,
    59     context,
    63     context,
    60     encoding,
    64     encoding,
    61     error,
    65     error,
    62     exthelper,
    66     exthelper,
       
    67     graphmod,
    63     httpconnection as httpconnectionmod,
    68     httpconnection as httpconnectionmod,
       
    69     logcmdutil,
    64     match,
    70     match,
    65     mdiff,
    71     mdiff,
    66     obsutil,
    72     obsutil,
    67     parser,
    73     parser,
    68     patch,
    74     patch,
    78 )
    84 )
    79 from mercurial.utils import (
    85 from mercurial.utils import (
    80     procutil,
    86     procutil,
    81     stringutil,
    87     stringutil,
    82 )
    88 )
       
    89 from . import show
       
    90 
    83 
    91 
    84 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    92 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
    85 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    93 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
    86 # be specifying the version(s) of Mercurial they are tested with, or
    94 # be specifying the version(s) of Mercurial they are tested with, or
    87 # leave the attribute unspecified.
    95 # leave the attribute unspecified.
   459                 oldnode = getnode(lastdiff)
   467                 oldnode = getnode(lastdiff)
   460                 if oldnode and not has_node(oldnode):
   468                 if oldnode and not has_node(oldnode):
   461                     oldnode = None
   469                     oldnode = None
   462 
   470 
   463             result[newnode] = (oldnode, lastdiff, drev)
   471             result[newnode] = (oldnode, lastdiff, drev)
       
   472 
       
   473     return result
       
   474 
       
   475 
       
   476 def getdrevmap(repo, revs):
       
   477     """Return a dict mapping each rev in `revs` to their Differential Revision
       
   478     ID or None.
       
   479     """
       
   480     result = {}
       
   481     for rev in revs:
       
   482         result[rev] = None
       
   483         ctx = repo[rev]
       
   484         # Check commit message
       
   485         m = _differentialrevisiondescre.search(ctx.description())
       
   486         if m:
       
   487             result[rev] = int(m.group('id'))
       
   488             continue
       
   489         # Check tags
       
   490         for tag in repo.nodetags(ctx.node()):
       
   491             m = _differentialrevisiontagre.match(tag)
       
   492             if m:
       
   493                 result[rev] = int(m.group(1))
       
   494                 break
   464 
   495 
   465     return result
   496     return result
   466 
   497 
   467 
   498 
   468 def getdiff(ctx, diffopts):
   499 def getdiff(ctx, diffopts):
  1649                     url += b'/'
  1680                     url += b'/'
  1650                 url += t
  1681                 url += t
  1651 
  1682 
  1652                 return templateutil.hybriddict({b'url': url, b'id': t,})
  1683                 return templateutil.hybriddict({b'url': url, b'id': t,})
  1653     return None
  1684     return None
       
  1685 
       
  1686 
       
  1687 @show.showview(b'phabstatus', csettopic=b'work')
       
  1688 def phabstatusshowview(ui, repo, displayer):
       
  1689     """Phabricator differiential status"""
       
  1690     revs = repo.revs('sort(_underway(), topo)')
       
  1691     drevmap = getdrevmap(repo, revs)
       
  1692     unknownrevs, drevids, revsbydrevid = [], set([]), {}
       
  1693     for rev, drevid in pycompat.iteritems(drevmap):
       
  1694         if drevid is not None:
       
  1695             drevids.add(drevid)
       
  1696             revsbydrevid.setdefault(drevid, set([])).add(rev)
       
  1697         else:
       
  1698             unknownrevs.append(rev)
       
  1699 
       
  1700     drevs = callconduit(ui, b'differential.query', {b'ids': list(drevids)})
       
  1701     drevsbyrev = {}
       
  1702     for drev in drevs:
       
  1703         for rev in revsbydrevid[int(drev[b'id'])]:
       
  1704             drevsbyrev[rev] = drev
       
  1705 
       
  1706     def phabstatus(ctx):
       
  1707         drev = drevsbyrev[ctx.rev()]
       
  1708         ui.write(b"\n%(uri)s %(statusName)s\n" % drev)
       
  1709 
       
  1710     revs -= smartset.baseset(unknownrevs)
       
  1711     revdag = graphmod.dagwalker(repo, revs)
       
  1712 
       
  1713     ui.setconfig(b'experimental', b'graphshorten', True)
       
  1714     displayer._exthook = phabstatus
       
  1715     nodelen = show.longestshortest(repo, revs)
       
  1716     logcmdutil.displaygraph(
       
  1717         ui,
       
  1718         repo,
       
  1719         revdag,
       
  1720         displayer,
       
  1721         graphmod.asciiedges,
       
  1722         props={b'nodelen': nodelen},
       
  1723     )