Mercurial > hg
annotate contrib/phabricator.py @ 33200:04cf9927f350
phabricator: add phabread command to read patches
This patch adds a `phabread` command generating plain-text patches from
Phabricator, suitable for `hg import`. It respects `hg:meta` so user and
date information might be preserved. And it removes `Summary:` field name
which makes the commit message a bit tidier.
To support stacked diffs, a `--stack` flag was added to read dependent
patches recursively.
author | Jun Wu <quark@fb.com> |
---|---|
date | Sun, 02 Jul 2017 20:08:09 -0700 |
parents | 228ad1e58a85 |
children | ed61189763ef |
rev | line source |
---|---|
33198 | 1 # phabricator.py - simple Phabricator integration |
2 # | |
3 # Copyright 2017 Facebook, Inc. | |
4 # | |
5 # This software may be used and distributed according to the terms of the | |
6 # GNU General Public License version 2 or any later version. | |
7 """simple Phabricator integration | |
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 | 18 Config:: |
19 | |
20 [phabricator] | |
21 # Phabricator URL | |
22 url = https://phab.example.com/ | |
23 | |
24 # API token. Get it from https://$HOST/conduit/login/ | |
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 | 31 """ |
32 | |
33 from __future__ import absolute_import | |
34 | |
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 | 37 |
38 from mercurial.i18n import _ | |
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 | 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 | 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 | 48 url as urlmod, |
49 util, | |
50 ) | |
51 | |
52 cmdtable = {} | |
53 command = registrar.command(cmdtable) | |
54 | |
55 def urlencodenested(params): | |
56 """like urlencode, but works with nested parameters. | |
57 | |
58 For example, if params is {'a': ['b', 'c'], 'd': {'e': 'f'}}, it will be | |
59 flattened to {'a[0]': 'b', 'a[1]': 'c', 'd[e]': 'f'} and then passed to | |
60 urlencode. Note: the encoding is consistent with PHP's http_build_query. | |
61 """ | |
62 flatparams = util.sortdict() | |
63 def process(prefix, obj): | |
64 items = {list: enumerate, dict: lambda x: x.items()}.get(type(obj)) | |
65 if items is None: | |
66 flatparams[prefix] = obj | |
67 else: | |
68 for k, v in items(obj): | |
69 if prefix: | |
70 process('%s[%s]' % (prefix, k), v) | |
71 else: | |
72 process(k, v) | |
73 process('', params) | |
74 return util.urlreq.urlencode(flatparams) | |
75 | |
76 def readurltoken(repo): | |
77 """return conduit url, token and make sure they exist | |
78 | |
79 Currently read from [phabricator] config section. In the future, it might | |
80 make sense to read from .arcconfig and .arcrc as well. | |
81 """ | |
82 values = [] | |
83 section = 'phabricator' | |
84 for name in ['url', 'token']: | |
85 value = repo.ui.config(section, name) | |
86 if not value: | |
87 raise error.Abort(_('config %s.%s is required') % (section, name)) | |
88 values.append(value) | |
89 return values | |
90 | |
91 def callconduit(repo, name, params): | |
92 """call Conduit API, params is a dict. return json.loads result, or None""" | |
93 host, token = readurltoken(repo) | |
94 url, authinfo = util.url('/'.join([host, 'api', name])).authinfo() | |
95 urlopener = urlmod.opener(repo.ui, authinfo) | |
96 repo.ui.debug('Conduit Call: %s %s\n' % (url, params)) | |
97 params = params.copy() | |
98 params['api.token'] = token | |
99 request = util.urlreq.request(url, data=urlencodenested(params)) | |
100 body = urlopener.open(request).read() | |
101 repo.ui.debug('Conduit Response: %s\n' % body) | |
102 parsed = json.loads(body) | |
103 if parsed.get(r'error_code'): | |
104 msg = (_('Conduit Error (%s): %s') | |
105 % (parsed[r'error_code'], parsed[r'error_info'])) | |
106 raise error.Abort(msg) | |
107 return parsed[r'result'] | |
108 | |
109 @command('debugcallconduit', [], _('METHOD')) | |
110 def debugcallconduit(ui, repo, name): | |
111 """call Conduit API | |
112 | |
113 Call parameters are read from stdin as a JSON blob. Result will be written | |
114 to stdout as a JSON blob. | |
115 """ | |
116 params = json.loads(ui.fin.read()) | |
117 result = callconduit(repo, name, params) | |
118 s = json.dumps(result, sort_keys=True, indent=2, separators=(',', ': ')) | |
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 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
138 _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
|
139 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
140 def getmapping(ctx): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
141 """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
|
142 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
143 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
|
144 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
|
145 (ex. 1234) will be returned. |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
146 """ |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
147 unfi = ctx.repo().unfiltered() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
148 nodemap = unfi.changelog.nodemap |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
149 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
|
150 if n in nodemap: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
151 for tag in unfi.nodetags(n): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
152 m = _differentialrevisionre.match(tag) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
153 if m: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
154 return n, int(m.group(1)) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
155 return None, None |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
156 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
157 def getdiff(ctx, diffopts): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
158 """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
|
159 output = util.stringio() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
160 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
|
161 None, opts=diffopts): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
162 output.write(chunk) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
163 return output.getvalue() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
164 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
165 def creatediff(ctx): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
166 """create a Differential Diff""" |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
167 repo = ctx.repo() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
168 repophid = getrepophid(repo) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
169 # 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
|
170 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
|
171 if repophid: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
172 params['repositoryPHID'] = repophid |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
173 diff = callconduit(repo, 'differential.createrawdiff', params) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
174 if not diff: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
175 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
|
176 return diff |
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 writediffproperties(ctx, diff): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
179 """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
|
180 params = { |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
181 'diff_id': diff[r'id'], |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
182 'name': 'hg:meta', |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
183 'data': json.dumps({ |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
184 'user': ctx.user(), |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
185 'date': '%d %d' % ctx.date(), |
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 } |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
188 callconduit(ctx.repo(), 'differential.setdiffproperty', params) |
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 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
|
191 """create or update a Differential Revision |
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 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
|
194 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
|
195 """ |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
196 repo = ctx.repo() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
197 diff = creatediff(ctx) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
198 writediffproperties(ctx, diff) |
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 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
|
201 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
202 # 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
|
203 # 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
|
204 # 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
|
205 # 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
|
206 if parentrevid and revid is None: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
207 summary = 'Depends on D%s' % parentrevid |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
208 transactions += [{'type': 'summary', 'value': summary}, |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
209 {'type': 'summary', 'value': ' '}] |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
210 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
211 # 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
|
212 desc = ctx.description() |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
213 info = callconduit(repo, 'differential.parsecommitmessage', |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
214 {'corpus': desc}) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
215 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
|
216 if k in ['title', 'summary', 'testPlan']: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
217 transactions.append({'type': k, 'value': v}) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
218 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
219 params = {'transactions': transactions} |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
220 if revid is not None: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
221 # Update an existing Differential Revision |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
222 params['objectIdentifier'] = revid |
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 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
|
225 if not revision: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
226 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
|
227 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
228 return revision |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
229 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
230 @command('phabsend', |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
231 [('r', 'rev', [], _('revisions to send'), _('REV'))], |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
232 _('REV [OPTIONS]')) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
233 def phabsend(ui, repo, *revs, **opts): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
234 """upload changesets to Phabricator |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
235 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
236 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
|
237 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
|
238 revset. |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
239 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
240 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
|
241 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
|
242 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
|
243 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
|
244 """ |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
245 revs = list(revs) + opts.get('rev', []) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
246 revs = scmutil.revrange(repo, revs) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
247 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
248 # 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
|
249 # can provide dependency relationship |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
250 lastrevid = None |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
251 for rev in revs: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
252 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
|
253 ctx = repo[rev] |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
254 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
255 # Get Differential Revision ID |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
256 oldnode, revid = getmapping(ctx) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
257 if oldnode != ctx.node(): |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
258 # Create or update Differential Revision |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
259 revision = createdifferentialrevision(ctx, revid, lastrevid) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
260 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
|
261 if revid: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
262 action = _('updated') |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
263 else: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
264 action = _('created') |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
265 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
266 # 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
|
267 tagname = 'D%d' % newrevid |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
268 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
|
269 date=None, local=True) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
270 else: |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
271 # 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
|
272 # could depend on this one. |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
273 newrevid = revid |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
274 action = _('skipped') |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
275 |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
276 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
|
277 ctx.description().split('\n')[0])) |
228ad1e58a85
phabricator: add phabsend command to send a stack
Jun Wu <quark@fb.com>
parents:
33198
diff
changeset
|
278 lastrevid = newrevid |
33200
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
279 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
280 _summaryre = re.compile('^Summary:\s*', re.M) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
281 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
282 def readpatch(repo, params, recursive=False): |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
283 """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
|
284 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
285 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
|
286 dependent patches. |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
287 """ |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
288 # Differential Revisions |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
289 drevs = callconduit(repo, 'differential.query', params) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
290 if len(drevs) == 1: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
291 drev = drevs[0] |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
292 else: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
293 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
|
294 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
295 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
|
296 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
297 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
|
298 body = callconduit(repo, 'differential.getrawdiff', {'diffID': diffid}) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
299 desc = callconduit(repo, 'differential.getcommitmessage', |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
300 {'revision_id': drev[r'id']}) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
301 header = '# HG changeset patch\n' |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
302 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
303 # Remove potential empty "Summary:" |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
304 desc = _summaryre.sub('', desc) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
305 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
306 # 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
|
307 diffs = callconduit(repo, 'differential.querydiffs', {'ids': [diffid]}) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
308 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
|
309 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
|
310 meta = props[r'hg:meta'] |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
311 for k, v in meta.items(): |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
312 header += '# %s %s\n' % (k.capitalize(), v) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
313 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
314 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
|
315 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
316 # Check dependencies |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
317 if recursive: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
318 auxiliary = drev.get(r'auxiliary', {}) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
319 depends = auxiliary.get(r'phabricator:depends-on', []) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
320 for phid in depends: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
321 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
|
322 return patch |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
323 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
324 @command('phabread', |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
325 [('', 'stack', False, _('read dependencies'))], |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
326 _('REVID [OPTIONS]')) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
327 def phabread(ui, repo, revid, **opts): |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
328 """print patches from Phabricator suitable for importing |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
329 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
330 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
|
331 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
|
332 |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
333 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
|
334 """ |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
335 try: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
336 revid = int(revid.split('/')[-1].replace('D', '')) |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
337 except ValueError: |
04cf9927f350
phabricator: add phabread command to read patches
Jun Wu <quark@fb.com>
parents:
33199
diff
changeset
|
338 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
|
339 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
|
340 ui.write(patch) |