Mercurial > hg-stable
changeset 44648:dbe9182c90f5
phabricator: combine commit messages into the review when folding commits
No visible changes here, until an option to enable it is added to `phabsend`.
This combines the Differential fields like Arcanist does, rather than simply
concatenating the text blocks. Aside from populating everything properly in the
web interface, Phabricator fails the review create/update if repeated fields are
seen as would happen with simple concatenation.
On the flip side, now that the Summary and Test Plan fields can contain data
from multiple commits, we can't just join these fields together to determine if
an amend is needed. If that were to happen, every single commit in the folded
range would get amended with the combined commit message, which seems clearly
wrong. Aside from making a minor assumption about the content of the
Differential Revision field (it seems they allow some minor variances with
spacing), this means that for folded reviews, you can't post it, go to the web
page add a missing Test Plan, and then get it added to the commit message by
re-posting it. I don't think that's a big deal.
Differential Revision: https://phab.mercurial-scm.org/D8309
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Fri, 06 Mar 2020 17:03:04 -0500 |
parents | 0437959de6f5 |
children | 419fec8237b7 |
files | hgext/phabricator.py |
diffstat | 1 files changed, 64 insertions(+), 9 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/phabricator.py Wed Feb 26 13:13:49 2020 -0500 +++ b/hgext/phabricator.py Fri Mar 06 17:03:04 2020 -0500 @@ -1067,14 +1067,42 @@ if actions: transactions += actions - # Parse commit message and update related fields. - desc = ctx.description() - info = callconduit( - repo.ui, b'differential.parsecommitmessage', {b'corpus': desc} - ) - for k, v in info[b'fields'].items(): - if k in [b'title', b'summary', b'testPlan']: - transactions.append({b'type': k, b'value': v}) + # When folding multiple local commits into a single review, arcanist will + # take the summary line of the first commit as the title, and then + # concatenate the rest of the remaining messages (including each of their + # first lines) to the rest of the first commit message (each separated by + # an empty line), and use that as the summary field. Do the same here. + # For commits with only a one line message, there is no summary field, as + # this gets assigned to the title. + fields = util.sortdict() # sorted for stable wire protocol in tests + + for i, _ctx in enumerate([ctx]): + # Parse commit message and update related fields. + desc = _ctx.description() + info = callconduit( + repo.ui, b'differential.parsecommitmessage', {b'corpus': desc} + ) + + for k in [b'title', b'summary', b'testPlan']: + v = info[b'fields'].get(k) + if not v: + continue + + if i == 0: + # Title, summary and test plan (if present) are taken verbatim + # for the first commit. + fields[k] = v.rstrip() + continue + elif k == b'title': + # Add subsequent titles (i.e. the first line of the commit + # message) back to the summary. + k = b'summary' + + # Append any current field to the existing composite field + fields[k] = b'\n\n'.join(filter(None, [fields.get(k), v.rstrip()])) + + for k, v in fields.items(): + transactions.append({b'type': k, b'value': v}) params = {b'transactions': transactions} if revid is not None: @@ -1266,7 +1294,7 @@ old = unfi[rev] drevid = drevids[i] drev = [d for d in drevs if int(d[b'id']) == drevid][0] - newdesc = getdescfromdrev(drev) + newdesc = get_amended_desc(drev, old, False) # Make sure commit message contain "Differential Revision" if old.description() != newdesc: if old.phase() == phases.public: @@ -1593,6 +1621,33 @@ return b'\n\n'.join(filter(None, [title, summary, testplan, uri])) +def get_amended_desc(drev, ctx, folded): + """similar to ``getdescfromdrev``, but supports a folded series of commits + + This is used when determining if an individual commit needs to have its + message amended after posting it for review. The determination is made for + each individual commit, even when they were folded into one review. + """ + if not folded: + return getdescfromdrev(drev) + + uri = b'Differential Revision: %s' % drev[b'uri'] + + # Since the commit messages were combined when posting multiple commits + # with --fold, the fields can't be read from Phabricator here, or *all* + # affected local revisions will end up with the same commit message after + # the URI is amended in. Append in the DREV line, or update it if it + # exists. At worst, this means commit message or test plan updates on + # Phabricator aren't propagated back to the repository, but that seems + # reasonable for the case where local commits are effectively combined + # in Phabricator. + m = _differentialrevisiondescre.search(ctx.description()) + if not m: + return b'\n\n'.join([ctx.description(), uri]) + + return _differentialrevisiondescre.sub(uri, ctx.description()) + + def getdiffmeta(diff): """get commit metadata (date, node, user, p1) from a diff object