annotate contrib/phabricator.py @ 33199:228ad1e58a85

phabricator: add phabsend command to send a stack The `phabsend` command is intended to provide `hg email`-like experience - sending a stack, setup dependency information and do not amend existing changesets. It uses differential.createrawdiff and differential.revision.edit Conduit API to create or update a Differential Revision. Local tags like `D123` are written indicating certain changesets were sent to Phabricator. The `phabsend` command will use obsstore and tags information to decide whether to update or create Differential Revisions.
author Jun Wu <quark@fb.com>
date Sun, 02 Jul 2017 20:08:09 -0700
parents 36b3febd739f
children 04cf9927f350
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
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
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
10 changesets to Phabricator without amending commit messages.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
11
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
12 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
13 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
14 ``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
15
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
16 Config::
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
17
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
18 [phabricator]
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
19 # Phabricator URL
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
20 url = https://phab.example.com/
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
21
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
22 # API token. Get it from https://$HOST/conduit/login/
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
23 token = cli-xxxxxxxxxxxxxxxxxxxxxxxxxxxx
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
24
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
25 # 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
26 # callsign is "FOO".
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
27 callsign = FOO
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
28 """
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
29
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
30 from __future__ import absolute_import
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 import json
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
33 import re
33198
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 from mercurial.i18n import _
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
36 from mercurial import (
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
37 encoding,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
38 error,
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
39 mdiff,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
40 obsolete,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
41 patch,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
42 registrar,
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
43 scmutil,
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
44 tags,
33198
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
45 url as urlmod,
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
46 util,
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
47 )
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
48
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
49 cmdtable = {}
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
50 command = registrar.command(cmdtable)
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 def urlencodenested(params):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
53 """like urlencode, but works with nested parameters.
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 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
56 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
57 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
58 """
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
59 flatparams = util.sortdict()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
60 def process(prefix, obj):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
61 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
62 if items is None:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
63 flatparams[prefix] = obj
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
64 else:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
65 for k, v in items(obj):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
66 if prefix:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
67 process('%s[%s]' % (prefix, k), v)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
68 else:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
69 process(k, v)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
70 process('', params)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
71 return util.urlreq.urlencode(flatparams)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
72
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
73 def readurltoken(repo):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
74 """return conduit url, token and make sure they exist
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 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
77 make sense to read from .arcconfig and .arcrc as well.
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 values = []
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
80 section = 'phabricator'
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
81 for name in ['url', 'token']:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
82 value = repo.ui.config(section, name)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
83 if not value:
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
84 raise error.Abort(_('config %s.%s is required') % (section, name))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
85 values.append(value)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
86 return values
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
87
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
88 def callconduit(repo, name, params):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
89 """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
90 host, token = readurltoken(repo)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
91 url, authinfo = util.url('/'.join([host, 'api', name])).authinfo()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
92 urlopener = urlmod.opener(repo.ui, authinfo)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
93 repo.ui.debug('Conduit Call: %s %s\n' % (url, params))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
94 params = params.copy()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
95 params['api.token'] = token
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
96 request = util.urlreq.request(url, data=urlencodenested(params))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
97 body = urlopener.open(request).read()
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
98 repo.ui.debug('Conduit Response: %s\n' % body)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
99 parsed = json.loads(body)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
100 if parsed.get(r'error_code'):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
101 msg = (_('Conduit Error (%s): %s')
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
102 % (parsed[r'error_code'], parsed[r'error_info']))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
103 raise error.Abort(msg)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
104 return parsed[r'result']
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
105
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
106 @command('debugcallconduit', [], _('METHOD'))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
107 def debugcallconduit(ui, repo, name):
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
108 """call Conduit API
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
109
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
110 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
111 to stdout as a JSON blob.
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 params = json.loads(ui.fin.read())
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
114 result = callconduit(repo, name, params)
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
115 s = json.dumps(result, sort_keys=True, indent=2, separators=(',', ': '))
36b3febd739f phabricator: add a contrib script
Jun Wu <quark@fb.com>
parents:
diff changeset
116 ui.write('%s\n' % s)
33199
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
117
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
118 def getrepophid(repo):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
119 """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
120 # developer config: phabricator.repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
121 repophid = repo.ui.config('phabricator', 'repophid')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
122 if repophid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
123 return repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
124 callsign = repo.ui.config('phabricator', 'callsign')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
125 if not callsign:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
126 return None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
127 query = callconduit(repo, 'diffusion.repository.search',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
128 {'constraints': {'callsigns': [callsign]}})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
129 if len(query[r'data']) == 0:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
130 return None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
131 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
132 repo.ui.setconfig('phabricator', 'repophid', repophid)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
133 return repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
134
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
135 _differentialrevisionre = re.compile('\AD([1-9][0-9]*)\Z')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
136
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
137 def getmapping(ctx):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
138 """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
139
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
140 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
141 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
142 (ex. 1234) will be returned.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
143 """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
144 unfi = ctx.repo().unfiltered()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
145 nodemap = unfi.changelog.nodemap
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
146 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
147 if n in nodemap:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
148 for tag in unfi.nodetags(n):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
149 m = _differentialrevisionre.match(tag)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
150 if m:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
151 return n, int(m.group(1))
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
152 return None, None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
153
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
154 def getdiff(ctx, diffopts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
155 """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
156 output = util.stringio()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
157 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
158 None, opts=diffopts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
159 output.write(chunk)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
160 return output.getvalue()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
161
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
162 def creatediff(ctx):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
163 """create a Differential Diff"""
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
164 repo = ctx.repo()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
165 repophid = getrepophid(repo)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
166 # 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
167 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
168 if repophid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
169 params['repositoryPHID'] = repophid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
170 diff = callconduit(repo, 'differential.createrawdiff', params)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
171 if not diff:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
172 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
173 return diff
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
174
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
175 def writediffproperties(ctx, diff):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
176 """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
177 params = {
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
178 'diff_id': diff[r'id'],
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
179 'name': 'hg:meta',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
180 'data': json.dumps({
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
181 'user': ctx.user(),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
182 'date': '%d %d' % ctx.date(),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
183 }),
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
184 }
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
185 callconduit(ctx.repo(), 'differential.setdiffproperty', params)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
186
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
187 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
188 """create or update a Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
189
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
190 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
191 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
192 """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
193 repo = ctx.repo()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
194 diff = creatediff(ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
195 writediffproperties(ctx, diff)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
196
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
197 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
198
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
199 # 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
200 # 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
201 # 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
202 # 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
203 if parentrevid and revid is None:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
204 summary = 'Depends on D%s' % parentrevid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
205 transactions += [{'type': 'summary', 'value': summary},
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
206 {'type': 'summary', 'value': ' '}]
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
207
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
208 # 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
209 desc = ctx.description()
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
210 info = callconduit(repo, 'differential.parsecommitmessage',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
211 {'corpus': desc})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
212 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
213 if k in ['title', 'summary', 'testPlan']:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
214 transactions.append({'type': k, 'value': v})
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
215
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
216 params = {'transactions': transactions}
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
217 if revid is not None:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
218 # Update an existing Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
219 params['objectIdentifier'] = revid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
220
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
221 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
222 if not revision:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
223 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
224
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
225 return revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
226
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
227 @command('phabsend',
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
228 [('r', 'rev', [], _('revisions to send'), _('REV'))],
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
229 _('REV [OPTIONS]'))
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
230 def phabsend(ui, repo, *revs, **opts):
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
231 """upload changesets to Phabricator
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
232
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
233 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
234 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
235 revset.
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 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
238 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
239 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
240 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
241 """
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
242 revs = list(revs) + opts.get('rev', [])
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
243 revs = scmutil.revrange(repo, revs)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
244
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
245 # 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
246 # can provide dependency relationship
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
247 lastrevid = None
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
248 for rev in revs:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
249 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
250 ctx = repo[rev]
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
251
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
252 # Get Differential Revision ID
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
253 oldnode, revid = getmapping(ctx)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
254 if oldnode != ctx.node():
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
255 # Create or update Differential Revision
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
256 revision = createdifferentialrevision(ctx, revid, lastrevid)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
257 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
258 if revid:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
259 action = _('updated')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
260 else:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
261 action = _('created')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
262
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
263 # 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
264 tagname = 'D%d' % newrevid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
265 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
266 date=None, local=True)
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
267 else:
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
268 # 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
269 # could depend on this one.
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
270 newrevid = revid
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
271 action = _('skipped')
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
272
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
273 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
274 ctx.description().split('\n')[0]))
228ad1e58a85 phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents: 33198
diff changeset
275 lastrevid = newrevid