[PATCH 3 of 3 v2] patchbomb: add support for a file that configures default To and CC
Augie Fackler
raf at durin42.com
Wed Jun 14 23:16:34 EDT 2017
# HG changeset patch
# User Augie Fackler <augie at google.com>
# Date 1497387366 14400
# Tue Jun 13 16:56:06 2017 -0400
# Node ID 5b5570529e237d1fd70ef3e6ba80739bd51a9d52
# Parent 85fa6c9f000f374bebd40c401e4d0945d2194e1f
patchbomb: add support for a file that configures default To and CC
This lets repositories configure a shorthand (I used devel in the
tests, but you could do anything) for their project list, and also
supports fileset-based "subscriptions" so that people can request
being CC'ed on certain changes by default.
diff --git a/hgext/patchbomb.py b/hgext/patchbomb.py
--- a/hgext/patchbomb.py
+++ b/hgext/patchbomb.py
@@ -75,6 +75,7 @@ from __future__ import absolute_import
import email as emailmod
import errno
+import itertools
import os
import socket
import tempfile
@@ -83,6 +84,7 @@ from mercurial.i18n import _
from mercurial import (
cmdutil,
commands,
+ config,
error,
formatter,
hg,
@@ -641,7 +643,7 @@ def email(ui, repo, *revs, **opts):
showaddrs = []
- def getaddrs(header, ask=False, default=None):
+ def getaddrs(header, ask=False, trustdefault=True, default=None):
configkey = header.lower()
opt = header.replace('-', '_').lower()
addrs = opts.get(opt)
@@ -655,7 +657,7 @@ def email(ui, repo, *revs, **opts):
if not addr:
specified = (ui.hasconfig('email', configkey) or
ui.hasconfig('patchbomb', configkey))
- if not specified and ask:
+ if (not trustdefault or not specified) and ask:
addr = prompt(ui, header, default=default)
if addr:
showaddrs.append('%s: %s' % (header, addr))
@@ -665,11 +667,63 @@ def email(ui, repo, *revs, **opts):
ui, [default], _charsets, opts.get('test'))
return []
- to = getaddrs('To', ask=True)
+ todefault = set()
+ ccdefault = set(opts['cc'])
+ tocctrustdefault = True
+ if opts['to'] and repo.wvfs.exists('.hgemaildefaults'):
+ mailconf = config.config()
+ confpath = repo.wvfs.join('.hgemaildefaults')
+ with repo.wvfs('.hgemaildefaults') as fp:
+ mailconf.parse(confpath, fp.read())
+ for toflag in opts['to']:
+ # @ is unsupported in destination configs to avoid
+ # collisions with routable email addresses.
+ if '@' in toflag or toflag not in mailconf:
+ todefault.add(toflag)
+ continue
+ todefault.add(mailconf.get(toflag, 'to', None))
+ ccdefault.add(mailconf.get(toflag, 'cc', None))
+ # Find all the config entries in our current section,
+ # minus reserved entries...
+ subents = ((k, v) for k, v in mailconf.items(toflag)
+ if k not in ('cc', 'to', 'bcc'))
+ # Group them by the part before the :
+ grouped = itertools.groupby(
+ subents, key=lambda s: s[0].split(':')[0])
+ # Now we coalesce it all down to a dict of dicts
+ subs = {subsec:
+ {key[len(subsec) + 1:]: value for key, value in values}
+ for subsec, values in grouped}
+ for r in revs:
+ ctx = repo[r]
+ mod = set(ctx.getfileset('modified() or added() or removed()'))
+ for name, sub in subs.iteritems():
+ match = False
+ if 'files' in sub:
+ match = bool(
+ mod.intersection(ctx.match(sub['files'])))
+ if match:
+ wantcc = sub.get('cc', '')
+ ui.debug('subscription %s matched, adding cc: %s\n'
+ % (name, wantcc))
+ ccdefault.update(config.parselist(wantcc))
+ todefault = {t for t in todefault if t is not None}
+ ccdefault = {t for t in ccdefault if t is not None}
+ # We've already handled the flags, so null the flag out. This
+ # also means the user will be prompted for an address, which
+ # is what we want, since the configuration can change as part
+ # of an `hg pull --update` or similar.
+ opts['to'] = []
+ opts['cc'] = []
+ tocctrustdefault = False
+
+ to = getaddrs('To', ask=True, default=', '.join(sorted(todefault)),
+ trustdefault=tocctrustdefault)
if not to:
# we can get here in non-interactive mode
raise error.Abort(_('no recipient addresses provided'))
- cc = getaddrs('Cc', ask=True, default='')
+ cc = getaddrs('Cc', ask=True, default=', '.join(sorted(ccdefault)),
+ trustdefault=tocctrustdefault)
bcc = getaddrs('Bcc')
replyto = getaddrs('Reply-To')
diff --git a/tests/test-patchbomb.t b/tests/test-patchbomb.t
--- a/tests/test-patchbomb.t
+++ b/tests/test-patchbomb.t
@@ -85,9 +85,9 @@ email.to config setting. Same for --cc:
X-Mercurial-Node: 8580ff50825a50c8f716709acdf8de0deddcd6ab
X-Mercurial-Series-Index: 1
X-Mercurial-Series-Total: 1
- Message-Id: <8580ff50825a50c8f716.60 at augie-macbookpro2.roam.corp.google.com>
- X-Mercurial-Series-Id: <8580ff50825a50c8f716.60 at augie-macbookpro2.roam.corp.google.com>
- User-Agent: Mercurial-patchbomb/4.2.1+627-72f2cafb81e3
+ Message-Id: <8580ff50825a50c8f716.*@*> (glob)
+ X-Mercurial-Series-Id: <8580ff50825a50c8f716.*@*> (glob)
+ User-Agent: Mercurial-patchbomb/* (glob)
Date: Thu, 01 Jan 1970 00:01:00 +0000
From: quux
To: foo
@@ -3072,15 +3072,22 @@ Test hg email defaults settings:
$ cat >> .hgemaildefaults <<EOF
> [devel]
> to = mercurial-devel at example.com
- > [devel.setsubscriptions]
- > c or d = c-or-d at example.com
- > a or b = a-or-b at example.com
+ > ab:files = set: a or b
+ > ab:cc = a-or-b at example.com
+ > cd:files = set: c or d
+ > cd:cc = c-or-d at example.com
+ > [foo]
+ > hatebin:files = set: binary()
+ > hatebin:cc = hates-binary-files at example.com
> EOF
-This change modifies file d
- $ hg email --date '1970-1-1 0:2' --to=devel --test -r 10 --config patchbomb.publicurl=
+This change modifies file d. Note that the "foo" to disappears from
+the To line because it has a setsubscription defined above.
+ $ hg email --date '1970-1-1 0:2' --to=devel --to=foo --test -r 10 --config patchbomb.publicurl=
From [test]: test
this patch series consists of 1 patches.
+ To [mercurial-devel at example.com]: mercurial-devel at example.com
+ Cc [c-or-d at example.com]: c-or-d at example.com
displaying [PATCH] dd ...
Content-Type: text/plain; charset="us-ascii"
@@ -3095,7 +3102,8 @@ This change modifies file d
User-Agent: Mercurial-patchbomb/* (glob)
Date: Thu, 01 Jan 1970 00:02:00 +0000
From: test
- To: devel
+ To: mercurial-devel at example.com
+ Cc: c-or-d at example.com
# HG changeset patch
# User test
@@ -3118,6 +3126,8 @@ This change modifies file b
From [test]: test
this patch series consists of 1 patches.
+ To [mercurial-devel at example.com]: mercurial-devel at example.com
+ Cc [a-or-b at example.com]: a-or-b at example.com
displaying [PATCH] b ...
Content-Type: text/plain; charset="us-ascii"
@@ -3132,7 +3142,8 @@ This change modifies file b
User-Agent: Mercurial-patchbomb/* (glob)
Date: Thu, 01 Jan 1970 00:02:00 +0000
From: test
- To: devel
+ To: mercurial-devel at example.com
+ Cc: a-or-b at example.com
# HG changeset patch
# User test
@@ -3154,6 +3165,8 @@ This change modifies file b
this patch series consists of 2 patches.
(optional) Subject: [PATCH 0 of 2]
+ To [mercurial-devel at example.com, specific-person at example.com]: mercurial-devel at example.com, specific-person at example.com
+ Cc [a-or-b at example.com, c-or-d at example.com, this-person-also at example.com]: a-or-b at example.com, c-or-d at example.com, this-person-also at example.com
displaying [PATCH 1 of 2] b ...
Content-Type: text/plain; charset="us-ascii"
@@ -3168,8 +3181,8 @@ This change modifies file b
User-Agent: Mercurial-patchbomb/* (glob)
Date: Thu, 01 Jan 1970 00:02:00 +0000
From: test
- To: devel, specific-person at example.com
- Cc: this-person-also at example.com
+ To: mercurial-devel at example.com, specific-person at example.com
+ Cc: a-or-b at example.com, c-or-d at example.com, this-person-also at example.com
# HG changeset patch
# User test
@@ -3200,8 +3213,8 @@ This change modifies file b
User-Agent: Mercurial-patchbomb/* (glob)
Date: Thu, 01 Jan 1970 00:02:01 +0000
From: test
- To: devel, specific-person at example.com
- Cc: this-person-also at example.com
+ To: mercurial-devel at example.com, specific-person at example.com
+ Cc: a-or-b at example.com, c-or-d at example.com, this-person-also at example.com
# HG changeset patch
# User test
More information about the Mercurial-devel
mailing list