##// END OF EJS Templates
notify: do not load style file if template is specified (BC)...
Yuya Nishihara -
r28951:1bba1b43 default
parent child Browse files
Show More
@@ -1,428 +1,430 b''
1 1 # notify.py - email notifications for mercurial
2 2 #
3 3 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 '''hooks for sending email push notifications
9 9
10 10 This extension implements hooks to send email notifications when
11 11 changesets are sent from or received by the local repository.
12 12
13 13 First, enable the extension as explained in :hg:`help extensions`, and
14 14 register the hook you want to run. ``incoming`` and ``changegroup`` hooks
15 15 are run when changesets are received, while ``outgoing`` hooks are for
16 16 changesets sent to another repository::
17 17
18 18 [hooks]
19 19 # one email for each incoming changeset
20 20 incoming.notify = python:hgext.notify.hook
21 21 # one email for all incoming changesets
22 22 changegroup.notify = python:hgext.notify.hook
23 23
24 24 # one email for all outgoing changesets
25 25 outgoing.notify = python:hgext.notify.hook
26 26
27 27 This registers the hooks. To enable notification, subscribers must
28 28 be assigned to repositories. The ``[usersubs]`` section maps multiple
29 29 repositories to a given recipient. The ``[reposubs]`` section maps
30 30 multiple recipients to a single repository::
31 31
32 32 [usersubs]
33 33 # key is subscriber email, value is a comma-separated list of repo patterns
34 34 user@host = pattern
35 35
36 36 [reposubs]
37 37 # key is repo pattern, value is a comma-separated list of subscriber emails
38 38 pattern = user@host
39 39
40 40 A ``pattern`` is a ``glob`` matching the absolute path to a repository,
41 41 optionally combined with a revset expression. A revset expression, if
42 42 present, is separated from the glob by a hash. Example::
43 43
44 44 [reposubs]
45 45 */widgets#branch(release) = qa-team@example.com
46 46
47 47 This sends to ``qa-team@example.com`` whenever a changeset on the ``release``
48 48 branch triggers a notification in any repository ending in ``widgets``.
49 49
50 50 In order to place them under direct user management, ``[usersubs]`` and
51 51 ``[reposubs]`` sections may be placed in a separate ``hgrc`` file and
52 52 incorporated by reference::
53 53
54 54 [notify]
55 55 config = /path/to/subscriptionsfile
56 56
57 57 Notifications will not be sent until the ``notify.test`` value is set
58 58 to ``False``; see below.
59 59
60 60 Notifications content can be tweaked with the following configuration entries:
61 61
62 62 notify.test
63 63 If ``True``, print messages to stdout instead of sending them. Default: True.
64 64
65 65 notify.sources
66 66 Space-separated list of change sources. Notifications are activated only
67 67 when a changeset's source is in this list. Sources may be:
68 68
69 69 :``serve``: changesets received via http or ssh
70 70 :``pull``: changesets received via ``hg pull``
71 71 :``unbundle``: changesets received via ``hg unbundle``
72 72 :``push``: changesets sent or received via ``hg push``
73 73 :``bundle``: changesets sent via ``hg unbundle``
74 74
75 75 Default: serve.
76 76
77 77 notify.strip
78 78 Number of leading slashes to strip from url paths. By default, notifications
79 79 reference repositories with their absolute path. ``notify.strip`` lets you
80 80 turn them into relative paths. For example, ``notify.strip=3`` will change
81 81 ``/long/path/repository`` into ``repository``. Default: 0.
82 82
83 83 notify.domain
84 84 Default email domain for sender or recipients with no explicit domain.
85 85
86 86 notify.style
87 87 Style file to use when formatting emails.
88 88
89 89 notify.template
90 90 Template to use when formatting emails.
91 91
92 92 notify.incoming
93 93 Template to use when run as an incoming hook, overriding ``notify.template``.
94 94
95 95 notify.outgoing
96 96 Template to use when run as an outgoing hook, overriding ``notify.template``.
97 97
98 98 notify.changegroup
99 99 Template to use when running as a changegroup hook, overriding
100 100 ``notify.template``.
101 101
102 102 notify.maxdiff
103 103 Maximum number of diff lines to include in notification email. Set to 0
104 104 to disable the diff, or -1 to include all of it. Default: 300.
105 105
106 106 notify.maxsubject
107 107 Maximum number of characters in email's subject line. Default: 67.
108 108
109 109 notify.diffstat
110 110 Set to True to include a diffstat before diff content. Default: True.
111 111
112 112 notify.merge
113 113 If True, send notifications for merge changesets. Default: True.
114 114
115 115 notify.mbox
116 116 If set, append mails to this mbox file instead of sending. Default: None.
117 117
118 118 notify.fromauthor
119 119 If set, use the committer of the first changeset in a changegroup for
120 120 the "From" field of the notification mail. If not set, take the user
121 121 from the pushing repo. Default: False.
122 122
123 123 If set, the following entries will also be used to customize the
124 124 notifications:
125 125
126 126 email.from
127 127 Email ``From`` address to use if none can be found in the generated
128 128 email content.
129 129
130 130 web.baseurl
131 131 Root repository URL to combine with repository paths when making
132 132 references. See also ``notify.strip``.
133 133
134 134 '''
135 135 from __future__ import absolute_import
136 136
137 137 import email
138 138 import fnmatch
139 139 import socket
140 140 import time
141 141
142 142 from mercurial import (
143 143 cmdutil,
144 144 error,
145 145 mail,
146 146 patch,
147 147 util,
148 148 )
149 149 from mercurial.i18n import _
150 150
151 151 # Note for extension authors: ONLY specify testedwith = 'internal' for
152 152 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
153 153 # be specifying the version(s) of Mercurial they are tested with, or
154 154 # leave the attribute unspecified.
155 155 testedwith = 'internal'
156 156
157 157 # template for single changeset can include email headers.
158 158 single_template = '''
159 159 Subject: changeset in {webroot}: {desc|firstline|strip}
160 160 From: {author}
161 161
162 162 changeset {node|short} in {root}
163 163 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
164 164 description:
165 165 \t{desc|tabindent|strip}
166 166 '''.lstrip()
167 167
168 168 # template for multiple changesets should not contain email headers,
169 169 # because only first set of headers will be used and result will look
170 170 # strange.
171 171 multiple_template = '''
172 172 changeset {node|short} in {root}
173 173 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
174 174 summary: {desc|firstline}
175 175 '''
176 176
177 177 deftemplates = {
178 178 'changegroup': multiple_template,
179 179 }
180 180
181 181 class notifier(object):
182 182 '''email notification class.'''
183 183
184 184 def __init__(self, ui, repo, hooktype):
185 185 self.ui = ui
186 186 cfg = self.ui.config('notify', 'config')
187 187 if cfg:
188 188 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
189 189 self.repo = repo
190 190 self.stripcount = int(self.ui.config('notify', 'strip', 0))
191 191 self.root = self.strip(self.repo.root)
192 192 self.domain = self.ui.config('notify', 'domain')
193 193 self.mbox = self.ui.config('notify', 'mbox')
194 194 self.test = self.ui.configbool('notify', 'test', True)
195 195 self.charsets = mail._charsets(self.ui)
196 196 self.subs = self.subscribers()
197 197 self.merge = self.ui.configbool('notify', 'merge', True)
198 198
199 mapfile = self.ui.config('notify', 'style')
199 mapfile = None
200 200 template = (self.ui.config('notify', hooktype) or
201 201 self.ui.config('notify', 'template'))
202 if not template:
203 mapfile = self.ui.config('notify', 'style')
202 204 if not mapfile and not template:
203 205 template = deftemplates.get(hooktype) or single_template
204 206 self.t = cmdutil.changeset_templater(self.ui, self.repo, False, None,
205 207 template, mapfile, False)
206 208
207 209 def strip(self, path):
208 210 '''strip leading slashes from local path, turn into web-safe path.'''
209 211
210 212 path = util.pconvert(path)
211 213 count = self.stripcount
212 214 while count > 0:
213 215 c = path.find('/')
214 216 if c == -1:
215 217 break
216 218 path = path[c + 1:]
217 219 count -= 1
218 220 return path
219 221
220 222 def fixmail(self, addr):
221 223 '''try to clean up email addresses.'''
222 224
223 225 addr = util.email(addr.strip())
224 226 if self.domain:
225 227 a = addr.find('@localhost')
226 228 if a != -1:
227 229 addr = addr[:a]
228 230 if '@' not in addr:
229 231 return addr + '@' + self.domain
230 232 return addr
231 233
232 234 def subscribers(self):
233 235 '''return list of email addresses of subscribers to this repo.'''
234 236 subs = set()
235 237 for user, pats in self.ui.configitems('usersubs'):
236 238 for pat in pats.split(','):
237 239 if '#' in pat:
238 240 pat, revs = pat.split('#', 1)
239 241 else:
240 242 revs = None
241 243 if fnmatch.fnmatch(self.repo.root, pat.strip()):
242 244 subs.add((self.fixmail(user), revs))
243 245 for pat, users in self.ui.configitems('reposubs'):
244 246 if '#' in pat:
245 247 pat, revs = pat.split('#', 1)
246 248 else:
247 249 revs = None
248 250 if fnmatch.fnmatch(self.repo.root, pat):
249 251 for user in users.split(','):
250 252 subs.add((self.fixmail(user), revs))
251 253 return [(mail.addressencode(self.ui, s, self.charsets, self.test), r)
252 254 for s, r in sorted(subs)]
253 255
254 256 def node(self, ctx, **props):
255 257 '''format one changeset, unless it is a suppressed merge.'''
256 258 if not self.merge and len(ctx.parents()) > 1:
257 259 return False
258 260 self.t.show(ctx, changes=ctx.changeset(),
259 261 baseurl=self.ui.config('web', 'baseurl'),
260 262 root=self.repo.root, webroot=self.root, **props)
261 263 return True
262 264
263 265 def skipsource(self, source):
264 266 '''true if incoming changes from this source should be skipped.'''
265 267 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
266 268 return source not in ok_sources
267 269
268 270 def send(self, ctx, count, data):
269 271 '''send message.'''
270 272
271 273 # Select subscribers by revset
272 274 subs = set()
273 275 for sub, spec in self.subs:
274 276 if spec is None:
275 277 subs.add(sub)
276 278 continue
277 279 revs = self.repo.revs('%r and %d:', spec, ctx.rev())
278 280 if len(revs):
279 281 subs.add(sub)
280 282 continue
281 283 if len(subs) == 0:
282 284 self.ui.debug('notify: no subscribers to selected repo '
283 285 'and revset\n')
284 286 return
285 287
286 288 p = email.Parser.Parser()
287 289 try:
288 290 msg = p.parsestr(data)
289 291 except email.Errors.MessageParseError as inst:
290 292 raise error.Abort(inst)
291 293
292 294 # store sender and subject
293 295 sender, subject = msg['From'], msg['Subject']
294 296 del msg['From'], msg['Subject']
295 297
296 298 if not msg.is_multipart():
297 299 # create fresh mime message from scratch
298 300 # (multipart templates must take care of this themselves)
299 301 headers = msg.items()
300 302 payload = msg.get_payload()
301 303 # for notification prefer readability over data precision
302 304 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
303 305 # reinstate custom headers
304 306 for k, v in headers:
305 307 msg[k] = v
306 308
307 309 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
308 310
309 311 # try to make subject line exist and be useful
310 312 if not subject:
311 313 if count > 1:
312 314 subject = _('%s: %d new changesets') % (self.root, count)
313 315 else:
314 316 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
315 317 subject = '%s: %s' % (self.root, s)
316 318 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
317 319 if maxsubject:
318 320 subject = util.ellipsis(subject, maxsubject)
319 321 msg['Subject'] = mail.headencode(self.ui, subject,
320 322 self.charsets, self.test)
321 323
322 324 # try to make message have proper sender
323 325 if not sender:
324 326 sender = self.ui.config('email', 'from') or self.ui.username()
325 327 if '@' not in sender or '@localhost' in sender:
326 328 sender = self.fixmail(sender)
327 329 msg['From'] = mail.addressencode(self.ui, sender,
328 330 self.charsets, self.test)
329 331
330 332 msg['X-Hg-Notification'] = 'changeset %s' % ctx
331 333 if not msg['Message-Id']:
332 334 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
333 335 (ctx, int(time.time()),
334 336 hash(self.repo.root), socket.getfqdn()))
335 337 msg['To'] = ', '.join(sorted(subs))
336 338
337 339 msgtext = msg.as_string()
338 340 if self.test:
339 341 self.ui.write(msgtext)
340 342 if not msgtext.endswith('\n'):
341 343 self.ui.write('\n')
342 344 else:
343 345 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
344 346 (len(subs), count))
345 347 mail.sendmail(self.ui, util.email(msg['From']),
346 348 subs, msgtext, mbox=self.mbox)
347 349
348 350 def diff(self, ctx, ref=None):
349 351
350 352 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
351 353 prev = ctx.p1().node()
352 354 if ref:
353 355 ref = ref.node()
354 356 else:
355 357 ref = ctx.node()
356 358 chunks = patch.diff(self.repo, prev, ref,
357 359 opts=patch.diffallopts(self.ui))
358 360 difflines = ''.join(chunks).splitlines()
359 361
360 362 if self.ui.configbool('notify', 'diffstat', True):
361 363 s = patch.diffstat(difflines)
362 364 # s may be nil, don't include the header if it is
363 365 if s:
364 366 self.ui.write('\ndiffstat:\n\n%s' % s)
365 367
366 368 if maxdiff == 0:
367 369 return
368 370 elif maxdiff > 0 and len(difflines) > maxdiff:
369 371 msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
370 372 self.ui.write(msg % (len(difflines), maxdiff))
371 373 difflines = difflines[:maxdiff]
372 374 elif difflines:
373 375 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
374 376
375 377 self.ui.write("\n".join(difflines))
376 378
377 379 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
378 380 '''send email notifications to interested subscribers.
379 381
380 382 if used as changegroup hook, send one email for all changesets in
381 383 changegroup. else send one email per changeset.'''
382 384
383 385 n = notifier(ui, repo, hooktype)
384 386 ctx = repo[node]
385 387
386 388 if not n.subs:
387 389 ui.debug('notify: no subscribers to repository %s\n' % n.root)
388 390 return
389 391 if n.skipsource(source):
390 392 ui.debug('notify: changes have source "%s" - skipping\n' % source)
391 393 return
392 394
393 395 ui.pushbuffer()
394 396 data = ''
395 397 count = 0
396 398 author = ''
397 399 if hooktype == 'changegroup' or hooktype == 'outgoing':
398 400 start, end = ctx.rev(), len(repo)
399 401 for rev in xrange(start, end):
400 402 if n.node(repo[rev]):
401 403 count += 1
402 404 if not author:
403 405 author = repo[rev].user()
404 406 else:
405 407 data += ui.popbuffer()
406 408 ui.note(_('notify: suppressing notification for merge %d:%s\n')
407 409 % (rev, repo[rev].hex()[:12]))
408 410 ui.pushbuffer()
409 411 if count:
410 412 n.diff(ctx, repo['tip'])
411 413 else:
412 414 if not n.node(ctx):
413 415 ui.popbuffer()
414 416 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
415 417 (ctx.rev(), ctx.hex()[:12]))
416 418 return
417 419 count += 1
418 420 n.diff(ctx)
419 421 if not author:
420 422 author = ctx.user()
421 423
422 424 data += ui.popbuffer()
423 425 fromauthor = ui.config('notify', 'fromauthor')
424 426 if author and fromauthor:
425 427 data = '\n'.join(['From: %s' % author, data])
426 428
427 429 if count:
428 430 n.send(ctx, count, data)
@@ -1,555 +1,628 b''
1 1
2 2 $ cat <<EOF >> $HGRCPATH
3 3 > [extensions]
4 4 > notify=
5 5 >
6 6 > [hooks]
7 7 > incoming.notify = python:hgext.notify.hook
8 8 >
9 9 > [notify]
10 10 > sources = pull
11 11 > diffstat = False
12 12 >
13 13 > [usersubs]
14 14 > foo@bar = *
15 15 >
16 16 > [reposubs]
17 17 > * = baz
18 18 > EOF
19 19 $ hg help notify
20 20 notify extension - hooks for sending email push notifications
21 21
22 22 This extension implements hooks to send email notifications when changesets
23 23 are sent from or received by the local repository.
24 24
25 25 First, enable the extension as explained in 'hg help extensions', and register
26 26 the hook you want to run. "incoming" and "changegroup" hooks are run when
27 27 changesets are received, while "outgoing" hooks are for changesets sent to
28 28 another repository:
29 29
30 30 [hooks]
31 31 # one email for each incoming changeset
32 32 incoming.notify = python:hgext.notify.hook
33 33 # one email for all incoming changesets
34 34 changegroup.notify = python:hgext.notify.hook
35 35
36 36 # one email for all outgoing changesets
37 37 outgoing.notify = python:hgext.notify.hook
38 38
39 39 This registers the hooks. To enable notification, subscribers must be assigned
40 40 to repositories. The "[usersubs]" section maps multiple repositories to a
41 41 given recipient. The "[reposubs]" section maps multiple recipients to a single
42 42 repository:
43 43
44 44 [usersubs]
45 45 # key is subscriber email, value is a comma-separated list of repo patterns
46 46 user@host = pattern
47 47
48 48 [reposubs]
49 49 # key is repo pattern, value is a comma-separated list of subscriber emails
50 50 pattern = user@host
51 51
52 52 A "pattern" is a "glob" matching the absolute path to a repository, optionally
53 53 combined with a revset expression. A revset expression, if present, is
54 54 separated from the glob by a hash. Example:
55 55
56 56 [reposubs]
57 57 */widgets#branch(release) = qa-team@example.com
58 58
59 59 This sends to "qa-team@example.com" whenever a changeset on the "release"
60 60 branch triggers a notification in any repository ending in "widgets".
61 61
62 62 In order to place them under direct user management, "[usersubs]" and
63 63 "[reposubs]" sections may be placed in a separate "hgrc" file and incorporated
64 64 by reference:
65 65
66 66 [notify]
67 67 config = /path/to/subscriptionsfile
68 68
69 69 Notifications will not be sent until the "notify.test" value is set to
70 70 "False"; see below.
71 71
72 72 Notifications content can be tweaked with the following configuration entries:
73 73
74 74 notify.test
75 75 If "True", print messages to stdout instead of sending them. Default: True.
76 76
77 77 notify.sources
78 78 Space-separated list of change sources. Notifications are activated only
79 79 when a changeset's source is in this list. Sources may be:
80 80
81 81 "serve" changesets received via http or ssh
82 82 "pull" changesets received via "hg pull"
83 83 "unbundle" changesets received via "hg unbundle"
84 84 "push" changesets sent or received via "hg push"
85 85 "bundle" changesets sent via "hg unbundle"
86 86
87 87 Default: serve.
88 88
89 89 notify.strip
90 90 Number of leading slashes to strip from url paths. By default, notifications
91 91 reference repositories with their absolute path. "notify.strip" lets you
92 92 turn them into relative paths. For example, "notify.strip=3" will change
93 93 "/long/path/repository" into "repository". Default: 0.
94 94
95 95 notify.domain
96 96 Default email domain for sender or recipients with no explicit domain.
97 97
98 98 notify.style
99 99 Style file to use when formatting emails.
100 100
101 101 notify.template
102 102 Template to use when formatting emails.
103 103
104 104 notify.incoming
105 105 Template to use when run as an incoming hook, overriding "notify.template".
106 106
107 107 notify.outgoing
108 108 Template to use when run as an outgoing hook, overriding "notify.template".
109 109
110 110 notify.changegroup
111 111 Template to use when running as a changegroup hook, overriding
112 112 "notify.template".
113 113
114 114 notify.maxdiff
115 115 Maximum number of diff lines to include in notification email. Set to 0 to
116 116 disable the diff, or -1 to include all of it. Default: 300.
117 117
118 118 notify.maxsubject
119 119 Maximum number of characters in email's subject line. Default: 67.
120 120
121 121 notify.diffstat
122 122 Set to True to include a diffstat before diff content. Default: True.
123 123
124 124 notify.merge
125 125 If True, send notifications for merge changesets. Default: True.
126 126
127 127 notify.mbox
128 128 If set, append mails to this mbox file instead of sending. Default: None.
129 129
130 130 notify.fromauthor
131 131 If set, use the committer of the first changeset in a changegroup for the
132 132 "From" field of the notification mail. If not set, take the user from the
133 133 pushing repo. Default: False.
134 134
135 135 If set, the following entries will also be used to customize the
136 136 notifications:
137 137
138 138 email.from
139 139 Email "From" address to use if none can be found in the generated email
140 140 content.
141 141
142 142 web.baseurl
143 143 Root repository URL to combine with repository paths when making references.
144 144 See also "notify.strip".
145 145
146 146 no commands defined
147 147 $ hg init a
148 148 $ echo a > a/a
149 149
150 150 commit
151 151
152 152 $ hg --cwd a commit -Ama -d '0 0'
153 153 adding a
154 154
155 155
156 156 clone
157 157
158 158 $ hg --traceback clone a b
159 159 updating to branch default
160 160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 161 $ echo a >> a/a
162 162
163 163 commit
164 164
165 165 $ hg --traceback --cwd a commit -Amb -d '1 0'
166 166
167 167 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
168 168
169 169 $ cat <<EOF >> $HGRCPATH
170 170 > [notify]
171 171 > maxsubject = 200
172 172 > EOF
173 173
174 174 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
175 175 of the very long subject line
176 176 pull (minimal config)
177 177
178 178 $ hg --traceback --cwd b pull ../a | \
179 179 > $PYTHON -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
180 180 pulling from ../a
181 181 searching for changes
182 182 adding changesets
183 183 adding manifests
184 184 adding file changes
185 185 added 1 changesets with 1 changes to 1 files
186 186 Content-Type: text/plain; charset="us-ascii"
187 187 MIME-Version: 1.0
188 188 Content-Transfer-Encoding: 7bit
189 189 Date: * (glob)
190 190 Subject: changeset in $TESTTMP/b: b
191 191 From: test
192 192 X-Hg-Notification: changeset 0647d048b600
193 193 Message-Id: <*> (glob)
194 194 To: baz, foo@bar
195 195
196 196 changeset 0647d048b600 in $TESTTMP/b (glob)
197 197 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
198 198 description: b
199 199
200 200 diffs (6 lines):
201 201
202 202 diff -r cb9a9f314b8b -r 0647d048b600 a
203 203 --- a/a Thu Jan 01 00:00:00 1970 +0000
204 204 +++ b/a Thu Jan 01 00:00:01 1970 +0000
205 205 @@ -1,1 +1,2 @@ a
206 206 +a
207 207 (run 'hg update' to get a working copy)
208 208 $ cat <<EOF >> $HGRCPATH
209 209 > [notify]
210 210 > config = `pwd`/.notify.conf
211 211 > domain = test.com
212 212 > strip = 42
213 213 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
214 214 >
215 215 > [web]
216 216 > baseurl = http://test/
217 217 > EOF
218 218
219 219 fail for config file is missing
220 220
221 221 $ hg --cwd b rollback
222 222 repository tip rolled back to revision 0 (undo pull)
223 223 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
224 224 pull failed
225 225 $ touch ".notify.conf"
226 226
227 227 pull
228 228
229 229 $ hg --cwd b rollback
230 230 repository tip rolled back to revision 0 (undo pull)
231 231 $ hg --traceback --cwd b pull ../a | \
232 232 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
233 233 pulling from ../a
234 234 searching for changes
235 235 adding changesets
236 236 adding manifests
237 237 adding file changes
238 238 added 1 changesets with 1 changes to 1 files
239 239 Content-Type: text/plain; charset="us-ascii"
240 240 MIME-Version: 1.0
241 241 Content-Transfer-Encoding: 7bit
242 242 X-Test: foo
243 243 Date: * (glob)
244 244 Subject: b
245 245 From: test@test.com
246 246 X-Hg-Notification: changeset 0647d048b600
247 247 Message-Id: <*> (glob)
248 248 To: baz@test.com, foo@bar
249 249
250 250 changeset 0647d048b600 in b
251 251 description: b
252 252 diffs (6 lines):
253 253
254 254 diff -r cb9a9f314b8b -r 0647d048b600 a
255 255 --- a/a Thu Jan 01 00:00:00 1970 +0000
256 256 +++ b/a Thu Jan 01 00:00:01 1970 +0000
257 257 @@ -1,1 +1,2 @@
258 258 a
259 259 +a
260 260 (run 'hg update' to get a working copy)
261 261
262 262 $ cat << EOF >> $HGRCPATH
263 263 > [hooks]
264 264 > incoming.notify = python:hgext.notify.hook
265 265 >
266 266 > [notify]
267 267 > sources = pull
268 268 > diffstat = True
269 269 > EOF
270 270
271 271 pull
272 272
273 273 $ hg --cwd b rollback
274 274 repository tip rolled back to revision 0 (undo pull)
275 275 $ hg --traceback --cwd b pull ../a | \
276 276 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
277 277 pulling from ../a
278 278 searching for changes
279 279 adding changesets
280 280 adding manifests
281 281 adding file changes
282 282 added 1 changesets with 1 changes to 1 files
283 283 Content-Type: text/plain; charset="us-ascii"
284 284 MIME-Version: 1.0
285 285 Content-Transfer-Encoding: 7bit
286 286 X-Test: foo
287 287 Date: * (glob)
288 288 Subject: b
289 289 From: test@test.com
290 290 X-Hg-Notification: changeset 0647d048b600
291 291 Message-Id: <*> (glob)
292 292 To: baz@test.com, foo@bar
293 293
294 294 changeset 0647d048b600 in b
295 295 description: b
296 296 diffstat:
297 297
298 298 a | 1 +
299 299 1 files changed, 1 insertions(+), 0 deletions(-)
300 300
301 301 diffs (6 lines):
302 302
303 303 diff -r cb9a9f314b8b -r 0647d048b600 a
304 304 --- a/a Thu Jan 01 00:00:00 1970 +0000
305 305 +++ b/a Thu Jan 01 00:00:01 1970 +0000
306 306 @@ -1,1 +1,2 @@
307 307 a
308 308 +a
309 309 (run 'hg update' to get a working copy)
310 310
311 311 test merge
312 312
313 313 $ cd a
314 314 $ hg up -C 0
315 315 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
316 316 $ echo a >> a
317 317 $ hg ci -Am adda2 -d '2 0'
318 318 created new head
319 319 $ hg merge
320 320 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 321 (branch merge, don't forget to commit)
322 322 $ hg ci -m merge -d '3 0'
323 323 $ cd ..
324 324 $ hg --traceback --cwd b pull ../a | \
325 325 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
326 326 pulling from ../a
327 327 searching for changes
328 328 adding changesets
329 329 adding manifests
330 330 adding file changes
331 331 added 2 changesets with 0 changes to 0 files
332 332 Content-Type: text/plain; charset="us-ascii"
333 333 MIME-Version: 1.0
334 334 Content-Transfer-Encoding: 7bit
335 335 X-Test: foo
336 336 Date: * (glob)
337 337 Subject: adda2
338 338 From: test@test.com
339 339 X-Hg-Notification: changeset 0a184ce6067f
340 340 Message-Id: <*> (glob)
341 341 To: baz@test.com, foo@bar
342 342
343 343 changeset 0a184ce6067f in b
344 344 description: adda2
345 345 diffstat:
346 346
347 347 a | 1 +
348 348 1 files changed, 1 insertions(+), 0 deletions(-)
349 349
350 350 diffs (6 lines):
351 351
352 352 diff -r cb9a9f314b8b -r 0a184ce6067f a
353 353 --- a/a Thu Jan 01 00:00:00 1970 +0000
354 354 +++ b/a Thu Jan 01 00:00:02 1970 +0000
355 355 @@ -1,1 +1,2 @@
356 356 a
357 357 +a
358 358 Content-Type: text/plain; charset="us-ascii"
359 359 MIME-Version: 1.0
360 360 Content-Transfer-Encoding: 7bit
361 361 X-Test: foo
362 362 Date: * (glob)
363 363 Subject: merge
364 364 From: test@test.com
365 365 X-Hg-Notification: changeset 6a0cf76b2701
366 366 Message-Id: <*> (glob)
367 367 To: baz@test.com, foo@bar
368 368
369 369 changeset 6a0cf76b2701 in b
370 370 description: merge
371 371 (run 'hg update' to get a working copy)
372 372
373 373 non-ascii content and truncation of multi-byte subject
374 374
375 375 $ cat <<EOF >> $HGRCPATH
376 376 > [notify]
377 377 > maxsubject = 4
378 378 > EOF
379 379 $ echo a >> a/a
380 380 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
381 381 > -m `$PYTHON -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
382 382 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
383 383 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
384 384 pulling from ../a
385 385 searching for changes
386 386 adding changesets
387 387 adding manifests
388 388 adding file changes
389 389 added 1 changesets with 1 changes to 1 files
390 390 Content-Type: text/plain; charset="us-ascii"
391 391 MIME-Version: 1.0
392 392 Content-Transfer-Encoding: 8bit
393 393 X-Test: foo
394 394 Date: * (glob)
395 395 Subject: \xc3\xa0... (esc)
396 396 From: test@test.com
397 397 X-Hg-Notification: changeset 7ea05ad269dc
398 398 Message-Id: <*> (glob)
399 399 To: baz@test.com, foo@bar
400 400
401 401 changeset 7ea05ad269dc in b
402 402 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
403 403 diffstat:
404 404
405 405 a | 1 +
406 406 1 files changed, 1 insertions(+), 0 deletions(-)
407 407
408 408 diffs (7 lines):
409 409
410 410 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
411 411 --- a/a Thu Jan 01 00:00:03 1970 +0000
412 412 +++ b/a Thu Jan 01 00:00:00 1970 +0000
413 413 @@ -1,2 +1,3 @@
414 414 a
415 415 a
416 416 +a
417 417 (run 'hg update' to get a working copy)
418 418
419 419 long lines
420 420
421 421 $ cat <<EOF >> $HGRCPATH
422 422 > [notify]
423 423 > maxsubject = 67
424 424 > test = False
425 425 > mbox = mbox
426 426 > EOF
427 427 $ $PYTHON -c 'file("a/a", "ab").write("no" * 500 + "\n")'
428 428 $ hg --cwd a commit -A -m "long line"
429 429 $ hg --traceback --cwd b pull ../a
430 430 pulling from ../a
431 431 searching for changes
432 432 adding changesets
433 433 adding manifests
434 434 adding file changes
435 435 added 1 changesets with 1 changes to 1 files
436 436 notify: sending 2 subscribers 1 changes
437 437 (run 'hg update' to get a working copy)
438 438 $ $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", file("b/mbox").read()),'
439 439 From test@test.com ... ... .. ..:..:.. .... (re)
440 440 Content-Type: text/plain; charset="us-ascii"
441 441 MIME-Version: 1.0
442 442 Content-Transfer-Encoding: quoted-printable
443 443 X-Test: foo
444 444 Date: * (glob)
445 445 Subject: long line
446 446 From: test@test.com
447 447 X-Hg-Notification: changeset e0be44cf638b
448 448 Message-Id: <hg.e0be44cf638b.*.*@*> (glob)
449 449 To: baz@test.com, foo@bar
450 450
451 451 changeset e0be44cf638b in b
452 452 description: long line
453 453 diffstat:
454 454
455 455 a | 1 +
456 456 1 files changed, 1 insertions(+), 0 deletions(-)
457 457
458 458 diffs (8 lines):
459 459
460 460 diff -r 7ea05ad269dc -r e0be44cf638b a
461 461 --- a/a Thu Jan 01 00:00:00 1970 +0000
462 462 +++ b/a Thu Jan 01 00:00:00 1970 +0000
463 463 @@ -1,3 +1,4 @@
464 464 a
465 465 a
466 466 a
467 467 +nonononononononononononononononononononononononononononononononononononono=
468 468 nononononononononononononononononononononononononononononononononononononon=
469 469 ononononononononononononononononononononononononononononononononononononono=
470 470 nononononononononononononononononononononononononononononononononononononon=
471 471 ononononononononononononononononononononononononononononononononononononono=
472 472 nononononononononononononononononononononononononononononononononononononon=
473 473 ononononononononononononononononononononononononononononononononononononono=
474 474 nononononononononononononononononononononononononononononononononononononon=
475 475 ononononononononononononononononononononononononononononononononononononono=
476 476 nononononononononononononononononononononononononononononononononononononon=
477 477 ononononononononononononononononononononononononononononononononononononono=
478 478 nononononononononononononononononononononononononononononononononononononon=
479 479 ononononononononononononononononononononononononononononononononononononono=
480 480 nonononononononononononono
481 481
482 482 revset selection: send to address that matches branch and repo
483 483
484 484 $ cat << EOF >> $HGRCPATH
485 485 > [hooks]
486 486 > incoming.notify = python:hgext.notify.hook
487 487 >
488 488 > [notify]
489 489 > sources = pull
490 490 > test = True
491 491 > diffstat = False
492 492 > maxdiff = 0
493 493 >
494 494 > [reposubs]
495 495 > */a#branch(test) = will_no_be_send@example.com
496 496 > */b#branch(test) = notify@example.com
497 497 > EOF
498 498 $ hg --cwd a branch test
499 499 marked working directory as branch test
500 500 (branches are permanent and global, did you want a bookmark?)
501 501 $ echo a >> a/a
502 502 $ hg --cwd a ci -m test -d '1 0'
503 503 $ hg --traceback --cwd b pull ../a | \
504 504 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
505 505 pulling from ../a
506 506 searching for changes
507 507 adding changesets
508 508 adding manifests
509 509 adding file changes
510 510 added 1 changesets with 1 changes to 1 files
511 511 Content-Type: text/plain; charset="us-ascii"
512 512 MIME-Version: 1.0
513 513 Content-Transfer-Encoding: 7bit
514 514 X-Test: foo
515 515 Date: * (glob)
516 516 Subject: test
517 517 From: test@test.com
518 518 X-Hg-Notification: changeset fbbcbc516f2f
519 519 Message-Id: <hg.fbbcbc516f2f.*.*@*> (glob)
520 520 To: baz@test.com, foo@bar, notify@example.com
521 521
522 522 changeset fbbcbc516f2f in b
523 523 description: test
524 524 (run 'hg update' to get a working copy)
525 525
526 526 revset selection: don't send to address that waits for mails
527 527 from different branch
528 528
529 529 $ hg --cwd a update default
530 530 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 531 $ echo a >> a/a
532 532 $ hg --cwd a ci -m test -d '1 0'
533 533 $ hg --traceback --cwd b pull ../a | \
534 534 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
535 535 pulling from ../a
536 536 searching for changes
537 537 adding changesets
538 538 adding manifests
539 539 adding file changes
540 540 added 1 changesets with 0 changes to 0 files (+1 heads)
541 541 Content-Type: text/plain; charset="us-ascii"
542 542 MIME-Version: 1.0
543 543 Content-Transfer-Encoding: 7bit
544 544 X-Test: foo
545 545 Date: * (glob)
546 546 Subject: test
547 547 From: test@test.com
548 548 X-Hg-Notification: changeset 38b42fa092de
549 549 Message-Id: <hg.38b42fa092de.*.*@*> (glob)
550 550 To: baz@test.com, foo@bar
551 551
552 552 changeset 38b42fa092de in b
553 553 description: test
554 554 (run 'hg heads' to see heads)
555 555
556 default template:
557
558 $ grep -v '^template =' $HGRCPATH > "$HGRCPATH.new"
559 $ mv "$HGRCPATH.new" $HGRCPATH
560 $ echo a >> a/a
561 $ hg --cwd a commit -m 'default template'
562 $ hg --cwd b pull ../a -q | \
563 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
564 Content-Type: text/plain; charset="us-ascii"
565 MIME-Version: 1.0
566 Content-Transfer-Encoding: 7bit
567 Date: * (glob)
568 Subject: changeset in b: default template
569 From: test@test.com
570 X-Hg-Notification: changeset 3548c9e294b6
571 Message-Id: <hg.3548c9e294b6.*.*@*> (glob)
572 To: baz@test.com, foo@bar
573
574 changeset 3548c9e294b6 in $TESTTMP/b
575 details: http://test/b?cmd=changeset;node=3548c9e294b6
576 description: default template
577
578 with style:
579
580 $ cat <<EOF > notifystyle.map
581 > changeset = "Subject: {desc|firstline|strip}
582 > From: {author}
583 > {""}
584 > changeset {node|short}"
585 > EOF
586 $ cat <<EOF >> $HGRCPATH
587 > [notify]
588 > style = $TESTTMP/notifystyle.map
589 > EOF
590 $ echo a >> a/a
591 $ hg --cwd a commit -m 'with style'
592 $ hg --cwd b pull ../a -q | \
593 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
594 Content-Type: text/plain; charset="us-ascii"
595 MIME-Version: 1.0
596 Content-Transfer-Encoding: 7bit
597 Date: * (glob)
598 Subject: with style
599 From: test@test.com
600 X-Hg-Notification: changeset e917dbd961d3
601 Message-Id: <hg.e917dbd961d3.*.*@*> (glob)
602 To: baz@test.com, foo@bar
603
604 changeset e917dbd961d3
605
606 with template (overrides style):
607
608 $ cat <<EOF >> $HGRCPATH
609 > template = Subject: {node|short}: {desc|firstline|strip}
610 > From: {author}
611 > {""}
612 > {desc}
613 > EOF
614 $ echo a >> a/a
615 $ hg --cwd a commit -m 'with template'
616 $ hg --cwd b pull ../a -q | \
617 > $PYTHON -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
618 Content-Type: text/plain; charset="us-ascii"
619 MIME-Version: 1.0
620 Content-Transfer-Encoding: 7bit
621 Date: * (glob)
622 Subject: a09743fd3edd: with template
623 From: test@test.com
624 X-Hg-Notification: changeset a09743fd3edd
625 Message-Id: <hg.a09743fd3edd.*.*@*> (glob)
626 To: baz@test.com, foo@bar
627
628 with template
General Comments 0
You need to be logged in to leave comments. Login now