131 notify.fromauthor |
131 notify.fromauthor |
132 If set, use the committer of the first changeset in a changegroup for |
132 If set, use the committer of the first changeset in a changegroup for |
133 the "From" field of the notification mail. If not set, take the user |
133 the "From" field of the notification mail. If not set, take the user |
134 from the pushing repo. Default: False. |
134 from the pushing repo. Default: False. |
135 |
135 |
|
136 notify.reply-to-predecessor (EXPERIMENTAL) |
|
137 If set and the changeset has a predecessor in the repository, try to thread |
|
138 the notification mail with the predecessor. This adds the "In-Reply-To" header |
|
139 to the notification mail with a reference to the predecessor with the smallest |
|
140 revision number. Mail threads can still be torn, especially when changesets |
|
141 are folded. |
|
142 |
|
143 This option must be used in combination with ``notify.messageidseed``. |
|
144 |
136 If set, the following entries will also be used to customize the |
145 If set, the following entries will also be used to customize the |
137 notifications: |
146 notifications: |
138 |
147 |
139 email.from |
148 email.from |
140 Email ``From`` address to use if none can be found in the generated |
149 Email ``From`` address to use if none can be found in the generated |
215 configitem( |
225 configitem( |
216 b'notify', b'merge', default=True, |
226 b'notify', b'merge', default=True, |
217 ) |
227 ) |
218 configitem( |
228 configitem( |
219 b'notify', b'outgoing', default=None, |
229 b'notify', b'outgoing', default=None, |
|
230 ) |
|
231 configitem( |
|
232 b'notify', b'reply-to-predecessor', default=False, |
220 ) |
233 ) |
221 configitem( |
234 configitem( |
222 b'notify', b'sources', default=b'serve', |
235 b'notify', b'sources', default=b'serve', |
223 ) |
236 ) |
224 configitem( |
237 configitem( |
279 self.charsets = mail._charsets(self.ui) |
292 self.charsets = mail._charsets(self.ui) |
280 self.subs = self.subscribers() |
293 self.subs = self.subscribers() |
281 self.merge = self.ui.configbool(b'notify', b'merge') |
294 self.merge = self.ui.configbool(b'notify', b'merge') |
282 self.showfunc = self.ui.configbool(b'notify', b'showfunc') |
295 self.showfunc = self.ui.configbool(b'notify', b'showfunc') |
283 self.messageidseed = self.ui.config(b'notify', b'messageidseed') |
296 self.messageidseed = self.ui.config(b'notify', b'messageidseed') |
|
297 self.reply = self.ui.configbool(b'notify', b'reply-to-predecessor') |
|
298 |
|
299 if self.reply and not self.messageidseed: |
|
300 raise error.Abort( |
|
301 _( |
|
302 b'notify.reply-to-predecessor used without ' |
|
303 b'notify.messageidseed' |
|
304 ) |
|
305 ) |
|
306 |
284 if self.showfunc is None: |
307 if self.showfunc is None: |
285 self.showfunc = self.ui.configbool(b'diff', b'showfunc') |
308 self.showfunc = self.ui.configbool(b'diff', b'showfunc') |
286 |
309 |
287 mapfile = None |
310 mapfile = None |
288 template = self.ui.config(b'notify', hooktype) or self.ui.config( |
311 template = self.ui.config(b'notify', hooktype) or self.ui.config( |
435 ) |
458 ) |
436 |
459 |
437 msg['X-Hg-Notification'] = 'changeset %s' % ctx |
460 msg['X-Hg-Notification'] = 'changeset %s' % ctx |
438 if not msg['Message-Id']: |
461 if not msg['Message-Id']: |
439 msg['Message-Id'] = messageid(ctx, self.domain, self.messageidseed) |
462 msg['Message-Id'] = messageid(ctx, self.domain, self.messageidseed) |
|
463 if self.reply: |
|
464 unfi = self.repo.unfiltered() |
|
465 has_node = unfi.changelog.index.has_node |
|
466 predecessors = [ |
|
467 unfi[ctx2] |
|
468 for ctx2 in obsutil.allpredecessors(unfi.obsstore, [ctx.node()]) |
|
469 if ctx2 != ctx.node() and has_node(ctx2) |
|
470 ] |
|
471 if predecessors: |
|
472 # There is at least one predecessor, so which to pick? |
|
473 # Ideally, there is a unique root because changesets have |
|
474 # been evolved/rebased one step at a time. In this case, |
|
475 # just picking the oldest known changeset provides a stable |
|
476 # base. It doesn't help when changesets are folded. Any |
|
477 # better solution would require storing more information |
|
478 # in the repository. |
|
479 pred = min(predecessors, key=lambda ctx: ctx.rev()) |
|
480 msg['In-Reply-To'] = messageid( |
|
481 pred, self.domain, self.messageidseed |
|
482 ) |
440 msg['To'] = ', '.join(sorted(subs)) |
483 msg['To'] = ', '.join(sorted(subs)) |
441 |
484 |
442 msgtext = msg.as_bytes() if pycompat.ispy3 else msg.as_string() |
485 msgtext = msg.as_bytes() if pycompat.ispy3 else msg.as_string() |
443 if self.test: |
486 if self.test: |
444 self.ui.write(msgtext) |
487 self.ui.write(msgtext) |