##// END OF EJS Templates
declare local constants instead of using magic values and comments
declare local constants instead of using magic values and comments

File last commit:

r16951:bdf8c6c6 merge default
r17429:72fa4ef2 default
Show More
notify.py
382 lines | 13.2 KiB | text/x-python | PythonLexer
Vadim Gelfer
add email notification hook. hook written in python....
r2203 # notify.py - email notifications for mercurial
#
# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Patrick Mezard
notify: rewrite user documentation...
r14940 '''hooks for sending email push notifications
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
David Champion
notify: various fixes to docstring...
r16950 This extension implements hooks to send email notifications when
changesets are sent from or received by the local repository.
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Patrick Mezard
notify: rewrite user documentation...
r14940 First, enable the extension as explained in :hg:`help extensions`, and
FUJIWARA Katsunori
doc: fix careless document miss in help of hgext/notify...
r16500 register the hook you want to run. ``incoming`` and ``changegroup`` hooks
David Champion
notify: various fixes to docstring...
r16950 are run when changesets are received, while ``outgoing`` hooks are for
changesets sent to another repository::
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Martin Geisler
notify: fix indentation in module docstring
r9105 [hooks]
# one email for each incoming changeset
incoming.notify = python:hgext.notify.hook
Patrick Mezard
notify: rewrite user documentation...
r14940 # one email for all incoming changesets
Martin Geisler
notify: fix indentation in module docstring
r9105 changegroup.notify = python:hgext.notify.hook
Patrick Mezard
notify: rewrite user documentation...
r14940
# one email for all outgoing changesets
Ingo Bressler
notify: send changesets on 'outgoing' hook, updated doc
r14617 outgoing.notify = python:hgext.notify.hook
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
David Champion
notify: various fixes to docstring...
r16950 This registers the hooks. To enable notification, subscribers must
be assigned to repositories. The ``[usersubs]`` section maps multiple
repositories to a given recipient. The ``[reposubs]`` section maps
multiple recipients to a single repository::
Martin Geisler
commands: use minirst parser when displaying help
r9157
Martin Geisler
notify: fix indentation in module docstring
r9105 [usersubs]
David Champion
notify: various fixes to docstring...
r16950 # key is subscriber email, value is a comma-separated list of repo glob
Patrick Mezard
notify: rewrite user documentation...
r14940 # patterns
Martin Geisler
notify: fix indentation in module docstring
r9105 user@host = pattern
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Martin Geisler
notify: fix indentation in module docstring
r9105 [reposubs]
Patrick Mezard
notify: rewrite user documentation...
r14940 # key is glob pattern, value is a comma-separated list of subscriber
# emails
Martin Geisler
notify: fix indentation in module docstring
r9105 pattern = user@host
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Patrick Mezard
notify: rewrite user documentation...
r14940 Glob patterns are matched against absolute path to repository
David Champion
notify: various fixes to docstring...
r16950 root.
In order to place them under direct user management, ``[usersubs]`` and
``[reposubs]`` sections may be placed in a separate ``hgrc`` file and
incorporated by reference::
Patrick Mezard
notify: rewrite user documentation...
r14940
[notify]
config = /path/to/subscriptionsfile
David Champion
notify: various fixes to docstring...
r16950 Notifications will not be sent until the ``notify.test`` value is set
to ``False``; see below.
Patrick Mezard
notify: rewrite user documentation...
r14940
Notifications content can be tweaked with the following configuration entries:
notify.test
If ``True``, print messages to stdout instead of sending them. Default: True.
notify.sources
David Champion
notify: various fixes to docstring...
r16950 Space-separated list of change sources. Notifications are activated only
when a changeset's source is in this list. Sources may be:
:``serve``: changesets received via http or ssh
:``pull``: changesets received via ``hg pull``
:``unbundle``: changesets received via ``hg unbundle``
:``push``: changesets sent or received via ``hg push``
:``bundle``: changesets sent via ``hg unbundle``
Default: serve.
Patrick Mezard
notify: rewrite user documentation...
r14940
notify.strip
Number of leading slashes to strip from url paths. By default, notifications
David Champion
notify: various fixes to docstring...
r16950 reference repositories with their absolute path. ``notify.strip`` lets you
Patrick Mezard
notify: rewrite user documentation...
r14940 turn them into relative paths. For example, ``notify.strip=3`` will change
``/long/path/repository`` into ``repository``. Default: 0.
notify.domain
David Champion
notify: various fixes to docstring...
r16950 Default email domain for sender or recipients with no explicit domain.
Dirkjan Ochtman
help: better documentation intro for a few extensions
r7127
Patrick Mezard
notify: rewrite user documentation...
r14940 notify.style
Style file to use when formatting emails.
notify.template
Template to use when formatting emails.
notify.incoming
David Champion
notify: various fixes to docstring...
r16950 Template to use when run as an incoming hook, overriding ``notify.template``.
Patrick Mezard
notify: rewrite user documentation...
r14940
notify.outgoing
David Champion
notify: various fixes to docstring...
r16950 Template to use when run as an outgoing hook, overriding ``notify.template``.
Patrick Mezard
notify: rewrite user documentation...
r14940
notify.changegroup
David Champion
notify: various fixes to docstring...
r16950 Template to use when running as a changegroup hook, overriding
Patrick Mezard
notify: rewrite user documentation...
r14940 ``notify.template``.
notify.maxdiff
Maximum number of diff lines to include in notification email. Set to 0
David Champion
notify: various fixes to docstring...
r16950 to disable the diff, or -1 to include all of it. Default: 300.
Patrick Mezard
notify: rewrite user documentation...
r14940
notify.maxsubject
David Champion
notify: various fixes to docstring...
r16950 Maximum number of characters in email's subject line. Default: 67.
Patrick Mezard
notify: rewrite user documentation...
r14940
notify.diffstat
Set to True to include a diffstat before diff content. Default: True.
notify.merge
If True, send notifications for merge changesets. Default: True.
Mads Kiilerich
notify: add option for writing to mbox...
r15561 notify.mbox
If set, append mails to this mbox file instead of sending. Default: None.
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654 notify.fromauthor
David Champion
notify: various fixes to docstring...
r16950 If set, use the committer of the first changeset in a changegroup for
the "From" field of the notification mail. If not set, take the user
from the pushing repo. Default: False.
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654
David Champion
notify: various fixes to docstring...
r16950 If set, the following entries will also be used to customize the
notifications:
Patrick Mezard
notify: rewrite user documentation...
r14940
email.from
David Champion
notify: various fixes to docstring...
r16950 Email ``From`` address to use if none can be found in the generated
email content.
Patrick Mezard
notify: rewrite user documentation...
r14940
web.baseurl
David Champion
notify: various fixes to docstring...
r16950 Root repository URL to combine with repository paths when making
Patrick Mezard
notify: rewrite user documentation...
r14940 references. See also ``notify.strip``.
Martin Geisler
notify: wrapped docstrings at 78 characters
r9068 '''
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Matt Mackall
Simplify i18n imports
r3891 from mercurial.i18n import _
Matt Mackall
Replace demandload with new demandimport
r3877 from mercurial import patch, cmdutil, templater, util, mail
Christian Ebert
notify: do not mime encode multipart templates...
r9313 import email.Parser, email.Errors, fnmatch, socket, time
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Augie Fackler
hgext: mark all first-party extensions as such
r16743 testedwith = 'internal'
Vadim Gelfer
add email notification hook. hook written in python....
r2203 # template for single changeset can include email headers.
single_template = '''
Subject: changeset in {webroot}: {desc|firstline|strip}
From: {author}
changeset {node|short} in {root}
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
description:
\t{desc|tabindent|strip}
'''.lstrip()
# template for multiple changesets should not contain email headers,
# because only first set of headers will be used and result will look
# strange.
multiple_template = '''
changeset {node|short} in {root}
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
summary: {desc|firstline}
'''
deftemplates = {
'changegroup': multiple_template,
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 }
Bryan O'Sullivan
patch queue: notify.patch
r2201
class notifier(object):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''email notification class.'''
def __init__(self, ui, repo, hooktype):
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.ui = ui
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 cfg = self.ui.config('notify', 'config')
if cfg:
Matt Mackall
ui: fold readsections into readconfig...
r8142 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.repo = repo
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.stripcount = int(self.ui.config('notify', 'strip', 0))
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.root = self.strip(self.repo.root)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.domain = self.ui.config('notify', 'domain')
Mads Kiilerich
notify: add option for writing to mbox...
r15561 self.mbox = self.ui.config('notify', 'mbox')
Christian Ebert
notify: no charset conversion when testing...
r7498 self.test = self.ui.configbool('notify', 'test', True)
Christian Ebert
notify: mime-encode messages...
r7116 self.charsets = mail._charsets(self.ui)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.subs = self.subscribers()
David Champion
notify: permit suppression of merge changeset notification...
r9516 self.merge = self.ui.configbool('notify', 'merge', True)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
mapfile = self.ui.config('notify', 'style')
template = (self.ui.config('notify', hooktype) or
self.ui.config('notify', 'template'))
Matt Mackall
fix notify with new ui buffering
r3739 self.t = cmdutil.changeset_templater(self.ui, self.repo,
Jim Correia
add --git option to commands supporting --patch (log, incoming, history, tip)...
r7762 False, None, mapfile, False)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if not mapfile and not template:
template = deftemplates.get(hooktype) or single_template
if template:
template = templater.parsestring(template, quoted=False)
self.t.use_template(template)
Bryan O'Sullivan
patch queue: notify.patch
r2201
def strip(self, path):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''strip leading slashes from local path, turn into web-safe path.'''
Bryan O'Sullivan
patch queue: notify.patch
r2201 path = util.pconvert(path)
count = self.stripcount
Vadim Gelfer
notify: fix off by one error.
r2326 while count > 0:
Bryan O'Sullivan
patch queue: notify.patch
r2201 c = path.find('/')
if c == -1:
break
Matt Mackall
many, many trivial check-code fixups
r10282 path = path[c + 1:]
Bryan O'Sullivan
patch queue: notify.patch
r2201 count -= 1
return path
Vadim Gelfer
add email notification hook. hook written in python....
r2203 def fixmail(self, addr):
'''try to clean up email addresses.'''
Matt Mackall
templater: move email function to util
r5975 addr = util.email(addr.strip())
Alexis S. L. Carvalho
notify: don't try to fix addresses if notify.domain is not set
r4094 if self.domain:
a = addr.find('@localhost')
if a != -1:
addr = addr[:a]
if '@' not in addr:
return addr + '@' + self.domain
Vadim Gelfer
add email notification hook. hook written in python....
r2203 return addr
Bryan O'Sullivan
patch queue: notify.patch
r2201 def subscribers(self):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''return list of email addresses of subscribers to this repo.'''
Martin Geisler
notify: turned a set-like dict into a real set
r8154 subs = set()
Vadim Gelfer
add email notification hook. hook written in python....
r2203 for user, pats in self.ui.configitems('usersubs'):
for pat in pats.split(','):
if fnmatch.fnmatch(self.repo.root, pat.strip()):
Martin Geisler
notify: turned a set-like dict into a real set
r8154 subs.add(self.fixmail(user))
Bryan O'Sullivan
patch queue: notify.patch
r2201 for pat, users in self.ui.configitems('reposubs'):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if fnmatch.fnmatch(self.repo.root, pat):
for user in users.split(','):
Martin Geisler
notify: turned a set-like dict into a real set
r8154 subs.add(self.fixmail(user))
Christian Ebert
notify: no charset conversion when testing...
r7498 return [mail.addressencode(self.ui, s, self.charsets, self.test)
Martin Geisler
notify: turned a set-like dict into a real set
r8154 for s in sorted(subs)]
Bryan O'Sullivan
patch queue: notify.patch
r2201
Bryan O'Sullivan
notify: make it possible to pass extra info into templates
r9486 def node(self, ctx, **props):
David Champion
notify: permit suppression of merge changeset notification...
r9516 '''format one changeset, unless it is a suppressed merge.'''
if not self.merge and len(ctx.parents()) > 1:
return False
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 self.t.show(ctx, changes=ctx.changeset(),
Vadim Gelfer
add email notification hook. hook written in python....
r2203 baseurl=self.ui.config('web', 'baseurl'),
Bryan O'Sullivan
notify: make it possible to pass extra info into templates
r9486 root=self.repo.root, webroot=self.root, **props)
David Champion
notify: permit suppression of merge changeset notification...
r9516 return True
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 def skipsource(self, source):
'''true if incoming changes from this source should be skipped.'''
ok_sources = self.ui.config('notify', 'sources', 'serve').split()
return source not in ok_sources
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 def send(self, ctx, count, data):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''send message.'''
p = email.Parser.Parser()
Christian Ebert
notify: do not mime encode multipart templates...
r9313 try:
msg = p.parsestr(data)
except email.Errors.MessageParseError, inst:
raise util.Abort(inst)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Christian Ebert
notify: mime-encode messages...
r7116 # store sender and subject
sender, subject = msg['From'], msg['Subject']
Christian Ebert
notify: fix neglect of custom headers set via template...
r7658 del msg['From'], msg['Subject']
Christian Ebert
notify: do not mime encode multipart templates...
r9313
if not msg.is_multipart():
# create fresh mime message from scratch
# (multipart templates must take care of this themselves)
headers = msg.items()
payload = msg.get_payload()
# for notification prefer readability over data precision
msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
# reinstate custom headers
for k, v in headers:
msg[k] = v
Christian Ebert
notify: mime-encode messages...
r7116
Christian Ebert
notify: remove subfunctions that are called only once
r7705 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Christian Ebert
notify: remove subfunctions that are called only once
r7705 # try to make subject line exist and be useful
if not subject:
if count > 1:
subject = _('%s: %d new changesets') % (self.root, count)
else:
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
Christian Ebert
notify: remove subfunctions that are called only once
r7705 subject = '%s: %s' % (self.root, s)
maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
Yuya Nishihara
notify: use util.ellipsis() to truncate long subject
r13202 if maxsubject:
subject = util.ellipsis(subject, maxsubject)
Christian Ebert
notify: remove subfunctions that are called only once
r7705 msg['Subject'] = mail.headencode(self.ui, subject,
self.charsets, self.test)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Christian Ebert
notify: remove subfunctions that are called only once
r7705 # try to make message have proper sender
if not sender:
sender = self.ui.config('email', 'from') or self.ui.username()
if '@' not in sender or '@localhost' in sender:
sender = self.fixmail(sender)
msg['From'] = mail.addressencode(self.ui, sender,
self.charsets, self.test)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 msg['X-Hg-Notification'] = 'changeset %s' % ctx
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if not msg['Message-Id']:
msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 (ctx, int(time.time()),
Vadim Gelfer
add email notification hook. hook written in python....
r2203 hash(self.repo.root), socket.getfqdn()))
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 msg['To'] = ', '.join(self.subs)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Nicolas Dumazet
for calls expecting bool args, pass bool instead of int...
r9136 msgtext = msg.as_string()
Christian Ebert
notify: no charset conversion when testing...
r7498 if self.test:
Vadim Gelfer
add email notification hook. hook written in python....
r2203 self.ui.write(msgtext)
if not msgtext.endswith('\n'):
self.ui.write('\n')
Bryan O'Sullivan
patch queue: notify.patch
r2201 else:
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 (len(self.subs), count))
Matt Mackall
templater: move email function to util
r5975 mail.sendmail(self.ui, util.email(msg['From']),
Mads Kiilerich
notify: add option for writing to mbox...
r15561 self.subs, msgtext, mbox=self.mbox)
Bryan O'Sullivan
patch queue: notify.patch
r2201
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 def diff(self, ctx, ref=None):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 prev = ctx.p1().node()
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 ref = ref and ref.node() or ctx.node()
Dirkjan Ochtman
patch: turn patch.diff() into a generator...
r7308 chunks = patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui))
difflines = ''.join(chunks).splitlines()
divy@chelsio.com
notify: fix diffstat printing...
r6979
Matt Doar
Add support for diffstat in commit emails, and move diffstat from...
r3096 if self.ui.configbool('notify', 'diffstat', True):
s = patch.diffstat(difflines)
Sean Dague
Prevent type exception on concatenation if diffstat returns None....
r4077 # s may be nil, don't include the header if it is
if s:
self.ui.write('\ndiffstat:\n\n%s' % s)
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
Benoît Allard
notify: print diffstat even if maxline == 0
r6305 if maxdiff == 0:
return
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 elif maxdiff > 0 and len(difflines) > maxdiff:
msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
self.ui.write(msg % (len(difflines), maxdiff))
Vadim Gelfer
add email notification hook. hook written in python....
r2203 difflines = difflines[:maxdiff]
elif difflines:
Matt Mackall
fix notify with new ui buffering
r3739 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
divy@chelsio.com
notify: fix diffstat printing...
r6979 self.ui.write("\n".join(difflines))
Bryan O'Sullivan
patch queue: notify.patch
r2201
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
Vadim Gelfer
add email notification hook. hook written in python....
r2203 '''send email notifications to interested subscribers.
if used as changegroup hook, send one email for all changesets in
changegroup. else send one email per changeset.'''
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
Vadim Gelfer
add email notification hook. hook written in python....
r2203 n = notifier(ui, repo, hooktype)
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 ctx = repo[node]
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 if not n.subs:
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('notify: no subscribers to repository %s\n' % n.root)
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 return
if n.skipsource(source):
Martin Geisler
do not attempt to translate ui.debug output
r9467 ui.debug('notify: changes have source "%s" - skipping\n' % source)
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 return
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
Matt Mackall
fix notify with new ui buffering
r3739 ui.pushbuffer()
David Champion
notify: permit suppression of merge changeset notification...
r9516 data = ''
count = 0
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654 author = ''
Ingo Bressler
notify: send changesets on 'outgoing' hook, updated doc
r14617 if hooktype == 'changegroup' or hooktype == 'outgoing':
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 start, end = ctx.rev(), len(repo)
Vadim Gelfer
add email notification hook. hook written in python....
r2203 for rev in xrange(start, end):
David Champion
notify: permit suppression of merge changeset notification...
r9516 if n.node(repo[rev]):
count += 1
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654 if not author:
author = repo[rev].user()
David Champion
notify: permit suppression of merge changeset notification...
r9516 else:
data += ui.popbuffer()
Brodie Rao
cleanup: eradicate long lines
r16683 ui.note(_('notify: suppressing notification for merge %d:%s\n')
% (rev, repo[rev].hex()[:12]))
David Champion
notify: permit suppression of merge changeset notification...
r9516 ui.pushbuffer()
if count:
n.diff(ctx, repo['tip'])
Vadim Gelfer
add email notification hook. hook written in python....
r2203 else:
David Champion
notify: permit suppression of merge changeset notification...
r9516 if not n.node(ctx):
ui.popbuffer()
ui.note(_('notify: suppressing notification for merge %d:%s\n') %
(ctx.rev(), ctx.hex()[:12]))
return
count += 1
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 n.diff(ctx)
David Champion
notify: permit suppression of merge changeset notification...
r9516 data += ui.popbuffer()
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654 fromauthor = ui.config('notify', 'fromauthor')
if author and fromauthor:
data = '\n'.join(['From: %s' % author, data])
David Champion
notify: permit suppression of merge changeset notification...
r9516 if count:
n.send(ctx, count, data)