hgext/notify.py
branchstable
changeset 44729 26ce8e751503
parent 44627 947e6df4ff77
child 45942 89a2afe31e82
equal deleted inserted replaced
44692:539490756a72 44729:26ce8e751503
   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
   158 from mercurial import (
   167 from mercurial import (
   159     encoding,
   168     encoding,
   160     error,
   169     error,
   161     logcmdutil,
   170     logcmdutil,
   162     mail,
   171     mail,
       
   172     obsutil,
   163     patch,
   173     patch,
   164     pycompat,
   174     pycompat,
   165     registrar,
   175     registrar,
   166     util,
   176     util,
   167 )
   177 )
   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)