Mercurial > public > mercurial-scm > hg-stable
comparison contrib/phabricator.py @ 33498:b7a75b9a3386
phabricator: allow specifying reviewers on phabsend
Sometimes people want to specify reviewer explicitly for a stack. The
webpage only allows changing reviewer for one revision at a time. This patch
adds a `--reviewer` flag to make it easier to specify reviewers.
Test Plan:
On a test Phabricator instance, enable `differential.allow-self-accept`,
assign myself as a reviewer and make sure it works. Also try an invalid
username and make sure it raises.
Differential Revision: https://phab.mercurial-scm.org/D38
author | Jun Wu <quark@fb.com> |
---|---|
date | Tue, 11 Jul 2017 08:52:55 -0700 |
parents | e48082e0a8d5 |
children | 91e3dcefc9b7 |
comparison
equal
deleted
inserted
replaced
33497:80e1331a7fe9 | 33498:b7a75b9a3386 |
---|---|
234 'parent': ctx.p1().hex(), | 234 'parent': ctx.p1().hex(), |
235 }), | 235 }), |
236 } | 236 } |
237 callconduit(ctx.repo(), 'differential.setdiffproperty', params) | 237 callconduit(ctx.repo(), 'differential.setdiffproperty', params) |
238 | 238 |
239 def createdifferentialrevision(ctx, revid=None, parentrevid=None, oldnode=None): | 239 def createdifferentialrevision(ctx, revid=None, parentrevid=None, oldnode=None, |
240 actions=None): | |
240 """create or update a Differential Revision | 241 """create or update a Differential Revision |
241 | 242 |
242 If revid is None, create a new Differential Revision, otherwise update | 243 If revid is None, create a new Differential Revision, otherwise update |
243 revid. If parentrevid is not None, set it as a dependency. | 244 revid. If parentrevid is not None, set it as a dependency. |
244 | 245 |
245 If oldnode is not None, check if the patch content (without commit message | 246 If oldnode is not None, check if the patch content (without commit message |
246 and metadata) has changed before creating another diff. | 247 and metadata) has changed before creating another diff. |
248 | |
249 If actions is not None, they will be appended to the transaction. | |
247 """ | 250 """ |
248 repo = ctx.repo() | 251 repo = ctx.repo() |
249 if oldnode: | 252 if oldnode: |
250 diffopts = mdiff.diffopts(git=True, context=1) | 253 diffopts = mdiff.diffopts(git=True, context=1) |
251 oldctx = repo.unfiltered()[oldnode] | 254 oldctx = repo.unfiltered()[oldnode] |
266 if parentrevid and revid is None: | 269 if parentrevid and revid is None: |
267 summary = 'Depends on D%s' % parentrevid | 270 summary = 'Depends on D%s' % parentrevid |
268 transactions += [{'type': 'summary', 'value': summary}, | 271 transactions += [{'type': 'summary', 'value': summary}, |
269 {'type': 'summary', 'value': ' '}] | 272 {'type': 'summary', 'value': ' '}] |
270 | 273 |
274 if actions: | |
275 transactions += actions | |
276 | |
271 # Parse commit message and update related fields. | 277 # Parse commit message and update related fields. |
272 desc = ctx.description() | 278 desc = ctx.description() |
273 info = callconduit(repo, 'differential.parsecommitmessage', | 279 info = callconduit(repo, 'differential.parsecommitmessage', |
274 {'corpus': desc}) | 280 {'corpus': desc}) |
275 for k, v in info[r'fields'].items(): | 281 for k, v in info[r'fields'].items(): |
285 if not revision: | 291 if not revision: |
286 raise error.Abort(_('cannot create revision for %s') % ctx) | 292 raise error.Abort(_('cannot create revision for %s') % ctx) |
287 | 293 |
288 return revision | 294 return revision |
289 | 295 |
296 def userphids(repo, names): | |
297 """convert user names to PHIDs""" | |
298 query = {'constraints': {'usernames': names}} | |
299 result = callconduit(repo, 'user.search', query) | |
300 # username not found is not an error of the API. So check if we have missed | |
301 # some names here. | |
302 data = result[r'data'] | |
303 resolved = set(entry[r'fields'][r'username'] for entry in data) | |
304 unresolved = set(names) - resolved | |
305 if unresolved: | |
306 raise error.Abort(_('unknown username: %s') | |
307 % ' '.join(sorted(unresolved))) | |
308 return [entry[r'phid'] for entry in data] | |
309 | |
290 @command('phabsend', | 310 @command('phabsend', |
291 [('r', 'rev', [], _('revisions to send'), _('REV'))], | 311 [('r', 'rev', [], _('revisions to send'), _('REV')), |
312 ('', 'reviewer', [], _('specify reviewers'))], | |
292 _('REV [OPTIONS]')) | 313 _('REV [OPTIONS]')) |
293 def phabsend(ui, repo, *revs, **opts): | 314 def phabsend(ui, repo, *revs, **opts): |
294 """upload changesets to Phabricator | 315 """upload changesets to Phabricator |
295 | 316 |
296 If there are multiple revisions specified, they will be send as a stack | 317 If there are multiple revisions specified, they will be send as a stack |
305 revs = list(revs) + opts.get('rev', []) | 326 revs = list(revs) + opts.get('rev', []) |
306 revs = scmutil.revrange(repo, revs) | 327 revs = scmutil.revrange(repo, revs) |
307 | 328 |
308 if not revs: | 329 if not revs: |
309 raise error.Abort(_('phabsend requires at least one changeset')) | 330 raise error.Abort(_('phabsend requires at least one changeset')) |
331 | |
332 actions = [] | |
333 reviewers = opts.get('reviewer', []) | |
334 if reviewers: | |
335 phids = userphids(repo, reviewers) | |
336 actions.append({'type': 'reviewers.add', 'value': phids}) | |
310 | 337 |
311 oldnodedrev = getoldnodedrevmap(repo, [repo[r].node() for r in revs]) | 338 oldnodedrev = getoldnodedrevmap(repo, [repo[r].node() for r in revs]) |
312 | 339 |
313 # Send patches one by one so we know their Differential Revision IDs and | 340 # Send patches one by one so we know their Differential Revision IDs and |
314 # can provide dependency relationship | 341 # can provide dependency relationship |
320 # Get Differential Revision ID | 347 # Get Differential Revision ID |
321 oldnode, revid = oldnodedrev.get(ctx.node(), (None, None)) | 348 oldnode, revid = oldnodedrev.get(ctx.node(), (None, None)) |
322 if oldnode != ctx.node(): | 349 if oldnode != ctx.node(): |
323 # Create or update Differential Revision | 350 # Create or update Differential Revision |
324 revision = createdifferentialrevision(ctx, revid, lastrevid, | 351 revision = createdifferentialrevision(ctx, revid, lastrevid, |
325 oldnode) | 352 oldnode, actions) |
326 newrevid = int(revision[r'object'][r'id']) | 353 newrevid = int(revision[r'object'][r'id']) |
327 if revid: | 354 if revid: |
328 action = _('updated') | 355 action = _('updated') |
329 else: | 356 else: |
330 action = _('created') | 357 action = _('created') |