contrib/phabricator.py
author Jun Wu <quark@fb.com>
Tue, 04 Jul 2017 16:16:37 -0700
changeset 33263 ed61189763ef
parent 33200 04cf9927f350
child 33264 266321579c68
permissions -rw-r--r--
phabricator: check associated Differential Revision from commit message Previously, only tags can "associate" a changeset to a Differential Revision. But the usual pattern (arc patch or hg phabread) is to put the Differential Revision URL in commit message. This patch makes the code read commit message to find associated Differential Revision if associated tags are not found. This makes some workflows possible. For example, if the author loses their repo, or switch to another computer, they can continue download their own patches from Phabricator and update them without needing to manually create tags.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     1
# phabricator.py - simple Phabricator integration
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     2
#
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     3
# Copyright 2017 Facebook, Inc.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     4
#
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     5
# This software may be used and distributed according to the terms of the
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     6
# GNU General Public License version 2 or any later version.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     7
"""simple Phabricator integration
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
     8
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
     9
This extension provides a ``phabsend`` command which sends a stack of
33200
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
    10
changesets to Phabricator without amending commit messages, and a ``phabread``
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
    11
command which prints a stack of revisions in a format suitable
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
    12
for :hg:`import`.
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    13
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    14
By default, Phabricator requires ``Test Plan`` which might prevent some
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    15
changeset from being sent. The requirement could be disabled by changing
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    16
``differential.require-test-plan-field`` config server side.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    17
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    18
Config::
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    19
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    20
    [phabricator]
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    21
    # Phabricator URL
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    22
    url = https://phab.example.com/
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    23
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    24
    # API token. Get it from https://$HOST/conduit/login/
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    25
    token = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    26
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    27
    # Repo callsign. If a repo has a URL https://$HOST/diffusion/FOO, then its
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    28
    # callsign is "FOO".
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    29
    callsign = FOO
33200
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
    30
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    31
"""
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    32
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    33
from __future__ import absolute_import
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    34
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    35
import json
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    36
import re
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    37
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    38
from mercurial.i18n import _
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    39
from mercurial import (
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    40
    encoding,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    41
    error,
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    42
    mdiff,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    43
    obsolete,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    44
    patch,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    45
    registrar,
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    46
    scmutil,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
    47
    tags,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    48
    url as urlmod,
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    49
    util,
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    50
)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    51
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    52
cmdtable = {}
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    53
command = registrar.command(cmdtable)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    54
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    55
def urlencodenested(params):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    56
    """like urlencode, but works with nested parameters.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    57
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    58
    For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    59
    flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    60
    urlencode. Note: the encoding is consistent with PHP's http_build_query.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    61
    """
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    62
    flatparams = util.sortdict()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    63
    def process(prefix, obj):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    64
        items = {list: enumerate, dict: lambda x: x.items()}.get(type(obj))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    65
        if items is None:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    66
            flatparams[prefix] = obj
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    67
        else:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    68
            for k, v in items(obj):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    69
                if prefix:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    70
                    process('%s[%s]' % (prefix, k), v)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    71
                else:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    72
                    process(k, v)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    73
    process('', params)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    74
    return util.urlreq.urlencode(flatparams)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    75
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    76
def readurltoken(repo):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    77
    """return conduit url, token and make sure they exist
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    78
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    79
    Currently read from [phabricator] config section. In the future, it might
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    80
    make sense to read from .arcconfig and .arcrc as well.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    81
    """
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    82
    values = []
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    83
    section = 'phabricator'
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    84
    for name in ['url', 'token']:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    85
        value = repo.ui.config(section, name)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    86
        if not value:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    87
            raise error.Abort(_('config %s.%s is required') % (section, name))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    88
        values.append(value)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    89
    return values
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    90
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    91
def callconduit(repo, name, params):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    92
    """call Conduit API, params is a dict. return json.loads result, or None"""
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    93
    host, token = readurltoken(repo)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    94
    url, authinfo = util.url('/'.join([host, 'api', name])).authinfo()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    95
    urlopener = urlmod.opener(repo.ui, authinfo)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    96
    repo.ui.debug('Conduit Call: %s %s\n' % (url, params))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    97
    params = params.copy()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    98
    params['api.token'] = token
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
    99
    request = util.urlreq.request(url, data=urlencodenested(params))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   100
    body = urlopener.open(request).read()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   101
    repo.ui.debug('Conduit Response: %s\n' % body)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   102
    parsed = json.loads(body)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   103
    if parsed.get(r'error_code'):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   104
        msg = (_('Conduit Error (%s): %s')
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   105
               % (parsed[r'error_code'], parsed[r'error_info']))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   106
        raise error.Abort(msg)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   107
    return parsed[r'result']
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   108
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   109
@command('debugcallconduit', [], _('METHOD'))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   110
def debugcallconduit(ui, repo, name):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   111
    """call Conduit API
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   112
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   113
    Call parameters are read from stdin as a JSON blob. Result will be written
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   114
    to stdout as a JSON blob.
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   115
    """
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   116
    params = json.loads(ui.fin.read())
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   117
    result = callconduit(repo, name, params)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   118
    s = json.dumps(result, sort_keys=True, indent=2, separators=(',', ': '))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
   119
    ui.write('%s\n' % s)
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   120
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   121
def getrepophid(repo):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   122
    """given callsign, return repository PHID or None"""
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   123
    # developer config: phabricator.repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   124
    repophid = repo.ui.config('phabricator', 'repophid')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   125
    if repophid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   126
        return repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   127
    callsign = repo.ui.config('phabricator', 'callsign')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   128
    if not callsign:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   129
        return None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   130
    query = callconduit(repo, 'diffusion.repository.search',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   131
                        {'constraints': {'callsigns': [callsign]}})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   132
    if len(query[r'data']) == 0:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   133
        return None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   134
    repophid = encoding.strtolocal(query[r'data'][0][r'phid'])
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   135
    repo.ui.setconfig('phabricator', 'repophid', repophid)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   136
    return repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   137
