# HG changeset patch # User Michal Sznajder # Date 1344890530 -7200 # Node ID 19e9bf7c0927714b6a6a58795f4a989bb5f2df60 # Parent 69d5078d760decd9779c91095844b3d44c46475c notify: support revset selection for subscriptions A repo pattern for any notify configuration contains a glob matching the path to the repo. Additionally, it may now contain a revset spec, separated from the glob by '#'. Example: [reposubs] */widgets#branch(release) = qa-team@example.com This sends to ``qa-team@example.com`` whenever a changeset on the ``release`` branch triggers a notification in any repository ending in ``widgets``. This patch was completely done by David Champion with me making tiny changes to his tests. diff -r 69d5078d760d -r 19e9bf7c0927 hgext/notify.py --- a/hgext/notify.py Mon Aug 13 21:50:45 2012 +0200 +++ b/hgext/notify.py Mon Aug 13 22:42:10 2012 +0200 @@ -30,17 +30,22 @@ multiple recipients to a single repository:: [usersubs] - # key is subscriber email, value is a comma-separated list of repo glob - # patterns + # key is subscriber email, value is a comma-separated list of repo patterns user@host = pattern [reposubs] - # key is glob pattern, value is a comma-separated list of subscriber - # emails + # key is repo pattern, value is a comma-separated list of subscriber emails pattern = user@host -Glob patterns are matched against absolute path to repository -root. +A ``pattern`` is a ``glob`` matching the absolute path to a repository, +optionally combined with a revset expression. A revset expression, if +present, is separated from the glob by a hash. Example:: + + [reposubs] + */widgets#branch(release) = qa-team@example.com + +This sends to ``qa-team@example.com`` whenever a changeset on the ``release`` +branch triggers a notification in any repository ending in ``widgets``. In order to place them under direct user management, ``[usersubs]`` and ``[reposubs]`` sections may be placed in a separate ``hgrc`` file and @@ -217,14 +222,22 @@ subs = set() for user, pats in self.ui.configitems('usersubs'): for pat in pats.split(','): + if '#' in pat: + pat, revs = pat.split('#', 1) + else: + revs = None if fnmatch.fnmatch(self.repo.root, pat.strip()): - subs.add(self.fixmail(user)) + subs.add((self.fixmail(user), revs)) for pat, users in self.ui.configitems('reposubs'): + if '#' in pat: + pat, revs = pat.split('#', 1) + else: + revs = None if fnmatch.fnmatch(self.repo.root, pat): for user in users.split(','): - subs.add(self.fixmail(user)) - return [mail.addressencode(self.ui, s, self.charsets, self.test) - for s in sorted(subs)] + subs.add((self.fixmail(user), revs)) + return [(mail.addressencode(self.ui, s, self.charsets, self.test), r) + for s, r in sorted(subs)] def node(self, ctx, **props): '''format one changeset, unless it is a suppressed merge.''' @@ -243,6 +256,21 @@ def send(self, ctx, count, data): '''send message.''' + # Select subscribers by revset + subs = set() + for sub, spec in self.subs: + if spec is None: + subs.add(sub) + continue + revs = self.repo.revs('%r and %d:', spec, ctx.rev()) + if len(revs): + subs.add(sub) + continue + if len(subs) == 0: + self.ui.debug('notify: no subscribers to selected repo ' + 'and revset\n') + return + p = email.Parser.Parser() try: msg = p.parsestr(data) @@ -292,7 +320,7 @@ msg['Message-Id'] = ('' % (ctx, int(time.time()), hash(self.repo.root), socket.getfqdn())) - msg['To'] = ', '.join(self.subs) + msg['To'] = ', '.join(sorted(subs)) msgtext = msg.as_string() if self.test: @@ -301,9 +329,9 @@ self.ui.write('\n') else: self.ui.status(_('notify: sending %d subscribers %d changes\n') % - (len(self.subs), count)) + (len(subs), count)) mail.sendmail(self.ui, util.email(msg['From']), - self.subs, msgtext, mbox=self.mbox) + subs, msgtext, mbox=self.mbox) def diff(self, ctx, ref=None): diff -r 69d5078d760d -r 19e9bf7c0927 tests/test-notify.t --- a/tests/test-notify.t Mon Aug 13 21:50:45 2012 +0200 +++ b/tests/test-notify.t Mon Aug 13 22:42:10 2012 +0200 @@ -42,16 +42,22 @@ repository: [usersubs] - # key is subscriber email, value is a comma-separated list of repo glob - # patterns + # key is subscriber email, value is a comma-separated list of repo patterns user@host = pattern [reposubs] - # key is glob pattern, value is a comma-separated list of subscriber - # emails + # key is repo pattern, value is a comma-separated list of subscriber emails pattern = user@host - Glob patterns are matched against absolute path to repository root. + A "pattern" is a "glob" matching the absolute path to a repository, optionally + combined with a revset expression. A revset expression, if present, is + separated from the glob by a hash. Example: + + [reposubs] + */widgets#branch(release) = qa-team@example.com + + This sends to "qa-team@example.com" whenever a changeset on the "release" + branch triggers a notification in any repository ending in "widgets". In order to place them under direct user management, "[usersubs]" and "[reposubs]" sections may be placed in a separate "hgrc" file and incorporated @@ -473,3 +479,77 @@ ononononononononononononononononononononononononononononononononononononono= nonononononononononononono + revset selection: send to address that matches branch and repo + + $ cat << EOF >> $HGRCPATH + > [hooks] + > incoming.notify = python:hgext.notify.hook + > + > [notify] + > sources = pull + > test = True + > diffstat = False + > maxdiff = 0 + > + > [reposubs] + > */a#branch(test) = will_no_be_send@example.com + > */b#branch(test) = notify@example.com + > EOF + $ hg --cwd a branch test + marked working directory as branch test + (branches are permanent and global, did you want a bookmark?) + $ echo a >> a/a + $ hg --cwd a ci -m test -d '1 0' + $ hg --traceback --cwd b pull ../a | \ + > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),' + pulling from ../a + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + X-Test: foo + Date: * (glob) + Subject: test + From: test@test.com + X-Hg-Notification: changeset fbbcbc516f2f + Message-Id: (glob) + To: baz@test.com, foo@bar, notify@example.com + + changeset fbbcbc516f2f in b + description: test + (run 'hg update' to get a working copy) + +revset selection: don't send to address that waits for mails +from different branch + + $ hg --cwd a update default + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + $ echo a >> a/a + $ hg --cwd a ci -m test -d '1 0' + $ hg --traceback --cwd b pull ../a | \ + > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),' + pulling from ../a + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 0 changes to 0 files (+1 heads) + Content-Type: text/plain; charset="us-ascii" + MIME-Version: 1.0 + Content-Transfer-Encoding: 7bit + X-Test: foo + Date: * (glob) + Subject: test + From: test@test.com + X-Hg-Notification: changeset 38b42fa092de + Message-Id: (glob) + To: baz@test.com, foo@bar + + changeset 38b42fa092de in b + description: test + (run 'hg heads' to see heads) +