diff --git a/hgext/notify.py b/hgext/notify.py --- a/hgext/notify.py +++ b/hgext/notify.py @@ -133,6 +133,15 @@ notify.fromauthor the "From" field of the notification mail. If not set, take the user from the pushing repo. Default: False. +notify.reply-to-predecessor (EXPERIMENTAL) + If set and the changeset has a predecessor in the repository, try to thread + the notification mail with the predecessor. This adds the "In-Reply-To" header + to the notification mail with a reference to the predecessor with the smallest + revision number. Mail threads can still be torn, especially when changesets + are folded. + + This option must be used in combination with ``notify.messageidseed``. + If set, the following entries will also be used to customize the notifications: @@ -160,6 +169,7 @@ from mercurial import ( error, logcmdutil, mail, + obsutil, patch, pycompat, registrar, @@ -219,6 +229,9 @@ configitem( b'notify', b'outgoing', default=None, ) configitem( + b'notify', b'reply-to-predecessor', default=False, +) +configitem( b'notify', b'sources', default=b'serve', ) configitem( @@ -281,6 +294,16 @@ class notifier(object): self.merge = self.ui.configbool(b'notify', b'merge') self.showfunc = self.ui.configbool(b'notify', b'showfunc') self.messageidseed = self.ui.config(b'notify', b'messageidseed') + self.reply = self.ui.configbool(b'notify', b'reply-to-predecessor') + + if self.reply and not self.messageidseed: + raise error.Abort( + _( + b'notify.reply-to-predecessor used without ' + b'notify.messageidseed' + ) + ) + if self.showfunc is None: self.showfunc = self.ui.configbool(b'diff', b'showfunc') @@ -437,6 +460,26 @@ class notifier(object): msg['X-Hg-Notification'] = 'changeset %s' % ctx if not msg['Message-Id']: msg['Message-Id'] = messageid(ctx, self.domain, self.messageidseed) + if self.reply: + unfi = self.repo.unfiltered() + has_node = unfi.changelog.index.has_node + predecessors = [ + unfi[ctx2] + for ctx2 in obsutil.allpredecessors(unfi.obsstore, [ctx.node()]) + if ctx2 != ctx.node() and has_node(ctx2) + ] + if predecessors: + # There is at least one predecessor, so which to pick? + # Ideally, there is a unique root because changesets have + # been evolved/rebased one step at a time. In this case, + # just picking the oldest known changeset provides a stable + # base. It doesn't help when changesets are folded. Any + # better solution would require storing more information + # in the repository. + pred = min(predecessors, key=lambda ctx: ctx.rev()) + msg['In-Reply-To'] = messageid( + pred, self.domain, self.messageidseed + ) msg['To'] = ', '.join(sorted(subs)) msgtext = msg.as_bytes() if pycompat.ispy3 else msg.as_string() diff --git a/tests/test-notify.t b/tests/test-notify.t --- a/tests/test-notify.t +++ b/tests/test-notify.t @@ -6,8 +6,15 @@ > EOF $ cat <> $HGRCPATH + > [experimental] + > evolution = true + > > [extensions] > notify= + > strip= + > + > [phases] + > publish=False > > [hooks] > incoming.notify = python:hgext.notify.hook @@ -15,6 +22,8 @@ > [notify] > sources = pull > diffstat = False + > reply-to-predecessor = True + > messageidseed = notifyseed > > [usersubs] > foo@bar = * @@ -151,6 +160,15 @@ "From" field of the notification mail. If not set, take the user from the pushing repo. Default: False. + notify.reply-to-predecessor (EXPERIMENTAL) + If set and the changeset has a predecessor in the repository, try to thread + the notification mail with the predecessor. This adds the "In-Reply-To" + header to the notification mail with a reference to the predecessor with the + smallest revision number. Mail threads can still be torn, especially when + changesets are folded. + + This option must be used in combination with "notify.messageidseed". + If set, the following entries will also be used to customize the notifications: @@ -205,7 +223,7 @@ pull (minimal config) adding manifests adding file changes added 1 changesets with 2 changes to 2 files - new changesets 00a13f371396 + new changesets 00a13f371396 (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -266,7 +284,7 @@ pull adding manifests adding file changes added 1 changesets with 2 changes to 2 files - new changesets 00a13f371396 + new changesets 00a13f371396 (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -316,7 +334,7 @@ pull adding manifests adding file changes added 1 changesets with 2 changes to 2 files - new changesets 00a13f371396 + new changesets 00a13f371396 (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -369,7 +387,7 @@ test merge adding manifests adding file changes added 2 changesets with 0 changes to 0 files - new changesets 3332653e1f3c:fccf66cd0c35 + new changesets 3332653e1f3c:fccf66cd0c35 (2 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -436,7 +454,7 @@ non-ascii content and truncation of mult adding manifests adding file changes added 1 changesets with 1 changes to 1 files - new changesets 0f25f9c22b4c + new changesets 0f25f9c22b4c (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8bit @@ -480,7 +498,7 @@ long lines adding manifests adding file changes added 1 changesets with 1 changes to 1 files - new changesets a846b5f6ebb7 + new changesets a846b5f6ebb7 (1 drafts) notify: sending 2 subscribers 1 changes (run 'hg update' to get a working copy) $ cat b/mbox | "$PYTHON" $TESTDIR/unwrap-message-id.py | "$PYTHON" $TESTTMP/filter.py @@ -493,7 +511,7 @@ long lines Subject: long line From: test@test.com X-Hg-Notification: changeset a846b5f6ebb7 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar changeset a846b5f6ebb7 in b @@ -543,6 +561,8 @@ long lines (branches are permanent and global, did you want a bookmark?) $ echo a >> a/a $ hg --cwd a ci -m test -d '1 0' + $ echo a >> a/a + $ hg --cwd a ci -m test -d '1 0' $ hg --traceback --cwd b pull ../a | \ > "$PYTHON" $TESTDIR/unwrap-message-id.py | \ > "$PYTHON" $TESTTMP/filter.py @@ -551,8 +571,8 @@ long lines adding changesets adding manifests adding file changes - added 1 changesets with 1 changes to 1 files - new changesets f7e5aaed4080 + added 2 changesets with 2 changes to 1 files + new changesets f7e5aaed4080:485bf79b9464 (2 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -561,11 +581,24 @@ long lines Subject: test From: test@test.com X-Hg-Notification: changeset f7e5aaed4080 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar, notify@example.com changeset f7e5aaed4080 in b description: test + MIME-Version: 1.0 + Content-Type: text/plain; charset="us-ascii" + Content-Transfer-Encoding: 7bit + X-Test: foo + Date: * (glob) + Subject: test + From: test@test.com + X-Hg-Notification: changeset 485bf79b9464 + Message-Id: + To: baz@test.com, foo@bar, notify@example.com + + changeset 485bf79b9464 in b + description: test (run 'hg update' to get a working copy) revset selection: don't send to address that waits for mails @@ -584,7 +617,7 @@ from different branch adding manifests adding file changes added 1 changesets with 0 changes to 0 files (+1 heads) - new changesets 645eb6690ecf + new changesets 645eb6690ecf (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -593,7 +626,7 @@ from different branch Subject: test From: test@test.com X-Hg-Notification: changeset 645eb6690ecf - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar changeset 645eb6690ecf in b @@ -616,7 +649,7 @@ default template: Subject: changeset in b: default template From: test@test.com X-Hg-Notification: changeset 5cd4346eed47 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar changeset 5cd4346eed47 in $TESTTMP/b @@ -647,7 +680,7 @@ with style: Subject: with style From: test@test.com X-Hg-Notification: changeset ec8d9d852f56 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar changeset ec8d9d852f56 @@ -672,7 +705,7 @@ with template (overrides style): Subject: 14721b538ae3: with template From: test@test.com X-Hg-Notification: changeset 14721b538ae3 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar with template @@ -695,6 +728,8 @@ showfunc diff > EOF $ hg commit -Am addfunction adding f1 + $ hg debugobsolete eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee b86bc16ff894f057d023b306936f290954857187 + 1 new obsolescence markers $ hg --cwd ../b pull ../a | \ > "$PYTHON" $TESTDIR/unwrap-message-id.py pulling from ../a @@ -703,7 +738,8 @@ showfunc diff adding manifests adding file changes added 1 changesets with 1 changes to 1 files - new changesets b86bc16ff894 + 1 new obsolescence markers + new changesets b86bc16ff894 (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -711,7 +747,7 @@ showfunc diff Subject: addfunction From: test@test.com X-Hg-Notification: changeset b86bc16ff894 - Message-Id: (glob) + Message-Id: To: baz@test.com, foo@bar changeset b86bc16ff894 @@ -739,6 +775,9 @@ showfunc diff > } > EOF $ hg commit -m changefunction + $ hg debugobsolete 485bf79b9464197b2ed2debd0b16252ad64ed458 e81040e9838c704d8bf17658cb11758f24e40b6b + 1 new obsolescence markers + obsoleted 1 changesets $ hg --cwd ../b --config notify.showfunc=True pull ../a | \ > "$PYTHON" $TESTDIR/unwrap-message-id.py pulling from ../a @@ -747,7 +786,9 @@ showfunc diff adding manifests adding file changes added 1 changesets with 1 changes to 1 files - new changesets e81040e9838c + 1 new obsolescence markers + obsoleted 1 changesets + new changesets e81040e9838c (1 drafts) MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit @@ -755,7 +796,8 @@ showfunc diff Subject: changefunction From: test@test.com X-Hg-Notification: changeset e81040e9838c - Message-Id: (glob) + Message-Id: + In-Reply-To: To: baz@test.com, foo@bar changeset e81040e9838c @@ -774,3 +816,50 @@ showfunc diff + return a + b + c + e; } (run 'hg update' to get a working copy) + +Retry the In-Reply-To, but make sure the oldest known change is older. +This can happen when folding commits that have been rebased by another user. + + $ hg --cwd ../b strip tip + saved backup bundle to $TESTTMP/b/.hg/strip-backup/e81040e9838c-10aad4de-backup.hg + $ hg debugobsolete f7e5aaed408029cfe9890318245e87ef44739fdd e81040e9838c704d8bf17658cb11758f24e40b6b + 1 new obsolescence markers + obsoleted 1 changesets + $ hg --cwd ../b --config notify.showfunc=True pull ../a | \ + > "$PYTHON" $TESTDIR/unwrap-message-id.py + pulling from ../a + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 1 changes to 1 files + 2 new obsolescence markers + obsoleted 2 changesets + new changesets e81040e9838c (1 drafts) + MIME-Version: 1.0 + Content-Type: text/plain; charset="us-ascii" + Content-Transfer-Encoding: 7bit + Date: * (glob) + Subject: changefunction + From: test@test.com + X-Hg-Notification: changeset e81040e9838c + Message-Id: + In-Reply-To: + To: baz@test.com, foo@bar + + changeset e81040e9838c + diffs (12 lines): + + diff -r b86bc16ff894 -r e81040e9838c f1 + --- a/f1 Thu Jan 01 00:00:00 1970 +0000 + +++ b/f1 Thu Jan 01 00:00:00 1970 +0000 + @@ -2,6 +2,6 @@ int main() { + int a = 0; + int b = 1; + int c = 2; + - int d = 3; + - return a + b + c + d; + + int e = 3; + + return a + b + c + e; + } + (run 'hg update' to get a working copy)