diff --git a/hgext/phabricator.py b/hgext/phabricator.py --- a/hgext/phabricator.py +++ b/hgext/phabricator.py @@ -11,6 +11,10 @@ revisions in a format suitable for :hg:`import`, and a ``phabupdate`` command to update statuses in batch. +A "phabstatus" view for :hg:`show` is also provided; it displays status +information of Phabricator differentials associated with unfinished +changesets. + By default, Phabricator requires ``Test Plan`` which might prevent some changeset from being sent. The requirement could be disabled by changing ``differential.require-test-plan-field`` config server side. @@ -60,9 +64,11 @@ encoding, error, exthelper, + graphmod, httpconnection as httpconnectionmod, match, mdiff, + logcmdutil, obsutil, parser, patch, @@ -80,6 +86,11 @@ procutil, stringutil, ) +from hgext.show import ( + longestshortest, + showview, +) + # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should @@ -462,6 +473,29 @@ return result +def getdrevmap(repo, revs): + """Return a dict mapping each rev in `revs` to their Differential + Revision ID. + """ + result = {} + for rev in revs: + result[rev] = None + ctx = repo[rev] + # Check commit message + m = _differentialrevisiondescre.search(ctx.description()) + if m: + result[rev] = int(m.group('id')) + continue + # Check tags + for tag in repo.nodetags(ctx.node()): + m = _differentialrevisiontagre.match(tag) + if m: + result[rev] = int(m.group(1)) + break + + return result + + def getdiff(ctx, diffopts): """plain-text diff without header (user, commit message, etc)""" output = util.stringio() @@ -1648,3 +1682,41 @@ return templateutil.hybriddict({b'url': url, b'id': t,}) return None + + +@showview(b'phabstatus', csettopic=b'work') +def phabstatusshowview(ui, repo, displayer): + """Phabricator differiential status""" + revs = repo.revs('sort(_underway(), topo)') + drevmap = getdrevmap(repo, revs) + revs, drevids, revsbydrevid = [], set([]), {} + for rev, drevid in pycompat.iteritems(drevmap): + if drevid is not None: + revs.append(rev) + drevids.add(drevid) + revsbydrevid.setdefault(drevid, set([])).add(rev) + + drevs = callconduit(ui, b'differential.query', {b'ids': list(drevids)}) + drevsbyrev = {} + for drev in drevs: + for rev in revsbydrevid[int(drev[b'id'])]: + drevsbyrev[rev] = drev + + def phabstatus(ctx): + drev = drevsbyrev[ctx.rev()] + ui.write(b"\n%(uri)s %(statusName)s\n" % drev) + + revs = smartset.baseset(revs) + revdag = graphmod.dagwalker(repo, revs) + + ui.setconfig(b'experimental', b'graphshorten', True) + displayer._exthook = phabstatus + nodelen = longestshortest(repo, revs) + logcmdutil.displaygraph( + ui, + repo, + revdag, + displayer, + graphmod.asciiedges, + props={b'nodelen': nodelen}, + )