##// END OF EJS Templates
notify: mime-encode messages...
Christian Ebert -
r7116:e981725d default
parent child Browse files
Show More
@@ -1,283 +1,288
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
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7 #
8 8 # hook extension to email notifications to people when changesets are
9 9 # committed to a repo they subscribe to.
10 10 #
11 11 # default mode is to print messages to stdout, for testing and
12 12 # configuring.
13 13 #
14 14 # to use, configure notify extension and enable in hgrc like this:
15 15 #
16 16 # [extensions]
17 17 # hgext.notify =
18 18 #
19 19 # [hooks]
20 20 # # one email for each incoming changeset
21 21 # incoming.notify = python:hgext.notify.hook
22 22 # # batch emails when many changesets incoming at one time
23 23 # changegroup.notify = python:hgext.notify.hook
24 24 #
25 25 # [notify]
26 26 # # config items go in here
27 27 #
28 28 # config items:
29 29 #
30 30 # REQUIRED:
31 31 # config = /path/to/file # file containing subscriptions
32 32 #
33 33 # OPTIONAL:
34 34 # test = True # print messages to stdout for testing
35 35 # strip = 3 # number of slashes to strip for url paths
36 36 # domain = example.com # domain to use if committer missing domain
37 37 # style = ... # style file to use when formatting email
38 38 # template = ... # template to use when formatting email
39 39 # incoming = ... # template to use when run as incoming hook
40 40 # changegroup = ... # template when run as changegroup hook
41 41 # maxdiff = 300 # max lines of diffs to include (0=none, -1=all)
42 42 # maxsubject = 67 # truncate subject line longer than this
43 43 # diffstat = True # add a diffstat before the diff content
44 44 # sources = serve # notify if source of incoming changes in this list
45 45 # # (serve == ssh or http, push, pull, bundle)
46 46 # [email]
47 47 # from = user@host.com # email address to send as if none given
48 48 # [web]
49 49 # baseurl = http://hgserver/... # root of hg web site for browsing commits
50 50 #
51 51 # notify config file has same format as regular hgrc. it has two
52 52 # sections so you can express subscriptions in whatever way is handier
53 53 # for you.
54 54 #
55 55 # [usersubs]
56 56 # # key is subscriber email, value is ","-separated list of glob patterns
57 57 # user@host = pattern
58 58 #
59 59 # [reposubs]
60 60 # # key is glob pattern, value is ","-separated list of subscriber emails
61 61 # pattern = user@host
62 62 #
63 63 # glob patterns are matched against path to repo root.
64 64 #
65 65 # if you like, you can put notify config file in repo that users can
66 66 # push changes to, they can manage their own subscriptions.
67 67
68 68 from mercurial.i18n import _
69 69 from mercurial.node import bin, short
70 70 from mercurial import patch, cmdutil, templater, util, mail
71 71 import email.Parser, fnmatch, socket, time
72 72
73 73 # template for single changeset can include email headers.
74 74 single_template = '''
75 75 Subject: changeset in {webroot}: {desc|firstline|strip}
76 76 From: {author}
77 77
78 78 changeset {node|short} in {root}
79 79 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
80 80 description:
81 81 \t{desc|tabindent|strip}
82 82 '''.lstrip()
83 83
84 84 # template for multiple changesets should not contain email headers,
85 85 # because only first set of headers will be used and result will look
86 86 # strange.
87 87 multiple_template = '''
88 88 changeset {node|short} in {root}
89 89 details: {baseurl}{webroot}?cmd=changeset;node={node|short}
90 90 summary: {desc|firstline}
91 91 '''
92 92
93 93 deftemplates = {
94 94 'changegroup': multiple_template,
95 95 }
96 96
97 97 class notifier(object):
98 98 '''email notification class.'''
99 99
100 100 def __init__(self, ui, repo, hooktype):
101 101 self.ui = ui
102 102 cfg = self.ui.config('notify', 'config')
103 103 if cfg:
104 104 self.ui.readsections(cfg, 'usersubs', 'reposubs')
105 105 self.repo = repo
106 106 self.stripcount = int(self.ui.config('notify', 'strip', 0))
107 107 self.root = self.strip(self.repo.root)
108 108 self.domain = self.ui.config('notify', 'domain')
109 self.charsets = mail._charsets(self.ui)
109 110 self.subs = self.subscribers()
110 111
111 112 mapfile = self.ui.config('notify', 'style')
112 113 template = (self.ui.config('notify', hooktype) or
113 114 self.ui.config('notify', 'template'))
114 115 self.t = cmdutil.changeset_templater(self.ui, self.repo,
115 116 False, mapfile, False)
116 117 if not mapfile and not template:
117 118 template = deftemplates.get(hooktype) or single_template
118 119 if template:
119 120 template = templater.parsestring(template, quoted=False)
120 121 self.t.use_template(template)
121 122
122 123 def strip(self, path):
123 124 '''strip leading slashes from local path, turn into web-safe path.'''
124 125
125 126 path = util.pconvert(path)
126 127 count = self.stripcount
127 128 while count > 0:
128 129 c = path.find('/')
129 130 if c == -1:
130 131 break
131 132 path = path[c+1:]
132 133 count -= 1
133 134 return path
134 135
135 136 def fixmail(self, addr):
136 137 '''try to clean up email addresses.'''
137 138
138 139 addr = util.email(addr.strip())
139 140 if self.domain:
140 141 a = addr.find('@localhost')
141 142 if a != -1:
142 143 addr = addr[:a]
143 144 if '@' not in addr:
144 145 return addr + '@' + self.domain
145 146 return addr
146 147
147 148 def subscribers(self):
148 149 '''return list of email addresses of subscribers to this repo.'''
149 150
150 151 subs = {}
151 152 for user, pats in self.ui.configitems('usersubs'):
152 153 for pat in pats.split(','):
153 154 if fnmatch.fnmatch(self.repo.root, pat.strip()):
154 155 subs[self.fixmail(user)] = 1
155 156 for pat, users in self.ui.configitems('reposubs'):
156 157 if fnmatch.fnmatch(self.repo.root, pat):
157 158 for user in users.split(','):
158 159 subs[self.fixmail(user)] = 1
159 return util.sort(subs)
160 subs = util.sort(subs)
161 return [mail.addressencode(self.ui, s, self.charsets) for s in subs]
160 162
161 163 def url(self, path=None):
162 164 return self.ui.config('web', 'baseurl') + (path or self.root)
163 165
164 166 def node(self, node):
165 167 '''format one changeset.'''
166 168
167 169 self.t.show(changenode=node, changes=self.repo.changelog.read(node),
168 170 baseurl=self.ui.config('web', 'baseurl'),
169 171 root=self.repo.root,
170 172 webroot=self.root)
171 173
172 174 def skipsource(self, source):
173 175 '''true if incoming changes from this source should be skipped.'''
174 176 ok_sources = self.ui.config('notify', 'sources', 'serve').split()
175 177 return source not in ok_sources
176 178
177 179 def send(self, node, count, data):
178 180 '''send message.'''
179 181
180 182 p = email.Parser.Parser()
181 183 msg = p.parsestr(data)
182 184
183 def fix_subject():
185 # store sender and subject
186 sender, subject = msg['From'], msg['Subject']
187 # create fresh mime message from msg body
188 text = msg.get_payload()
189 # for notification prefer readability over data precision
190 msg = mail.mimeencode(self.ui, text, self.charsets)
191
192 def fix_subject(subject):
184 193 '''try to make subject line exist and be useful.'''
185 194
186 subject = msg['Subject']
187 195 if not subject:
188 196 if count > 1:
189 197 subject = _('%s: %d new changesets') % (self.root, count)
190 198 else:
191 199 changes = self.repo.changelog.read(node)
192 200 s = changes[4].lstrip().split('\n', 1)[0].rstrip()
193 201 subject = '%s: %s' % (self.root, s)
194 202 maxsubject = int(self.ui.config('notify', 'maxsubject', 67))
195 203 if maxsubject and len(subject) > maxsubject:
196 204 subject = subject[:maxsubject-3] + '...'
197 del msg['Subject']
198 msg['Subject'] = subject
205 msg['Subject'] = mail.headencode(self.ui, subject, self.charsets)
199 206
200 def fix_sender():
207 def fix_sender(sender):
201 208 '''try to make message have proper sender.'''
202 209
203 sender = msg['From']
204 210 if not sender:
205 211 sender = self.ui.config('email', 'from') or self.ui.username()
206 212 if '@' not in sender or '@localhost' in sender:
207 213 sender = self.fixmail(sender)
208 del msg['From']
209 msg['From'] = sender
214 msg['From'] = mail.addressencode(self.ui, sender, self.charsets)
210 215
211 216 msg['Date'] = util.datestr(format="%a, %d %b %Y %H:%M:%S %1%2")
212 fix_subject()
213 fix_sender()
217 fix_subject(subject)
218 fix_sender(sender)
214 219
215 220 msg['X-Hg-Notification'] = 'changeset ' + short(node)
216 221 if not msg['Message-Id']:
217 222 msg['Message-Id'] = ('<hg.%s.%s.%s@%s>' %
218 223 (short(node), int(time.time()),
219 224 hash(self.repo.root), socket.getfqdn()))
220 225 msg['To'] = ', '.join(self.subs)
221 226
222 227 msgtext = msg.as_string(0)
223 228 if self.ui.configbool('notify', 'test', True):
224 229 self.ui.write(msgtext)
225 230 if not msgtext.endswith('\n'):
226 231 self.ui.write('\n')
227 232 else:
228 233 self.ui.status(_('notify: sending %d subscribers %d changes\n') %
229 234 (len(self.subs), count))
230 235 mail.sendmail(self.ui, util.email(msg['From']),
231 236 self.subs, msgtext)
232 237
233 238 def diff(self, node, ref):
234 239 maxdiff = int(self.ui.config('notify', 'maxdiff', 300))
235 240 prev = self.repo.changelog.parents(node)[0]
236 241
237 242 self.ui.pushbuffer()
238 243 patch.diff(self.repo, prev, ref, opts=patch.diffopts(self.ui))
239 244 difflines = self.ui.popbuffer().splitlines()
240 245
241 246 if self.ui.configbool('notify', 'diffstat', True):
242 247 s = patch.diffstat(difflines)
243 248 # s may be nil, don't include the header if it is
244 249 if s:
245 250 self.ui.write('\ndiffstat:\n\n%s' % s)
246 251 if maxdiff == 0:
247 252 return
248 253 if maxdiff > 0 and len(difflines) > maxdiff:
249 254 self.ui.write(_('\ndiffs (truncated from %d to %d lines):\n\n') %
250 255 (len(difflines), maxdiff))
251 256 difflines = difflines[:maxdiff]
252 257 elif difflines:
253 258 self.ui.write(_('\ndiffs (%d lines):\n\n') % len(difflines))
254 259 self.ui.write("\n".join(difflines))
255 260
256 261 def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
257 262 '''send email notifications to interested subscribers.
258 263
259 264 if used as changegroup hook, send one email for all changesets in
260 265 changegroup. else send one email per changeset.'''
261 266 n = notifier(ui, repo, hooktype)
262 267 if not n.subs:
263 268 ui.debug(_('notify: no subscribers to repo %s\n') % n.root)
264 269 return
265 270 if n.skipsource(source):
266 271 ui.debug(_('notify: changes have source "%s" - skipping\n') %
267 272 source)
268 273 return
269 274 node = bin(node)
270 275 ui.pushbuffer()
271 276 if hooktype == 'changegroup':
272 277 start = repo[node].rev()
273 278 end = len(repo)
274 279 count = end - start
275 280 for rev in xrange(start, end):
276 281 n.node(repo[rev].node())
277 282 n.diff(node, repo.changelog.tip())
278 283 else:
279 284 count = 1
280 285 n.node(node)
281 286 n.diff(node, node)
282 287 data = ui.popbuffer()
283 288 n.send(node, count, data)
@@ -1,343 +1,343
1 1 #!/bin/sh
2 2
3 3 cat <<EOF >> $HGRCPATH
4 4 [extensions]
5 5 hgext.keyword =
6 6 hgext.mq =
7 7 hgext.notify =
8 8 [keyword]
9 9 * =
10 10 b = ignore
11 11 [hooks]
12 12 commit=
13 13 commit.test=cp a hooktest
14 14 EOF
15 15
16 16 echo % help
17 17 hg help keyword
18 18
19 19 echo % hg kwdemo
20 20 hg --quiet kwdemo --default \
21 21 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
22 22 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
23 23 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
24 24 -e 's! 20[0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]! 2000/00/00 00:00:00!'
25 25
26 26 hg --quiet kwdemo "Branch = {branches}"
27 27
28 28 hg init Test-bndl
29 29 cd Test-bndl
30 30
31 31 echo % kwshrink should exit silently in empty/invalid repo
32 32 hg kwshrink
33 33
34 34 # Symlinks cannot be created on Windows. The bundle was made with:
35 35 #
36 36 # hg init t
37 37 # cd t
38 38 # echo a > a
39 39 # ln -s a sym
40 40 # hg add sym
41 41 # hg ci -m addsym -u mercurial
42 42 # hg bundle --base null ../test-keyword.hg
43 43 #
44 44 hg pull -u "$TESTDIR/test-keyword.hg" \
45 45 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
46 46
47 47 echo 'expand $Id$' > a
48 48 echo 'do not process $Id:' >> a
49 49 echo 'xxx $' >> a
50 50 echo 'ignore $Id$' > b
51 51 echo % cat
52 52 cat a b
53 53
54 54 echo % addremove
55 55 hg addremove
56 56 echo % status
57 57 hg status
58 58
59 59 echo % default keyword expansion including commit hook
60 60 echo % interrupted commit should not change state or run commit hook
61 61 hg --debug commit
62 62 echo % status
63 63 hg status
64 64
65 65 echo % commit
66 66 hg --debug commit -mabsym -d '0 0' -u 'User Name <user@example.com>'
67 67 echo % status
68 68 hg status
69 69 echo % identify
70 70 hg debugrebuildstate
71 71 hg --quiet identify
72 72 echo % cat
73 73 cat a b
74 74 echo % hg cat
75 75 hg cat sym a b
76 76
77 77 echo
78 78 echo % diff a hooktest
79 79 diff a hooktest
80 80
81 81 echo % removing commit hook from config
82 82 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nohook
83 83 mv $HGRCPATH.nohook $HGRCPATH
84 84 rm hooktest
85 85
86 86 echo % bundle
87 87 hg bundle --base null ../kw.hg
88 88
89 89 cd ..
90 90 hg init Test
91 91 cd Test
92 92
93 93 echo % notify on pull to check whether keywords stay as is in email
94 94 echo % ie. if patch.diff wrapper acts as it should
95 95
96 96 cat <<EOF >> $HGRCPATH
97 97 [hooks]
98 98 incoming.notify = python:hgext.notify.hook
99 99 [notify]
100 100 sources = pull
101 101 diffstat = False
102 102 [reposubs]
103 103 * = Test
104 104 EOF
105 105
106 106 echo % pull from bundle
107 hg pull -u ../kw.hg 2>&1 | sed -e '/^Date:/,/^diffs (/ d'
107 hg pull -u ../kw.hg 2>&1 | sed -e '/^Content-Type:/,/^diffs (/ d'
108 108
109 109 echo % remove notify config
110 110 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nonotify
111 111 mv $HGRCPATH.nonotify $HGRCPATH
112 112
113 113 echo % touch
114 114 touch a b
115 115 echo % status
116 116 hg status
117 117
118 118 rm sym a b
119 119 echo % update
120 120 hg update
121 121 echo % cat
122 122 cat a b
123 123
124 124 echo % check whether expansion is filewise
125 125 echo '$Id$' > c
126 126 echo 'tests for different changenodes' >> c
127 127 echo % commit c
128 128 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
129 129 echo % force expansion
130 130 hg -v kwexpand
131 131 echo % compare changenodes in a c
132 132 cat a c
133 133
134 134 echo % qinit -c
135 135 hg qinit -c
136 136 echo % qimport
137 137 hg qimport -r tip -n mqtest.diff
138 138 echo % qcommit
139 139 hg qcommit -mqtest
140 140 echo % keywords should not be expanded in patch
141 141 cat .hg/patches/mqtest.diff
142 142 echo % qpop
143 143 hg qpop
144 144 echo % qgoto - should imply qpush
145 145 hg qgoto mqtest.diff
146 146 echo % cat
147 147 cat c
148 148 echo % qpop and move on
149 149 hg qpop
150 150
151 151 echo % copy
152 152 hg cp a c
153 153
154 154 echo % kwfiles added
155 155 hg kwfiles
156 156
157 157 echo % commit
158 158 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
159 159 echo % cat a c
160 160 cat a c
161 161 echo % touch copied c
162 162 touch c
163 163 echo % status
164 164 hg status
165 165
166 166 echo % kwfiles
167 167 hg kwfiles
168 168
169 169 echo % diff --rev
170 170 hg diff --rev 1 | grep -v 'b/c'
171 171
172 172 echo % rollback
173 173 hg rollback
174 174 echo % status
175 175 hg status
176 176 echo % update -C
177 177 hg update --clean
178 178
179 179 echo % custom keyword expansion
180 180 echo % try with kwdemo
181 181 hg --quiet kwdemo "Xinfo = {author}: {desc}"
182 182
183 183 cat <<EOF >>$HGRCPATH
184 184 [keywordmaps]
185 185 Id = {file} {node|short} {date|rfc822date} {author|user}
186 186 Xinfo = {author}: {desc}
187 187 EOF
188 188
189 189 echo % cat
190 190 cat a b
191 191 echo % hg cat
192 192 hg cat sym a b
193 193
194 194 echo
195 195 echo '$Xinfo$' >> a
196 196 cat <<EOF >> log
197 197 firstline
198 198 secondline
199 199 EOF
200 200
201 201 echo % interrupted commit should not change state
202 202 hg commit
203 203 echo % status
204 204 hg status
205 205
206 206 echo % commit
207 207 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
208 208 rm log
209 209 echo % status
210 210 hg status
211 211 echo % verify
212 212 hg verify
213 213
214 214 echo % cat
215 215 cat a b
216 216 echo % hg cat
217 217 hg cat sym a b
218 218 echo
219 219 echo % annotate
220 220 hg annotate a
221 221
222 222 echo % remove
223 223 hg debugrebuildstate
224 224 hg remove a
225 225 hg --debug commit -m rma
226 226 echo % status
227 227 hg status
228 228 echo % rollback
229 229 hg rollback
230 230 echo % status
231 231 hg status
232 232 echo % revert a
233 233 hg revert --no-backup --rev tip a
234 234 echo % cat a
235 235 cat a
236 236
237 237 echo % clone to test incoming
238 238 cd ..
239 239 hg clone -r1 Test Test-a
240 240 cd Test-a
241 241 cat <<EOF >> .hg/hgrc
242 242 [paths]
243 243 default = ../Test
244 244 EOF
245 245 echo % incoming
246 246 # remove path to temp dir
247 247 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
248 248
249 249 sed -e 's/Id.*/& rejecttest/' a > a.new
250 250 mv a.new a
251 251 echo % commit rejecttest
252 252 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
253 253 echo % export
254 254 hg export -o ../rejecttest.diff tip
255 255
256 256 cd ../Test
257 257 echo % import
258 258 hg import ../rejecttest.diff
259 259 echo % cat
260 260 cat a b
261 261 echo
262 262 echo % rollback
263 263 hg rollback
264 264 echo % clean update
265 265 hg update --clean
266 266
267 267 echo % kwexpand/kwshrink on selected files
268 268 mkdir x
269 269 echo % copy a x/a
270 270 hg copy a x/a
271 271 echo % kwexpand a
272 272 hg --verbose kwexpand a
273 273 echo % kwexpand x/a should abort
274 274 hg --verbose kwexpand x/a
275 275 cd x
276 276 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
277 277 echo % cat a
278 278 cat a
279 279 echo % kwshrink a inside directory x
280 280 hg --verbose kwshrink a
281 281 echo % cat a
282 282 cat a
283 283 cd ..
284 284
285 285 echo % kwexpand nonexistent
286 286 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
287 287
288 288 echo % hg serve
289 289 hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
290 290 cat hg.pid >> $DAEMON_PIDS
291 291 echo % expansion
292 292 echo % hgweb file
293 293 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/a/?style=raw')
294 294 echo % no expansion
295 295 echo % hgweb annotate
296 296 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/annotate/tip/a/?style=raw')
297 297 echo % hgweb changeset
298 298 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/tip/?style=raw')
299 299 echo % hgweb filediff
300 300 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/bb948857c743/a?style=raw')
301 301 echo % errors encountered
302 302 cat errors.log
303 303
304 304 echo % merge/resolve
305 305 echo '$Id$' > m
306 306 hg add m
307 307 hg commit -m 4kw
308 308 echo foo >> m
309 309 hg commit -m 5foo
310 310 echo % simplemerge
311 311 hg update 4
312 312 echo foo >> m
313 313 hg commit -m 6foo
314 314 hg merge
315 315 hg commit -m simplemerge
316 316 cat m
317 317 echo % conflict
318 318 hg update 4
319 319 echo bar >> m
320 320 hg commit -m 8bar
321 321 hg merge
322 322 echo % keyword stays outside conflict zone
323 323 cat m
324 324 echo % resolve to local
325 325 HGMERGE=internal:local hg resolve
326 326 hg commit -m localresolve
327 327 cat m
328 328
329 329 echo % switch off expansion
330 330 echo % kwshrink with unknown file u
331 331 cp a u
332 332 hg --verbose kwshrink
333 333 echo % cat
334 334 cat a b
335 335 echo % hg cat
336 336 hg cat sym a b
337 337 echo
338 338 rm $HGRCPATH
339 339 echo % cat
340 340 cat a b
341 341 echo % hg cat
342 342 hg cat sym a b
343 343 echo
@@ -1,36 +1,39
1 1 % clone
2 2 updating working directory
3 3 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
4 4 % commit
5 5 adding a
6 6 % commit
7 7 % push
8 8 pushing to ../a
9 9 searching for changes
10 10 adding changesets
11 11 adding manifests
12 12 adding file changes
13 13 added 2 changesets with 2 changes to 1 files
14 Content-Type: text/plain; charset="us-ascii"
15 MIME-Version: 1.0
16 Content-Transfer-Encoding: 7bit
14 17 Date:
15 18 Subject: test-notify-changegroup/a: 2 new changesets
16 19 From: test
17 20 X-Hg-Notification: changeset cb9a9f314b8b
18 21 Message-Id:
19 22 To: baz, foo@bar
20 23
21 24 changeset cb9a9f314b8b in test-notify-changegroup/a
22 25 details: test-notify-changegroup/a?cmd=changeset;node=cb9a9f314b8b
23 26 summary: a
24 27
25 28 changeset ba677d0156c1 in test-notify-changegroup/a
26 29 details: test-notify-changegroup/a?cmd=changeset;node=ba677d0156c1
27 30 summary: b
28 31
29 32 diffs (6 lines):
30 33
31 34 diff -r 000000000000 -r ba677d0156c1 a
32 35 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33 36 +++ b/a Thu Jan 01 00:00:00 1970 +0000
34 37 @@ -0,0 +1,2 @@
35 38 +a
36 39 +a
@@ -1,98 +1,107
1 1 notify extension - No help text available
2 2
3 3 no commands defined
4 4 % commit
5 5 adding a
6 6 % clone
7 7 updating working directory
8 8 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
9 9 % commit
10 10 % pull (minimal config)
11 11 pulling from ../a
12 12 searching for changes
13 13 adding changesets
14 14 adding manifests
15 15 adding file changes
16 16 added 1 changesets with 1 changes to 1 files
17 Content-Type: text/plain; charset="us-ascii"
18 MIME-Version: 1.0
19 Content-Transfer-Encoding: 7bit
17 20 Date:
18 21 Subject: changeset in test-notify/b: b
19 22 From: test
20 23 X-Hg-Notification: changeset 0647d048b600
21 24 Message-Id:
22 25 To: baz, foo@bar
23 26
24 27 changeset 0647d048b600 in test-notify/b
25 28 details: test-notify/b?cmd=changeset;node=0647d048b600
26 29 description: b
27 30
28 31 diffs (6 lines):
29 32
30 33 diff -r cb9a9f314b8b -r 0647d048b600 a
31 34 --- a/a Thu Jan 01 00:00:00 1970 +0000
32 35 +++ b/a Thu Jan 01 00:00:01 1970 +0000
33 36 @@ -1,1 +1,2 @@
34 37 a
35 38 +a
36 39 (run 'hg update' to get a working copy)
37 40 % fail for config file is missing
38 41 rolling back last transaction
39 42 pull failed
40 43 % pull
41 44 rolling back last transaction
42 45 pulling from ../a
43 46 searching for changes
44 47 adding changesets
45 48 adding manifests
46 49 adding file changes
47 50 added 1 changesets with 1 changes to 1 files
51 Content-Type: text/plain; charset="us-ascii"
52 MIME-Version: 1.0
53 Content-Transfer-Encoding: 7bit
48 54 Date:
49 55 Subject: b
50 56 From: test@test.com
51 57 X-Hg-Notification: changeset 0647d048b600
52 58 Message-Id:
53 59 To: baz@test.com, foo@bar
54 60
55 61 changeset 0647d048b600
56 62 description:
57 63 b
58 64 diffs (6 lines):
59 65
60 66 diff -r cb9a9f314b8b -r 0647d048b600 a
61 67 --- a/a Thu Jan 01 00:00:00 1970 +0000
62 68 +++ b/a Thu Jan 01 00:00:01 1970 +0000
63 69 @@ -1,1 +1,2 @@
64 70 a
65 71 +a
66 72 (run 'hg update' to get a working copy)
67 73 % pull
68 74 rolling back last transaction
69 75 pulling from ../a
70 76 searching for changes
71 77 adding changesets
72 78 adding manifests
73 79 adding file changes
74 80 added 1 changesets with 1 changes to 1 files
81 Content-Type: text/plain; charset="us-ascii"
82 MIME-Version: 1.0
83 Content-Transfer-Encoding: 7bit
75 84 Date:
76 85 Subject: b
77 86 From: test@test.com
78 87 X-Hg-Notification: changeset 0647d048b600
79 88 Message-Id:
80 89 To: baz@test.com, foo@bar
81 90
82 91 changeset 0647d048b600
83 92 description:
84 93 b
85 94 diffstat:
86 95
87 96 1 file changed, 1 insertion(+)
88 97 a | 1 +
89 98
90 99 diffs (6 lines):
91 100
92 101 diff -r cb9a9f314b8b -r 0647d048b600 a
93 102 --- a/a Thu Jan 01 00:00:00 1970 +0000
94 103 +++ b/a Thu Jan 01 00:00:01 1970 +0000
95 104 @@ -1,1 +1,2 @@
96 105 a
97 106 +a
98 107 (run 'hg update' to get a working copy)
General Comments 0
You need to be logged in to leave comments. Login now