phabricator: finding old nodes in batch
authorJun Wu <quark@fb.com>
Mon, 10 Jul 2017 13:50:50 -0700
changeset 33442 3ab0d5767b54
parent 33441 de7c6ec27d99
child 33443 e48082e0a8d5
phabricator: finding old nodes in batch This allows us to do extra sanity checks using batch APIs to prevent updating a wrong revision, which could happen when people switch Phabricator instances and having stale tags living in the repo. Differential Revision: https://phab.mercurial-scm.org/D34
contrib/phabricator.py
--- a/contrib/phabricator.py	Mon Jul 10 22:37:33 2017 -0700
+++ b/contrib/phabricator.py	Mon Jul 10 13:50:50 2017 -0700
@@ -139,8 +139,12 @@
 _differentialrevisiondescre = re.compile(
     '^Differential Revision:.*D([1-9][0-9]*)$', re.M)
 
-def getmapping(ctx):
-    """return (node, associated Differential Revision ID) or (None, None)
+def getoldnodedrevmap(repo, nodelist):
+    """find previous nodes that has been sent to Phabricator
+
+    return {node: (oldnode or None, Differential Revision ID)}
+    for node in nodelist with known previous sent versions, or associated
+    Differential Revision IDs.
 
     Examines all precursors and their tags. Tags with format like "D1234" are
     considered a match and the node with that tag, and the number after "D"
@@ -149,23 +153,28 @@
     If tags are not found, examine commit message. The "Differential Revision:"
     line could associate this changeset to a Differential Revision.
     """
-    unfi = ctx.repo().unfiltered()
+    url, token = readurltoken(repo)
+    unfi = repo.unfiltered()
     nodemap = unfi.changelog.nodemap
 
-    # Check tags like "D123"
-    for n in obsolete.allprecursors(unfi.obsstore, [ctx.node()]):
-        if n in nodemap:
-            for tag in unfi.nodetags(n):
-                m = _differentialrevisiontagre.match(tag)
-                if m:
-                    return n, int(m.group(1))
+    result = {} # {node: (oldnode or None, drev)}
+    for node in nodelist:
+        ctx = unfi[node]
+        # Check tags like "D123"
+        for n in obsolete.allprecursors(unfi.obsstore, [node]):
+            if n in nodemap:
+                for tag in unfi.nodetags(n):
+                    m = _differentialrevisiontagre.match(tag)
+                    if m:
+                        result[node] = (n, int(m.group(1)))
+                        continue
 
-    # Check commit message
-    m = _differentialrevisiondescre.search(ctx.description())
-    if m:
-        return None, int(m.group(1))
+        # Check commit message
+        m = _differentialrevisiondescre.search(ctx.description())
+        if m:
+            result[node] = (None, int(m.group(1)))
 
-    return None, None
+    return result
 
 def getdiff(ctx, diffopts):
     """plain-text diff without header (user, commit message, etc)"""
@@ -274,6 +283,8 @@
     if not revs:
         raise error.Abort(_('phabsend requires at least one changeset'))
 
+    oldnodedrev = getoldnodedrevmap(repo, [repo[r].node() for r in revs])
+
     # Send patches one by one so we know their Differential Revision IDs and
     # can provide dependency relationship
     lastrevid = None
@@ -282,7 +293,7 @@
         ctx = repo[rev]
 
         # Get Differential Revision ID
-        oldnode, revid = getmapping(ctx)
+        oldnode, revid = oldnodedrev.get(ctx.node(), (None, None))
         if oldnode != ctx.node():
             # Create or update Differential Revision
             revision = createdifferentialrevision(ctx, revid, lastrevid,