##// END OF EJS Templates
compression: use sysstr to specify attribute to fetch for priority...
compression: use sysstr to specify attribute to fetch for priority These are attributes so they should be `str`.

File last commit:

r50759:5f006f78 default
r51806:93b0de7f default
Show More
notify.py
658 lines | 20.0 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]
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 # key is subscriber email, value is a comma-separated list of repo 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]
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 # key is repo 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
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 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``.
David Champion
notify: various fixes to docstring...
r16950
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.
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 It is also used for the domain part of the ``Message-Id`` when using
``notify.messageidseed``.
notify.messageidseed
Create deterministic ``Message-Id`` headers for the mails based on the seed
and the revision identifier of the first commit in the changeset.
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
Joerg Sonnenberger
notify: add maxdiffstat option to truncate long file lists...
r37795 notify.maxdiffstat
Maximum number of diffstat lines to include in notification email. Set to -1
to include all of it. Default: -1.
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.
Joerg Sonnenberger
notify: add option to include function names in the diff output...
r38048 notify.showfunc
If set, override ``diff.showfunc`` for the diff content. Default: None.
Patrick Mezard
notify: rewrite user documentation...
r14940 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
Joerg Sonnenberger
notify: optional mail threading based on obsmarker...
r45117 notify.reply-to-predecessor (EXPERIMENTAL)
If set and the changeset has a predecessor in the repository, try to thread
the notification mail with the predecessor. This adds the "In-Reply-To" header
to the notification mail with a reference to the predecessor with the smallest
revision number. Mail threads can still be torn, especially when changesets
are folded.
This option must be used in combination with ``notify.messageidseed``.
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
Yuya Nishihara
notify: just use email.errors...
r40326 import email.errors as emailerrors
Denis Laxalde
py3: use stdlib's parseaddr() to get sender header in notify extension...
r43635 import email.utils as emailutils
timeless
notify: use absolute_import
r28416 import fnmatch
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 import hashlib
timeless
notify: use absolute_import
r28416 import socket
import time
Yuya Nishihara
py3: move up symbol imports to enforce import-checker rules...
r29205 from mercurial.i18n import _
timeless
notify: use absolute_import
r28416 from mercurial import (
Augie Fackler
notify: a ton of encoding dancing to deal with the email module...
r40340 encoding,
timeless
notify: use absolute_import
r28416 error,
Yuya Nishihara
cmdutil: drop aliases for logcmdutil functions (API)...
r35906 logcmdutil,
timeless
notify: use absolute_import
r28416 mail,
Joerg Sonnenberger
notify: optional mail threading based on obsmarker...
r45117 obsutil,
timeless
notify: use absolute_import
r28416 patch,
Gregory Szorc
notify: cast hash to bytes...
r43434 pycompat,
Boris Feld
configitems: register the 'notify.config' config
r33738 registrar,
timeless
notify: use absolute_import
r28416 util,
)
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from mercurial.utils import (
dateutil,
stringutil,
)
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Augie Fackler
extensions: change magic "shipped with hg" string...
r29841 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
Augie Fackler
extensions: document that `testedwith = 'internal'` is special...
r25186 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Augie Fackler
hgext: mark all first-party extensions as such
r16743
Boris Feld
configitems: register the 'notify.config' config
r33738 configtable = {}
configitem = registrar.configitem(configtable)
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'changegroup',
default=None,
Boris Feld
configitem: register the 'notify.changegroup' config
r34755 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'config',
default=None,
Boris Feld
configitems: register the 'notify.config' config
r33738 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'diffstat',
default=True,
Boris Feld
configitems: register the 'notify.diffstat' config
r33739 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'domain',
default=None,
Boris Feld
configitems: register the 'notify.domain' config
r33740 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'messageidseed',
default=None,
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'fromauthor',
default=None,
Boris Feld
configitems: register the 'notify.fromauthor' config
r33741 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'incoming',
default=None,
Boris Feld
configitem: register the 'notify.incoming' config
r34753 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'maxdiff',
default=300,
Boris Feld
configitems: register the 'notify.maxdiff' config
r33742 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'maxdiffstat',
default=-1,
Joerg Sonnenberger
notify: add maxdiffstat option to truncate long file lists...
r37795 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'maxsubject',
default=67,
Boris Feld
configitems: register the 'notify.maxsubject' config
r33743 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'mbox',
default=None,
Boris Feld
configitems: register the 'notify.mbox' config
r33744 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'merge',
default=True,
Boris Feld
configitems: register the 'notify.merge' config
r33745 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'outgoing',
default=None,
Boris Feld
configitem: register the 'notify.outgoing' config
r34754 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'reply-to-predecessor',
default=False,
Joerg Sonnenberger
notify: optional mail threading based on obsmarker...
r45117 )
configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'sources',
default=b'serve',
Boris Feld
configitems: register the 'notify.sources' config
r33746 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'showfunc',
default=None,
Joerg Sonnenberger
notify: add option to include function names in the diff output...
r38048 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'strip',
default=0,
Boris Feld
configitems: register the 'notify.strip' config
r33747 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'style',
default=None,
Boris Feld
configitems: register the 'notify.style' config
r33748 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'template',
default=None,
Boris Feld
configitems: register the 'notify.template' config
r33749 )
Augie Fackler
formatting: blacken the codebase...
r43346 configitem(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'notify',
b'test',
default=True,
Boris Feld
configitems: register the 'notify.test' config
r33750 )
Boris Feld
configitems: register the 'notify.config' config
r33738
Vadim Gelfer
add email notification hook. hook written in python....
r2203 # template for single changeset can include email headers.
Augie Fackler
notify: add some b prefixes...
r40319 single_template = b'''
Vadim Gelfer
add email notification hook. hook written in python....
r2203 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.
Augie Fackler
notify: add some b prefixes...
r40319 multiple_template = b'''
Vadim Gelfer
add email notification hook. hook written in python....
r2203 changeset {node|short} in {root}
details: {baseurl}{webroot}?cmd=changeset;node={node|short}
summary: {desc|firstline}
'''
deftemplates = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'changegroup': multiple_template,
Thomas Arendsen Hein
Fixed indentation in hgext/notify.py
r4498 }
Bryan O'Sullivan
patch queue: notify.patch
r2201
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class notifier:
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cfg = self.ui.config(b'notify', b'config')
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 if cfg:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.readconfig(cfg, sections=[b'usersubs', b'reposubs'])
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.repo = repo
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.stripcount = int(self.ui.config(b'notify', b'strip'))
Bryan O'Sullivan
patch queue: notify.patch
r2201 self.root = self.strip(self.repo.root)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.domain = self.ui.config(b'notify', b'domain')
self.mbox = self.ui.config(b'notify', b'mbox')
self.test = self.ui.configbool(b'notify', b'test')
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.merge = self.ui.configbool(b'notify', b'merge')
self.showfunc = self.ui.configbool(b'notify', b'showfunc')
self.messageidseed = self.ui.config(b'notify', b'messageidseed')
Joerg Sonnenberger
notify: optional mail threading based on obsmarker...
r45117 self.reply = self.ui.configbool(b'notify', b'reply-to-predecessor')
if self.reply and not self.messageidseed:
raise error.Abort(
_(
b'notify.reply-to-predecessor used without '
b'notify.messageidseed'
)
)
Joerg Sonnenberger
notify: add option to include function names in the diff output...
r38048 if self.showfunc is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.showfunc = self.ui.configbool(b'diff', b'showfunc')
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Yuya Nishihara
notify: do not load style file if template is specified (BC)...
r28951 mapfile = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 template = self.ui.config(b'notify', hooktype) or self.ui.config(
b'notify', b'template'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
notify: do not load style file if template is specified (BC)...
r28951 if not template:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mapfile = self.ui.config(b'notify', b'style')
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if not mapfile and not template:
template = deftemplates.get(hooktype) or single_template
Yuya Nishihara
cmdutil: drop aliases for logcmdutil functions (API)...
r35906 spec = logcmdutil.templatespec(template, mapfile)
Yuya Nishihara
logcmdutil: drop default arguments from changesetdisplayer/templater() calls
r35972 self.t = logcmdutil.changesettemplater(self.ui, self.repo, spec)
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 c = path.find(b'/')
Bryan O'Sullivan
patch queue: notify.patch
r2201 if c == -1:
break
Augie Fackler
formatting: blacken the codebase...
r43346 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.'''
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 addr = stringutil.email(addr.strip())
Alexis S. L. Carvalho
notify: don't try to fix addresses if notify.domain is not set
r4094 if self.domain:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 a = addr.find(b'@localhost')
Alexis S. L. Carvalho
notify: don't try to fix addresses if notify.domain is not set
r4094 if a != -1:
addr = addr[:a]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'@' not in addr:
return addr + b'@' + 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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for user, pats in self.ui.configitems(b'usersubs'):
for pat in pats.split(b','):
if b'#' in pat:
pat, revs = pat.split(b'#', 1)
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 else:
revs = None
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if fnmatch.fnmatch(self.repo.root, pat.strip()):
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 subs.add((self.fixmail(user), revs))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for pat, users in self.ui.configitems(b'reposubs'):
if b'#' in pat:
pat, revs = pat.split(b'#', 1)
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 else:
revs = None
Vadim Gelfer
add email notification hook. hook written in python....
r2203 if fnmatch.fnmatch(self.repo.root, pat):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 for user in users.split(b','):
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 subs.add((self.fixmail(user), revs))
Augie Fackler
formatting: blacken the codebase...
r43346 return [
(mail.addressencode(self.ui, s, self.charsets, self.test), r)
for s, r 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
Augie Fackler
formatting: blacken the codebase...
r43346 self.t.show(
ctx,
changes=ctx.changeset(),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 baseurl=self.ui.config(b'web', b'baseurl'),
Augie Fackler
formatting: blacken the codebase...
r43346 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.'''
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ok_sources = self.ui.config(b'notify', b'sources').split()
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 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.'''
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 # Select subscribers by revset
subs = set()
for sub, spec in self.subs:
if spec is None:
subs.add(sub)
continue
av6
notify: don't produce errors if a revision is not found...
r49566 try:
revs = self.repo.revs(b'%r and %d:', spec, ctx.rev())
except error.RepoLookupError:
continue
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 if len(revs):
subs.add(sub)
continue
if len(subs) == 0:
Augie Fackler
formatting: blacken the codebase...
r43346 self.ui.debug(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 b'notify: no subscribers to selected repo and revset\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Michal Sznajder
notify: support revset selection for subscriptions...
r17754 return
Christian Ebert
notify: do not mime encode multipart templates...
r9313 try:
Denis Laxalde
py3: use a BytesParser in notify extension...
r43634 msg = mail.parsebytes(data)
Augie Fackler
notify: adapt to new location of email module's errors...
r40320 except emailerrors.MessageParseError as inst:
Matt Harbison
notify: force an exception wrapped by errors.Abort to bytestr...
r50759 raise error.Abort(stringutil.forcebytestr(inst))
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Christian Ebert
notify: mime-encode messages...
r7116 # store sender and subject
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 sender = msg['From']
subject = msg['Subject']
Gregory Szorc
notify: be more defensive aboute None values...
r41449 if sender is not None:
Denis Laxalde
py3: decode email headers with mail.headdecode() in notify extension
r43636 sender = mail.headdecode(sender)
Gregory Szorc
notify: be more defensive aboute None values...
r41449 if subject is not None:
Denis Laxalde
py3: decode email headers with mail.headdecode() in notify extension
r43636 subject = mail.headdecode(subject)
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 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()
Manuel Jacob
py3: constant-fold some `pycompat.ispy3`
r50183 payload = msg.get_payload(decode=True)
Christian Ebert
notify: do not mime encode multipart templates...
r9313 # 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
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 msg['Date'] = encoding.strfromlocal(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 dateutil.datestr(format=b"%a, %d %b %Y %H:%M:%S %1%2")
Augie Fackler
formatting: blacken the codebase...
r43346 )
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 subject = _(b'%s: %d new changesets') % (self.root, count)
Christian Ebert
notify: remove subfunctions that are called only once
r7705 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s = ctx.description().lstrip().split(b'\n', 1)[0].rstrip()
subject = b'%s: %s' % (self.root, s)
maxsubject = int(self.ui.config(b'notify', b'maxsubject'))
Yuya Nishihara
notify: use util.ellipsis() to truncate long subject
r13202 if maxsubject:
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 subject = stringutil.ellipsis(subject, maxsubject)
Denis Laxalde
mail: let headencode() return a native string...
r43975 msg['Subject'] = mail.headencode(
self.ui, subject, self.charsets, self.test
Augie Fackler
formatting: blacken the codebase...
r43346 )
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 sender = self.ui.config(b'email', b'from') or self.ui.username()
if b'@' not in sender or b'@localhost' in sender:
Christian Ebert
notify: remove subfunctions that are called only once
r7705 sender = self.fixmail(sender)
Denis Laxalde
mail: let addressencode() / addrlistencode() return native strings...
r43976 msg['From'] = mail.addressencode(
self.ui, sender, self.charsets, self.test
Augie Fackler
formatting: blacken the codebase...
r43346 )
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 msg['X-Hg-Notification'] = 'changeset %s' % ctx
if not msg['Message-Id']:
msg['Message-Id'] = messageid(ctx, self.domain, self.messageidseed)
Joerg Sonnenberger
notify: optional mail threading based on obsmarker...
r45117 if self.reply:
unfi = self.repo.unfiltered()
has_node = unfi.changelog.index.has_node
predecessors = [
unfi[ctx2]
for ctx2 in obsutil.allpredecessors(unfi.obsstore, [ctx.node()])
if ctx2 != ctx.node() and has_node(ctx2)
]
if predecessors:
# There is at least one predecessor, so which to pick?
# Ideally, there is a unique root because changesets have
# been evolved/rebased one step at a time. In this case,
# just picking the oldest known changeset provides a stable
# base. It doesn't help when changesets are folded. Any
# better solution would require storing more information
# in the repository.
pred = min(predecessors, key=lambda ctx: ctx.rev())
msg['In-Reply-To'] = messageid(
pred, self.domain, self.messageidseed
)
Denis Laxalde
mail: let addressencode() / addrlistencode() return native strings...
r43976 msg['To'] = ', '.join(sorted(subs))
Vadim Gelfer
add email notification hook. hook written in python....
r2203
Manuel Jacob
py3: constant-fold some `pycompat.ispy3`
r50183 msgtext = msg.as_bytes()
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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not msgtext.endswith(b'\n'):
self.ui.write(b'\n')
Bryan O'Sullivan
patch queue: notify.patch
r2201 else:
Augie Fackler
formatting: blacken the codebase...
r43346 self.ui.status(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'notify: sending %d subscribers %d changes\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (len(subs), count)
)
mail.sendmail(
self.ui,
Augie Fackler
cleanup: remove pointless r-prefixes on single-quoted strings...
r43906 emailutils.parseaddr(msg['From'])[1],
Augie Fackler
formatting: blacken the codebase...
r43346 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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 maxdiff = int(self.ui.config(b'notify', b'maxdiff'))
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 prev = ctx.p1().node()
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if ref:
ref = ref.node()
else:
ref = ctx.node()
Joerg Sonnenberger
notify: add option to include function names in the diff output...
r38048 diffopts = patch.diffallopts(self.ui)
diffopts.showfunc = self.showfunc
chunks = patch.diff(self.repo, prev, ref, opts=diffopts)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 difflines = b''.join(chunks).splitlines()
divy@chelsio.com
notify: fix diffstat printing...
r6979
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.ui.configbool(b'notify', b'diffstat'):
maxdiffstat = int(self.ui.config(b'notify', b'maxdiffstat'))
Matt Doar
Add support for diffstat in commit emails, and move diffstat from...
r3096 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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if maxdiffstat >= 0 and s.count(b"\n") > maxdiffstat + 1:
s = s.split(b"\n")
msg = _(b'\ndiffstat (truncated from %d to %d lines):\n\n')
Joerg Sonnenberger
notify: add maxdiffstat option to truncate long file lists...
r37795 self.ui.write(msg % (len(s) - 2, maxdiffstat))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(b"\n".join(s[:maxdiffstat] + s[-2:]))
Joerg Sonnenberger
notify: add maxdiffstat option to truncate long file lists...
r37795 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(_(b'\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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b'\ndiffs (truncated from %d to %d lines):\n\n')
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 self.ui.write(msg % (len(difflines), maxdiff))
Vadim Gelfer
add email notification hook. hook written in python....
r2203 difflines = difflines[:maxdiff]
elif difflines:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(_(b'\ndiffs (%d lines):\n\n') % len(difflines))
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.write(b"\n".join(difflines))
Bryan O'Sullivan
patch queue: notify.patch
r2201
Augie Fackler
formatting: blacken the codebase...
r43346
Vadim Gelfer
localrepository.addchangegroup: add more source infos to hooks
r2230 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """send email notifications to interested subscribers.
Vadim Gelfer
add email notification hook. hook written in python....
r2203
if used as changegroup hook, send one email for all changesets in
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 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)
Boris Feld
notify: access the initial revision on an unfiltered repository (issue5821)...
r37812 ctx = repo.unfiltered()[node]
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
Vadim Gelfer
notify: add debug output. do not fail if no config file....
r2329 if not n.subs:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b'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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.debug(b'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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 data = b''
David Champion
notify: permit suppression of merge changeset notification...
r9516 count = 0
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 author = b''
if hooktype == b'changegroup' or hooktype == b'outgoing':
Boris Feld
notify: use changelog API to iterate over revision number (issue5821)...
r37811 for rev in repo.changelog.revs(start=ctx.rev()):
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()
Augie Fackler
formatting: blacken the codebase...
r43346 ui.note(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'notify: suppressing notification for merge %d:%s\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (rev, repo[rev].hex()[:12])
)
David Champion
notify: permit suppression of merge changeset notification...
r9516 ui.pushbuffer()
if count:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 n.diff(ctx, repo[b'tip'])
Boris Feld
notify: only notify for non-filtered revision...
r37813 elif ctx.rev() in repo:
David Champion
notify: permit suppression of merge changeset notification...
r9516 if not n.node(ctx):
ui.popbuffer()
Augie Fackler
formatting: blacken the codebase...
r43346 ui.note(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'notify: suppressing notification for merge %d:%s\n')
Augie Fackler
formatting: blacken the codebase...
r43346 % (ctx.rev(), ctx.hex()[:12])
)
David Champion
notify: permit suppression of merge changeset notification...
r9516 return
count += 1
Dirkjan Ochtman
notify: use contexts more pervasively
r7726 n.diff(ctx)
Bruce Cran
notify: fix fromauthor setting for 'incoming' hook type (issue4194)...
r26503 if not author:
author = ctx.user()
Dirkjan Ochtman
notify: use contexts more pervasively
r7726
David Champion
notify: permit suppression of merge changeset notification...
r9516 data += ui.popbuffer()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fromauthor = ui.config(b'notify', b'fromauthor')
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654 if author and fromauthor:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 data = b'\n'.join([b'From: %s' % author, data])
Nikolaus Schueler
notify: change behavior of "changegroup" hook...
r15654
David Champion
notify: permit suppression of merge changeset notification...
r9516 if count:
n.send(ctx, count, data)
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174
Augie Fackler
formatting: blacken the codebase...
r43346
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 def messageid(ctx, domain, messageidseed):
if domain and messageidseed:
host = domain
else:
host = encoding.strtolocal(socket.getfqdn())
if messageidseed:
messagehash = hashlib.sha512(ctx.hex() + messageidseed)
Gregory Szorc
notify: cast hash to bytes...
r43434 messageid = b'<hg.%s@%s>' % (
pycompat.sysbytes(messagehash.hexdigest()[:64]),
host,
)
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 messageid = b'<hg.%s.%d.%d@%s>' % (
Augie Fackler
formatting: blacken the codebase...
r43346 ctx,
int(time.time()),
hash(ctx.repo().root),
host,
)
Joerg Sonnenberger
notify: add option for deterministic message-id generation...
r43174 return encoding.strfromlocal(messageid)