33263
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   138
_differentialrevisiontagre = re.compile('\AD([1-9][0-9]*)\Z')
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   139
_differentialrevisiondescre = re.compile(
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   140
    '^Differential Revision:.*D([1-9][0-9]*)$', re.M)
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   141
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   142
def getmapping(ctx):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   143
    """return (node, associated Differential Revision ID) or (None, None)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   144
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   145
    Examines all precursors and their tags. Tags with format like "D1234" are
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   146
    considered a match and the node with that tag, and the number after "D"
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   147
    (ex. 1234) will be returned.
33263
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   148
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   149
    If tags are not found, examine commit message. The "Differential Revision:"
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   150
    line could associate this changeset to a Differential Revision.
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   151
    """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   152
    unfi = ctx.repo().unfiltered()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   153
    nodemap = unfi.changelog.nodemap
33263
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   154
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   155
    # Check tags like "D123"
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   156
    for n in obsolete.allprecursors(unfi.obsstore, [ctx.node()]):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   157
        if n in nodemap:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   158
            for tag in unfi.nodetags(n):
33263
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   159
                m = _differentialrevisiontagre.match(tag)
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   160
                if m:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   161
                    return n, int(m.group(1))
33263
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   162
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   163
    # Check commit message
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   164
    m = _differentialrevisiondescre.search(ctx.description())
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   165
    if m:
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   166
        return None, int(m.group(1))
