##// END OF EJS Templates
notify: various fixes to docstring...
David Champion -
r16950:0fdd8193 stable
parent child Browse files
Show More
@@ -1,376 +1,380 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 This extension let you run hooks sending email notifications when
11 changesets are being pushed, from the sending or receiving side.
10 This extension implements hooks to send email notifications when
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 are run by the changesets receiver while the ``outgoing`` one is for
16 the sender::
15 are run when changesets are received, while ``outgoing`` hooks are for
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 Now the hooks are running, subscribers must be assigned to
28 repositories. Use the ``[usersubs]`` section to map repositories to a
29 given email or the ``[reposubs]`` section to map emails to a single
30 repository::
27 This registers the hooks. To enable notification, subscribers must
28 be assigned to repositories. The ``[usersubs]`` section maps multiple
29 repositories to a given recipient. The ``[reposubs]`` section maps
30 multiple recipients to a single repository::
31 31
32 32 [usersubs]
33 # key is subscriber email, value is a comma-separated list of glob
33 # key is subscriber email, value is a comma-separated list of repo glob
34 34 # patterns
35 35 user@host = pattern
36 36
37 37 [reposubs]
38 38 # key is glob pattern, value is a comma-separated list of subscriber
39 39 # emails
40 40 pattern = user@host
41 41
42 42 Glob patterns are matched against absolute path to repository
43 root. The subscriptions can be defined in their own file and
44 referenced with::
43 root.
44
45 In order to place them under direct user management, ``[usersubs]`` and
46 ``[reposubs]`` sections may be placed in a separate ``hgrc`` file and
47 incorporated by reference::
45 48
46 49 [notify]
47 50 config = /path/to/subscriptionsfile
48 51
49 Alternatively, they can be added to Mercurial configuration files by
50 setting the previous entry to an empty value.
51
52 At this point, notifications should be generated but will not be sent until you
53 set the ``notify.test`` entry to ``False``.
52 Notifications will not be sent until the ``notify.test`` value is set
53 to ``False``; see below.
54 54
55 55 Notifications content can be tweaked with the following configuration entries:
56 56
57 57 notify.test
58 58 If ``True``, print messages to stdout instead of sending them. Default: True.
59 59
60 60 notify.sources
61 Space separated list of change sources. Notifications are sent only
62 if it includes the incoming or outgoing changes source. Incoming
63 sources can be ``serve`` for changes coming from http or ssh,
64 ``pull`` for pulled changes, ``unbundle`` for changes added by
65 :hg:`unbundle` or ``push`` for changes being pushed
66 locally. Outgoing sources are the same except for ``unbundle`` which
67 is replaced by ``bundle``. Default: serve.
61 Space-separated list of change sources. Notifications are activated only
62 when a changeset's source is in this list. Sources may be:
63
64 :``serve``: changesets received via http or ssh
65 :``pull``: changesets received via ``hg pull``
66 :``unbundle``: changesets received via ``hg unbundle``
67 :``push``: changesets sent or received via ``hg push``
68 :``bundle``: changesets sent via ``hg unbundle``
69
70 Default: serve.
68 71
69 72 notify.strip
70 73 Number of leading slashes to strip from url paths. By default, notifications
71 references repositories with their absolute path. ``notify.strip`` let you
74 reference repositories with their absolute path. ``notify.strip`` lets you
72 75 turn them into relative paths. For example, ``notify.strip=3`` will change
73 76 ``/long/path/repository`` into ``repository``. Default: 0.
74 77
75 78 notify.domain
76 If subscribers emails or the from email have no domain set, complete them
77 with this value.
79 Default email domain for sender or recipients with no explicit domain.
78 80
79 81 notify.style
80 82 Style file to use when formatting emails.
81 83
82 84 notify.template
83 85 Template to use when formatting emails.
84 86
85 87 notify.incoming
86 Template to use when run as incoming hook, override ``notify.template``.
88 Template to use when run as an incoming hook, overriding ``notify.template``.
87 89
88 90 notify.outgoing
89 Template to use when run as outgoing hook, override ``notify.template``.
91 Template to use when run as an outgoing hook, overriding ``notify.template``.
90 92
91 93 notify.changegroup
92 Template to use when running as changegroup hook, override
94 Template to use when running as a changegroup hook, overriding
93 95 ``notify.template``.
94 96
95 97 notify.maxdiff
96 98 Maximum number of diff lines to include in notification email. Set to 0
97 to disable the diff, -1 to include all of it. Default: 300.
99 to disable the diff, or -1 to include all of it. Default: 300.
98 100
99 101 notify.maxsubject
100 Maximum number of characters in emails subject line. Default: 67.
102 Maximum number of characters in email's subject line. Default: 67.
101 103
102 104 notify.diffstat
103 105 Set to True to include a diffstat before diff content. Default: True.
104 106
105 107 notify.merge
106 108 If True, send notifications for merge changesets. Default: True.
107 109
108 110 notify.mbox
109 111 If set, append mails to this mbox file instead of sending. Default: None.
110 112
111 113 notify.fromauthor
112 If set, use the first committer of the changegroup for the "From" field of
113 the notification mail. If not set, take the user from the pushing repo.
114 Default: False.
114 If set, use the committer of the first changeset in a changegroup for
115 the "From" field of the notification mail. If not set, take the user
116 from the pushing repo. Default: False.
115 117
116 If set, the following entries will also be used to customize the notifications:
118 If set, the following entries will also be used to customize the
119 notifications:
117 120
118 121 email.from
119 Email ``From`` address to use if none can be found in generated email content.
122 Email ``From`` address to use if none can be found in the generated
123 email content.
120 124
121 125 web.baseurl
122 Root repository browsing URL to combine with repository paths when making
126 Root repository URL to combine with repository paths when making
123 127 references. See also ``notify.strip``.
124 128
125 129 '''
126 130
127 131 from mercurial.i18n import _
128 132 from mercurial import patch, cmdutil, templater, util, mail
129 133 import email.Parser, email.Errors, fnmatch, socket, time
130 134
131 135 # template for single changeset can include email headers.
132 136 single_template = '''
133 137 Subject: changeset in {webroot}: {desc|firstline|strip}
134 138 From: {author}
135 139
136 140 changeset {node|short} in {root}
137 141 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
138 142 description:
139 143 \t{desc|tabindent|strip}
140 144 '''.lstrip()
141 145
142 146 # template for multiple changesets should not contain email headers,
143 147 # because only first set of headers will be used and result will look
144 148 # strange.
145 149 multiple_template = '''
146 150 changeset {node|short} in {root}
147 151 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
148 152 summary: {desc|firstline}
149 153 '''
150 154
151 155 deftemplates = {
152 156 'changegroup': multiple_template,
153 157 }
154 158
155 159 class notifier(object):
156 160 '''email notification class.'''
157 161
158 162 def __init__(self, ui, repo, hooktype):
159 163 self.ui = ui
160 164 cfg = self.ui.config('notify', 'config')
161 165 if cfg:
162 166 self.ui.readconfig(cfg, sections=['usersubs', 'reposubs'])
163 167 self.repo = repo
164 168 self.stripcount = int(self.ui.config('notify', 'strip', 0))
165 169 self.root = self.strip(self.repo.root)
166 170 self.domain = self.ui.config('notify', 'domain')
167 171 self.mbox = self.ui.config('notify', 'mbox')
168 172 self.test = self.ui.configbool('notify', 'test', True)
169 173 self.charsets = mail._charsets(self.ui)
170 174 self.subs = self.subscribers()
171 175 self.merge = self.ui.configbool('notify', 'merge', True)
172 176
173 177 mapfile = self.ui.config('notify', 'style')
174 178 template = (self.ui.config('notify', hooktype) or
175 179 self.ui.config('notify', 'template'))
176 180 self.t = cmdutil.changeset_templater(self.ui, self.repo,
177 181 False, None, mapfile, False)
178 182 if not mapfile and not template:
179 183 template = deftemplates.get(hooktype) or single_template
180 184 if template:
181 185 template = templater.parsestring(template, quoted=False)
182 186 self.t.use_template(template)
183 187
184 188 def strip(self, path):
185 189 '''strip leading slashes from local path, turn into web-safe path.'''
186 190
187 191 path = util.pconvert(path)
188 192 count = self.stripcount
189 193 while count > 0:
190 194 c = path.find('/')
191 195 if c == -1:
192 196 break
193 197 path = path[c + 1:]
194 198 count -= 1
195 199 return path
196 200
197 201 def fixmail(self, addr):
198 202 '''try to clean up email addresses.'''
199 203
200 204 addr = util.email(addr.strip())
201 205 if self.domain:
202 206 a = addr.find('@localhost')
203 207 if a != -1:
204 208 addr = addr[:a]
205 209 if '@' not in addr:
206 210 return addr + '@' + self.domain
207 211 return addr
208 212
209 213 def subscribers(self):
210 214 '''return list of email addresses of subscribers to this repo.'''
211 215 subs = set()
212 216 for user, pats in self.ui.configitems('usersubs'):
213 217 for pat in pats.split(','):
214 218 if fnmatch.fnmatch(self.repo.root, pat.strip()):
215 219 subs.add(self.fixmail(user))
216 220 for pat, users in self.ui.configitems('reposubs'):
217 221 if fnmatch.fnmatch(self.repo.root, pat):
218 222 for user in users.split(','):
219 223 subs.add(self.fixmail(user))
220 224 return [mail.addressencode(self.ui, s, self.charsets, self.test)
221 225 for s in sorted(subs)]
222 226
223 227 def node(self, ctx, **props):
224 228 '''format one changeset, unless it is a suppressed merge.'''
225 229 if not self.merge and len(ctx.parents()) > 1:
226 230 return False
227 231 self.t.show(ctx, changes=ctx.changeset(),
228 232 baseurl=self.ui.config('web', 'baseurl'),
229 233 root=self.repo.root, webroot=self.root, **props)
230 234 return True
231 235
232 236 def skipsource(self, source):
233 237 '''true if incoming changes from this source should be skipped.'''
234 238 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
235 239 return source not in ok_sources
236 240
237 241 def send(self, ctx, count, data):
238 242 '''send message.'''
239 243
240 244 p = email.Parser.Parser()
241 245 try:
242 246 msg = p.parsestr(data)
243 247 except email.Errors.MessageParseError, inst:
244 248 raise util.Abort(inst)
245 249
246 250 # store sender and subject
247 251 sender, subject = msg['From'], msg['Subject']
248 252 del msg['From'], msg['Subject']
249 253
250 254 if not msg.is_multipart():
251 255 # create fresh mime message from scratch
252 256 # (multipart templates must take care of this themselves)
253 257 headers = msg.items()
254 258 payload = msg.get_payload()
255 259 # for notification prefer readability over data precision
256 260 msg = mail.mimeencode(self.ui, payload, self.charsets, self.test)
257 261 # reinstate custom headers
258 262 for k, v in headers:
259 263 msg[k] = v
260 264
261 265 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
262 266
263 267 # try to make subject line exist and be useful
264 268 if not subject:
265 269 if count > 1:
266 270 subject = _('%s: %d new changesets') % (self.root, count)
267 271 else:
268 272 s = ctx.description().lstrip().split('\n', 1)[0].rstrip()
269 273 subject = '%s: %s' % (self.root, s)
270 274 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
271 275 if maxsubject:
272 276 subject = util.ellipsis(subject, maxsubject)
273 277 msg['Subject'] = mail.headencode(self.ui, subject,
274 278 self.charsets, self.test)
275 279
276 280 # try to make message have proper sender
277 281 if not sender:
278 282 sender = self.ui.config('email', 'from') or self.ui.username()
279 283 if '@' not in sender or '@localhost' in sender:
280 284 sender = self.fixmail(sender)
281 285 msg['From'] = mail.addressencode(self.ui, sender,
282 286 self.charsets, self.test)
283 287
284 288 msg['X-Hg-Notification'] = 'changeset %s' % ctx
285 289 if not msg['Message-Id']:
286 290 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
287 291 (ctx, int(time.time()),
288 292 hash(self.repo.root), socket.getfqdn()))
289 293 msg['To'] = ', '.join(self.subs)
290 294
291 295 msgtext = msg.as_string()
292 296 if self.test:
293 297 self.ui.write(msgtext)
294 298 if not msgtext.endswith('\n'):
295 299 self.ui.write('\n')
296 300 else:
297 301 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
298 302 (len(self.subs), count))
299 303 mail.sendmail(self.ui, util.email(msg['From']),
300 304 self.subs, msgtext, mbox=self.mbox)
301 305
302 306 def diff(self, ctx, ref=None):
303 307
304 308 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
305 309 prev = ctx.p1().node()
306 310 ref = ref and ref.node() or ctx.node()
307 311 chunks = patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui))
308 312 difflines = ''.join(chunks).splitlines()
309 313
310 314 if self.ui.configbool('notify', 'diffstat', True):
311 315 s = patch.diffstat(difflines)
312 316 # s may be nil, don't include the header if it is
313 317 if s:
314 318 self.ui.write('\ndiffstat:\n\n%s' % s)
315 319
316 320 if maxdiff == 0:
317 321 return
318 322 elif maxdiff > 0 and len(difflines) > maxdiff:
319 323 msg = _('\ndiffs (truncated from %d to %d lines):\n\n')
320 324 self.ui.write(msg % (len(difflines), maxdiff))
321 325 difflines = difflines[:maxdiff]
322 326 elif difflines:
323 327 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
324 328
325 329 self.ui.write("\n".join(difflines))
326 330
327 331 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
328 332 '''send email notifications to interested subscribers.
329 333
330 334 if used as changegroup hook, send one email for all changesets in
331 335 changegroup. else send one email per changeset.'''
332 336
333 337 n = notifier(ui, repo, hooktype)
334 338 ctx = repo[node]
335 339
336 340 if not n.subs:
337 341 ui.debug('notify: no subscribers to repository %s\n' % n.root)
338 342 return
339 343 if n.skipsource(source):
340 344 ui.debug('notify: changes have source "%s" - skipping\n' % source)
341 345 return
342 346
343 347 ui.pushbuffer()
344 348 data = ''
345 349 count = 0
346 350 author = ''
347 351 if hooktype == 'changegroup' or hooktype == 'outgoing':
348 352 start, end = ctx.rev(), len(repo)
349 353 for rev in xrange(start, end):
350 354 if n.node(repo[rev]):
351 355 count += 1
352 356 if not author:
353 357 author = repo[rev].user()
354 358 else:
355 359 data += ui.popbuffer()
356 360 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
357 361 (rev, repo[rev].hex()[:12]))
358 362 ui.pushbuffer()
359 363 if count:
360 364 n.diff(ctx, repo['tip'])
361 365 else:
362 366 if not n.node(ctx):
363 367 ui.popbuffer()
364 368 ui.note(_('notify: suppressing notification for merge %d:%s\n') %
365 369 (ctx.rev(), ctx.hex()[:12]))
366 370 return
367 371 count += 1
368 372 n.diff(ctx)
369 373
370 374 data += ui.popbuffer()
371 375 fromauthor = ui.config('notify', 'fromauthor')
372 376 if author and fromauthor:
373 377 data = '\n'.join(['From: %s' % author, data])
374 378
375 379 if count:
376 380 n.send(ctx, count, data)
@@ -1,469 +1,475 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 This extension let you run hooks sending email notifications when changesets
23 are being pushed, from the sending or receiving side.
22 This extension implements hooks to send email notifications when changesets
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 the hook you want to run. "incoming" and "changegroup" hooks are run by the
27 changesets receiver while the "outgoing" one is for the sender:
26 the hook you want to run. "incoming" and "changegroup" hooks are run when
27 changesets are received, while "outgoing" hooks are for changesets sent to
28 another repository:
28 29
29 30 [hooks]
30 31 # one email for each incoming changeset
31 32 incoming.notify = python:hgext.notify.hook
32 33 # one email for all incoming changesets
33 34 changegroup.notify = python:hgext.notify.hook
34 35
35 36 # one email for all outgoing changesets
36 37 outgoing.notify = python:hgext.notify.hook
37 38
38 Now the hooks are running, subscribers must be assigned to repositories. Use
39 the "[usersubs]" section to map repositories to a given email or the
40 "[reposubs]" section to map emails to a single repository:
39 This registers the hooks. To enable notification, subscribers must be assigned
40 to repositories. The "[usersubs]" section maps multiple repositories to a
41 given recipient. The "[reposubs]" section maps multiple recipients to a single
42 repository:
41 43
42 44 [usersubs]
43 # key is subscriber email, value is a comma-separated list of glob
45 # key is subscriber email, value is a comma-separated list of repo glob
44 46 # patterns
45 47 user@host = pattern
46 48
47 49 [reposubs]
48 50 # key is glob pattern, value is a comma-separated list of subscriber
49 51 # emails
50 52 pattern = user@host
51 53
52 Glob patterns are matched against absolute path to repository root. The
53 subscriptions can be defined in their own file and referenced with:
54 Glob patterns are matched against absolute path to repository root.
55
56 In order to place them under direct user management, "[usersubs]" and
57 "[reposubs]" sections may be placed in a separate "hgrc" file and incorporated
58 by reference:
54 59
55 60 [notify]
56 61 config = /path/to/subscriptionsfile
57 62
58 Alternatively, they can be added to Mercurial configuration files by setting
59 the previous entry to an empty value.
60
61 At this point, notifications should be generated but will not be sent until
62 you set the "notify.test" entry to "False".
63 Notifications will not be sent until the "notify.test" value is set to
64 "False"; see below.
63 65
64 66 Notifications content can be tweaked with the following configuration entries:
65 67
66 68 notify.test
67 69 If "True", print messages to stdout instead of sending them. Default: True.
68 70
69 71 notify.sources
70 Space separated list of change sources. Notifications are sent only if it
71 includes the incoming or outgoing changes source. Incoming sources can be
72 "serve" for changes coming from http or ssh, "pull" for pulled changes,
73 "unbundle" for changes added by "hg unbundle" or "push" for changes being
74 pushed locally. Outgoing sources are the same except for "unbundle" which is
75 replaced by "bundle". Default: serve.
72 Space-separated list of change sources. Notifications are activated only
73 when a changeset's source is in this list. Sources may be:
74
75 "serve" changesets received via http or ssh
76 "pull" changesets received via "hg pull"
77 "unbundle" changesets received via "hg unbundle"
78 "push" changesets sent or received via "hg push"
79 "bundle" changesets sent via "hg unbundle"
80
81 Default: serve.
76 82
77 83 notify.strip
78 84 Number of leading slashes to strip from url paths. By default, notifications
79 references repositories with their absolute path. "notify.strip" let you
85 reference repositories with their absolute path. "notify.strip" lets you
80 86 turn them into relative paths. For example, "notify.strip=3" will change
81 87 "/long/path/repository" into "repository". Default: 0.
82 88
83 89 notify.domain
84 If subscribers emails or the from email have no domain set, complete them
85 with this value.
90 Default email domain for sender or recipients with no explicit domain.
86 91
87 92 notify.style
88 93 Style file to use when formatting emails.
89 94
90 95 notify.template
91 96 Template to use when formatting emails.
92 97
93 98 notify.incoming
94 Template to use when run as incoming hook, override "notify.template".
99 Template to use when run as an incoming hook, overriding "notify.template".
95 100
96 101 notify.outgoing
97 Template to use when run as outgoing hook, override "notify.template".
102 Template to use when run as an outgoing hook, overriding "notify.template".
98 103
99 104 notify.changegroup
100 Template to use when running as changegroup hook, override
105 Template to use when running as a changegroup hook, overriding
101 106 "notify.template".
102 107
103 108 notify.maxdiff
104 109 Maximum number of diff lines to include in notification email. Set to 0 to
105 disable the diff, -1 to include all of it. Default: 300.
110 disable the diff, or -1 to include all of it. Default: 300.
106 111
107 112 notify.maxsubject
108 Maximum number of characters in emails subject line. Default: 67.
113 Maximum number of characters in email's subject line. Default: 67.
109 114
110 115 notify.diffstat
111 116 Set to True to include a diffstat before diff content. Default: True.
112 117
113 118 notify.merge
114 119 If True, send notifications for merge changesets. Default: True.
115 120
116 121 notify.mbox
117 122 If set, append mails to this mbox file instead of sending. Default: None.
118 123
119 124 notify.fromauthor
120 If set, use the first committer of the changegroup for the "From" field of
121 the notification mail. If not set, take the user from the pushing repo.
122 Default: False.
125 If set, use the committer of the first changeset in a changegroup for the
126 "From" field of the notification mail. If not set, take the user from the
127 pushing repo. Default: False.
123 128
124 129 If set, the following entries will also be used to customize the
125 130 notifications:
126 131
127 132 email.from
128 Email "From" address to use if none can be found in generated email content.
133 Email "From" address to use if none can be found in the generated email
134 content.
129 135
130 136 web.baseurl
131 Root repository browsing URL to combine with repository paths when making
132 references. See also "notify.strip".
137 Root repository URL to combine with repository paths when making references.
138 See also "notify.strip".
133 139
134 140 no commands defined
135 141 $ hg init a
136 142 $ echo a > a/a
137 143
138 144 commit
139 145
140 146 $ hg --cwd a commit -Ama -d '0 0'
141 147 adding a
142 148
143 149
144 150 clone
145 151
146 152 $ hg --traceback clone a b
147 153 updating to branch default
148 154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
149 155 $ echo a >> a/a
150 156
151 157 commit
152 158
153 159 $ hg --traceback --cwd a commit -Amb -d '1 0'
154 160
155 161 on Mac OS X 10.5 the tmp path is very long so would get stripped in the subject line
156 162
157 163 $ cat <<EOF >> $HGRCPATH
158 164 > [notify]
159 165 > maxsubject = 200
160 166 > EOF
161 167
162 168 the python call below wraps continuation lines, which appear on Mac OS X 10.5 because
163 169 of the very long subject line
164 170 pull (minimal config)
165 171
166 172 $ hg --traceback --cwd b pull ../a | \
167 173 > python -c 'import sys,re; print re.sub("\n[\t ]", " ", sys.stdin.read()),'
168 174 pulling from ../a
169 175 searching for changes
170 176 adding changesets
171 177 adding manifests
172 178 adding file changes
173 179 added 1 changesets with 1 changes to 1 files
174 180 Content-Type: text/plain; charset="us-ascii"
175 181 MIME-Version: 1.0
176 182 Content-Transfer-Encoding: 7bit
177 183 Date: * (glob)
178 184 Subject: changeset in $TESTTMP/b: b
179 185 From: test
180 186 X-Hg-Notification: changeset 0647d048b600
181 187 Message-Id: <*> (glob)
182 188 To: baz, foo@bar
183 189
184 190 changeset 0647d048b600 in $TESTTMP/b (glob)
185 191 details: $TESTTMP/b?cmd=changeset;node=0647d048b600
186 192 description: b
187 193
188 194 diffs (6 lines):
189 195
190 196 diff -r cb9a9f314b8b -r 0647d048b600 a
191 197 --- a/a Thu Jan 01 00:00:00 1970 +0000
192 198 +++ b/a Thu Jan 01 00:00:01 1970 +0000
193 199 @@ -1,1 +1,2 @@ a
194 200 +a
195 201 (run 'hg update' to get a working copy)
196 202 $ cat <<EOF >> $HGRCPATH
197 203 > [notify]
198 204 > config = `pwd`/.notify.conf
199 205 > domain = test.com
200 206 > strip = 42
201 207 > template = Subject: {desc|firstline|strip}\nFrom: {author}\nX-Test: foo\n\nchangeset {node|short} in {webroot}\ndescription:\n\t{desc|tabindent|strip}
202 208 >
203 209 > [web]
204 210 > baseurl = http://test/
205 211 > EOF
206 212
207 213 fail for config file is missing
208 214
209 215 $ hg --cwd b rollback
210 216 repository tip rolled back to revision 0 (undo pull)
211 217 $ hg --cwd b pull ../a 2>&1 | grep 'error.*\.notify\.conf' > /dev/null && echo pull failed
212 218 pull failed
213 219 $ touch ".notify.conf"
214 220
215 221 pull
216 222
217 223 $ hg --cwd b rollback
218 224 repository tip rolled back to revision 0 (undo pull)
219 225 $ hg --traceback --cwd b pull ../a | \
220 226 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
221 227 pulling from ../a
222 228 searching for changes
223 229 adding changesets
224 230 adding manifests
225 231 adding file changes
226 232 added 1 changesets with 1 changes to 1 files
227 233 Content-Type: text/plain; charset="us-ascii"
228 234 MIME-Version: 1.0
229 235 Content-Transfer-Encoding: 7bit
230 236 X-Test: foo
231 237 Date: * (glob)
232 238 Subject: b
233 239 From: test@test.com
234 240 X-Hg-Notification: changeset 0647d048b600
235 241 Message-Id: <*> (glob)
236 242 To: baz@test.com, foo@bar
237 243
238 244 changeset 0647d048b600 in b
239 245 description: b
240 246 diffs (6 lines):
241 247
242 248 diff -r cb9a9f314b8b -r 0647d048b600 a
243 249 --- a/a Thu Jan 01 00:00:00 1970 +0000
244 250 +++ b/a Thu Jan 01 00:00:01 1970 +0000
245 251 @@ -1,1 +1,2 @@
246 252 a
247 253 +a
248 254 (run 'hg update' to get a working copy)
249 255
250 256 $ cat << EOF >> $HGRCPATH
251 257 > [hooks]
252 258 > incoming.notify = python:hgext.notify.hook
253 259 >
254 260 > [notify]
255 261 > sources = pull
256 262 > diffstat = True
257 263 > EOF
258 264
259 265 pull
260 266
261 267 $ hg --cwd b rollback
262 268 repository tip rolled back to revision 0 (undo pull)
263 269 $ hg --traceback --cwd b pull ../a | \
264 270 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
265 271 pulling from ../a
266 272 searching for changes
267 273 adding changesets
268 274 adding manifests
269 275 adding file changes
270 276 added 1 changesets with 1 changes to 1 files
271 277 Content-Type: text/plain; charset="us-ascii"
272 278 MIME-Version: 1.0
273 279 Content-Transfer-Encoding: 7bit
274 280 X-Test: foo
275 281 Date: * (glob)
276 282 Subject: b
277 283 From: test@test.com
278 284 X-Hg-Notification: changeset 0647d048b600
279 285 Message-Id: <*> (glob)
280 286 To: baz@test.com, foo@bar
281 287
282 288 changeset 0647d048b600 in b
283 289 description: b
284 290 diffstat:
285 291
286 292 a | 1 +
287 293 1 files changed, 1 insertions(+), 0 deletions(-)
288 294
289 295 diffs (6 lines):
290 296
291 297 diff -r cb9a9f314b8b -r 0647d048b600 a
292 298 --- a/a Thu Jan 01 00:00:00 1970 +0000
293 299 +++ b/a Thu Jan 01 00:00:01 1970 +0000
294 300 @@ -1,1 +1,2 @@
295 301 a
296 302 +a
297 303 (run 'hg update' to get a working copy)
298 304
299 305 test merge
300 306
301 307 $ cd a
302 308 $ hg up -C 0
303 309 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 310 $ echo a >> a
305 311 $ hg ci -Am adda2 -d '2 0'
306 312 created new head
307 313 $ hg merge
308 314 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 315 (branch merge, don't forget to commit)
310 316 $ hg ci -m merge -d '3 0'
311 317 $ cd ..
312 318 $ hg --traceback --cwd b pull ../a | \
313 319 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
314 320 pulling from ../a
315 321 searching for changes
316 322 adding changesets
317 323 adding manifests
318 324 adding file changes
319 325 added 2 changesets with 0 changes to 0 files
320 326 Content-Type: text/plain; charset="us-ascii"
321 327 MIME-Version: 1.0
322 328 Content-Transfer-Encoding: 7bit
323 329 X-Test: foo
324 330 Date: * (glob)
325 331 Subject: adda2
326 332 From: test@test.com
327 333 X-Hg-Notification: changeset 0a184ce6067f
328 334 Message-Id: <*> (glob)
329 335 To: baz@test.com, foo@bar
330 336
331 337 changeset 0a184ce6067f in b
332 338 description: adda2
333 339 diffstat:
334 340
335 341 a | 1 +
336 342 1 files changed, 1 insertions(+), 0 deletions(-)
337 343
338 344 diffs (6 lines):
339 345
340 346 diff -r cb9a9f314b8b -r 0a184ce6067f a
341 347 --- a/a Thu Jan 01 00:00:00 1970 +0000
342 348 +++ b/a Thu Jan 01 00:00:02 1970 +0000
343 349 @@ -1,1 +1,2 @@
344 350 a
345 351 +a
346 352 Content-Type: text/plain; charset="us-ascii"
347 353 MIME-Version: 1.0
348 354 Content-Transfer-Encoding: 7bit
349 355 X-Test: foo
350 356 Date: * (glob)
351 357 Subject: merge
352 358 From: test@test.com
353 359 X-Hg-Notification: changeset 6a0cf76b2701
354 360 Message-Id: <*> (glob)
355 361 To: baz@test.com, foo@bar
356 362
357 363 changeset 6a0cf76b2701 in b
358 364 description: merge
359 365 (run 'hg update' to get a working copy)
360 366
361 367 non-ascii content and truncation of multi-byte subject
362 368
363 369 $ cat <<EOF >> $HGRCPATH
364 370 > [notify]
365 371 > maxsubject = 4
366 372 > EOF
367 373 $ echo a >> a/a
368 374 $ hg --cwd a --encoding utf-8 commit -A -d '0 0' \
369 375 > -m `python -c 'print "\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4"'`
370 376 $ hg --traceback --cwd b --encoding utf-8 pull ../a | \
371 377 > python -c 'import sys,re; print re.sub("\n\t", " ", sys.stdin.read()),'
372 378 pulling from ../a
373 379 searching for changes
374 380 adding changesets
375 381 adding manifests
376 382 adding file changes
377 383 added 1 changesets with 1 changes to 1 files
378 384 Content-Type: text/plain; charset="us-ascii"
379 385 MIME-Version: 1.0
380 386 Content-Transfer-Encoding: 8bit
381 387 X-Test: foo
382 388 Date: * (glob)
383 389 Subject: \xc3\xa0... (esc)
384 390 From: test@test.com
385 391 X-Hg-Notification: changeset 7ea05ad269dc
386 392 Message-Id: <*> (glob)
387 393 To: baz@test.com, foo@bar
388 394
389 395 changeset 7ea05ad269dc in b
390 396 description: \xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4 (esc)
391 397 diffstat:
392 398
393 399 a | 1 +
394 400 1 files changed, 1 insertions(+), 0 deletions(-)
395 401
396 402 diffs (7 lines):
397 403
398 404 diff -r 6a0cf76b2701 -r 7ea05ad269dc a
399 405 --- a/a Thu Jan 01 00:00:03 1970 +0000
400 406 +++ b/a Thu Jan 01 00:00:00 1970 +0000
401 407 @@ -1,2 +1,3 @@
402 408 a
403 409 a
404 410 +a
405 411 (run 'hg update' to get a working copy)
406 412
407 413 long lines
408 414
409 415 $ cat <<EOF >> $HGRCPATH
410 416 > [notify]
411 417 > maxsubject = 67
412 418 > test = False
413 419 > mbox = mbox
414 420 > EOF
415 421 $ python -c 'file("a/a", "ab").write("no" * 500 + "\n")'
416 422 $ hg --cwd a commit -A -m "long line"
417 423 $ hg --traceback --cwd b pull ../a
418 424 pulling from ../a
419 425 searching for changes
420 426 adding changesets
421 427 adding manifests
422 428 adding file changes
423 429 added 1 changesets with 1 changes to 1 files
424 430 notify: sending 2 subscribers 1 changes
425 431 (run 'hg update' to get a working copy)
426 432 $ python -c 'import sys,re; print re.sub("\n\t", " ", file("b/mbox").read()),'
427 433 From test@test.com ... ... .. ..:..:.. .... (re)
428 434 Content-Type: text/plain; charset="us-ascii"
429 435 MIME-Version: 1.0
430 436 Content-Transfer-Encoding: quoted-printable
431 437 X-Test: foo
432 438 Date: * (glob)
433 439 Subject: long line
434 440 From: test@test.com
435 441 X-Hg-Notification: changeset e0be44cf638b
436 442 Message-Id: <hg.e0be44cf638b.*.*@*> (glob)
437 443 To: baz@test.com, foo@bar
438 444
439 445 changeset e0be44cf638b in b
440 446 description: long line
441 447 diffstat:
442 448
443 449 a | 1 +
444 450 1 files changed, 1 insertions(+), 0 deletions(-)
445 451
446 452 diffs (8 lines):
447 453
448 454 diff -r 7ea05ad269dc -r e0be44cf638b a
449 455 --- a/a Thu Jan 01 00:00:00 1970 +0000
450 456 +++ b/a Thu Jan 01 00:00:00 1970 +0000
451 457 @@ -1,3 +1,4 @@
452 458 a
453 459 a
454 460 a
455 461 +nonononononononononononononononononononononononononononononononononononono=
456 462 nononononononononononononononononononononononononononononononononononononon=
457 463 ononononononononononononononononononononononononononononononononononononono=
458 464 nononononononononononononononononononononononononononononononononononononon=
459 465 ononononononononononononononononononononononononononononononononononononono=
460 466 nononononononononononononononononononononononononononononononononononononon=
461 467 ononononononononononononononononononononononononononononononononononononono=
462 468 nononononononononononononononononononononononononononononononononononononon=
463 469 ononononononononononononononononononononononononononononononononononononono=
464 470 nononononononononononononononononononononononononononononononononononononon=
465 471 ononononononononononononononononononononononononononononononononononononono=
466 472 nononononononononononononononononononononononononononononononononononononon=
467 473 ononononononononononononononononononononononononononononononononononononono=
468 474 nonononononononononononono
469 475
General Comments 0
You need to be logged in to leave comments. Login now