ed61189763ef phabricator: check associated Differential Revision from commit message
Jun Wu <quark@fb.com>
parents: 33200
diff changeset
   167
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   168
    return None, None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   169
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   170
def getdiff(ctx, diffopts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   171
    """plain-text diff without header (user, commit message, etc)"""
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   172
    output = util.stringio()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   173
    for chunk, _label in patch.diffui(ctx.repo(), ctx.p1().node(), ctx.node(),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   174
                                      None, opts=diffopts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   175
        output.write(chunk)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   176
    return output.getvalue()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   177
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   178
def creatediff(ctx):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   179
    """create a Differential Diff"""
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   180
    repo = ctx.repo()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   181
    repophid = getrepophid(repo)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   182
    # Create a "Differential Diff" via "differential.createrawdiff" API
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   183
    params = {'diff': getdiff(ctx, mdiff.diffopts(git=True, context=32767))}
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   184
    if repophid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   185
        params['repositoryPHID'] = repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   186
    diff = callconduit(repo, 'differential.createrawdiff', params)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   187
    if not diff:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   188
        raise error.Abort(_('cannot create diff for %s') % ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   189
    return diff
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   190
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   191
def writediffproperties(ctx, diff):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   192
    """write metadata to diff so patches could be applied losslessly"""
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   193
    params = {
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   194
        'diff_id': diff[r'id'],
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   195
        'name': 'hg:meta',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   196
        'data': json.dumps({
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   197
            'user': ctx.user(),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   198
            'date': '%d %d' % ctx.date(),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   199
        }),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   200
    }
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   201
    callconduit(ctx.repo(), 'differential.setdiffproperty', params)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   202
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   203
def createdifferentialrevision(ctx, revid=None, parentrevid=None):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   204
    """create or update a Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   205
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   206
    If revid is None, create a new Differential Revision, otherwise update
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   207
    revid. If parentrevid is not None, set it as a dependency.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   208
    """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   209
    repo = ctx.repo()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   210
    diff = creatediff(ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   211
    writediffproperties(ctx, diff)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   212
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   213
    transactions = [{'type': 'update', 'value': diff[r'phid']}]
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   214
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   215
    # Use a temporary summary to set dependency. There might be better ways but
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   216
    # I cannot find them for now. But do not do that if we are updating an
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   217
    # existing revision (revid is not None) since that introduces visible
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   218
    # churns (someone edited "Summary" twice) on the web page.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   219
    if parentrevid and revid is None:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   220
        summary = 'Depends on D%s' % parentrevid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   221
        transactions += [{'type': 'summary', 'value': summary},
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   222
                         {'type': 'summary', 'value': ' '}]
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   223
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   224
    # Parse commit message and update related fields.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   225
    desc = ctx.description()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   226
    info = callconduit(repo, 'differential.parsecommitmessage',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   227
                       {'corpus': desc})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   228
    for k, v in info[r'fields'].items():
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   229
        if k in ['title', 'summary', 'testPlan']:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   230
            transactions.append({'type': k, 'value': v})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   231
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   232
    params = {'transactions': transactions}
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   233
    if revid is not None:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   234
        # Update an existing Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   235
        params['objectIdentifier'] = revid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   236
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   237
    revision = callconduit(repo, 'differential.revision.edit', params)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   238
    if not revision:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   239
        raise error.Abort(_('cannot create revision for %s') % ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   240
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   241
    return revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   242
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   243
@command('phabsend',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   244
         [('r', 'rev', [], _('revisions to send'), _('REV'))],
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   245
         _('REV [OPTIONS]'))
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   246
def phabsend(ui, repo, *revs, **opts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   247
    """upload changesets to Phabricator
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   248
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   249
    If there are multiple revisions specified, they will be send as a stack
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   250
    with a linear dependencies relationship using the order specified by the
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   251
    revset.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   252
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   253
    For the first time uploading changesets, local tags will be created to
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   254
    maintain the association. After the first time, phabsend will check
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   255
    obsstore and tags information so it can figure out whether to update an
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   256
    existing Differential Revision, or create a new one.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   257
    """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   258
    revs = list(revs) + opts.get('rev', [])
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   259
    revs = scmutil.revrange(repo, revs)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   260
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   261
    # Send patches one by one so we know their Differential Revision IDs and
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   262
    # can provide dependency relationship
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   263
    lastrevid = None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   264
    for rev in revs:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   265
        ui.debug('sending rev %d\n' % rev)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   266
        ctx = repo[rev]
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   267
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   268
        # Get Differential Revision ID
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   269
        oldnode, revid = getmapping(ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   270
        if oldnode != ctx.node():
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   271
            # Create or update Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   272
            revision = createdifferentialrevision(ctx, revid, lastrevid)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   273
            newrevid = int(revision[r'object'][r'id'])
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   274
            if revid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   275
                action = _('updated')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   276
            else:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   277
                action = _('created')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   278
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   279
            # Create a local tag to note the association
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   280
            tagname = 'D%d' % newrevid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   281
            tags.tag(repo, tagname, ctx.node(), message=None, user=None,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   282
                     date=None, local=True)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   283
        else:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   284
            # Nothing changed. But still set "newrevid" so the next revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   285
            # could depend on this one.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   286
            newrevid = revid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   287
            action = _('skipped')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   288
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   289
        ui.write(_('D%s: %s - %s: %s\n') % (newrevid, action, ctx,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   290
                                            ctx.description().split('\n')[0]))
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
   291
        lastrevid = newrevid
33200
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   292
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   293
_summaryre = re.compile('^Summary:\s*', re.M)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   294
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   295
def readpatch(repo, params, recursive=False):
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   296
    """generate plain-text patch readable by 'hg import'
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   297
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   298
    params is passed to "differential.query". If recursive is True, also return
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   299
    dependent patches.
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   300
    """
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   301
    # Differential Revisions
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   302
    drevs = callconduit(repo, 'differential.query', params)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   303
    if len(drevs) == 1:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   304
        drev = drevs[0]
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   305
    else:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   306
        raise error.Abort(_('cannot get Differential Revision %r') % params)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   307
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   308
    repo.ui.note(_('reading D%s\n') % drev[r'id'])
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   309
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   310
    diffid = max(int(v) for v in drev[r'diffs'])
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   311
    body = callconduit(repo, 'differential.getrawdiff', {'diffID': diffid})
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   312
    desc = callconduit(repo, 'differential.getcommitmessage',
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   313
                       {'revision_id': drev[r'id']})
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   314
    header = '# HG changeset patch\n'
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   315
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   316
    # Remove potential empty "Summary:"
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   317
    desc = _summaryre.sub('', desc)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   318
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   319
    # Try to preserve metadata (user, date) from hg:meta property
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   320
    diffs = callconduit(repo, 'differential.querydiffs', {'ids': [diffid]})
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   321
    props = diffs[str(diffid)][r'properties'] # could be empty list or dict
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   322
    if props and r'hg:meta' in props:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   323
        meta = props[r'hg:meta']
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   324
        for k, v in meta.items():
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   325
            header += '# %s %s\n' % (k.capitalize(), v)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   326
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   327
    patch = ('%s%s\n%s') % (header, desc, body)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   328
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   329
    # Check dependencies
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   330
    if recursive:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   331
        auxiliary = drev.get(r'auxiliary', {})
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   332
        depends = auxiliary.get(r'phabricator:depends-on', [])
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   333
        for phid in depends:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   334
            patch = readpatch(repo, {'phids': [phid]}, recursive=True) + patch
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   335
    return patch
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   336
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   337
@command('phabread',
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   338
         [('', 'stack', False, _('read dependencies'))],
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   339
         _('REVID [OPTIONS]'))
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   340
def phabread(ui, repo, revid, **opts):
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   341
    """print patches from Phabricator suitable for importing
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   342
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   343
    REVID could be a Differential Revision identity, like ``D123``, or just the
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   344
    number ``123``, or a full URL like ``https://phab.example.com/D123``.
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   345
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   346
    If --stack is given, follow dependencies information and read all patches.
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   347
    """
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   348
    try:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   349
        revid = int(revid.split('/')[-1].replace('D', ''))
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   350
    except ValueError:
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   351
        raise error.Abort(_('invalid Revision ID: %s') % revid)
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   352
    patch = readpatch(repo, {'ids': [revid]}, recursive=opts.get('stack'))
04cf9927f350 phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents: 33199
diff changeset
   353
    ui.write(patch)