diff --git a/hgext/hooklib/changeset_obsoleted.py b/hgext/hooklib/changeset_obsoleted.py --- a/hgext/hooklib/changeset_obsoleted.py +++ b/hgext/hooklib/changeset_obsoleted.py @@ -122,10 +122,18 @@ ) +def has_successor(repo, rev): + return any( + r for r in obsutil.allsuccessors(repo.obsstore, [rev]) if r != rev + ) + + def hook(ui, repo, hooktype, node=None, **kwargs): - if hooktype != b"pretxnclose": + if hooktype != b"txnclose": raise error.Abort( _(b'Unsupported hook type %r') % pycompat.bytestr(hooktype) ) - for rev in obsutil.getobsoleted(repo, repo.currenttransaction()): - _report_commit(ui, repo, repo.unfiltered()[rev]) + for rev in obsutil.getobsoleted(repo, changes=kwargs['changes']): + ctx = repo.unfiltered()[rev] + if not has_successor(repo, ctx.node()): + _report_commit(ui, repo, ctx) diff --git a/mercurial/obsutil.py b/mercurial/obsutil.py --- a/mercurial/obsutil.py +++ b/mercurial/obsutil.py @@ -13,6 +13,7 @@ from . import ( diffutil, encoding, + error, node as nodemod, phases, pycompat, @@ -481,14 +482,23 @@ return effects -def getobsoleted(repo, tr): - """return the set of pre-existing revisions obsoleted by a transaction""" +def getobsoleted(repo, tr=None, changes=None): + """return the set of pre-existing revisions obsoleted by a transaction + + Either the transaction or changes item of the transaction (for hooks) + must be provided, but not both. + """ + if (tr is None) == (changes is None): + e = b"exactly one of tr and changes must be provided" + raise error.ProgrammingError(e) torev = repo.unfiltered().changelog.index.get_rev phase = repo._phasecache.phase succsmarkers = repo.obsstore.successors.get public = phases.public - addedmarkers = tr.changes[b'obsmarkers'] - origrepolen = tr.changes[b'origrepolen'] + if changes is None: + changes = tr.changes + addedmarkers = changes[b'obsmarkers'] + origrepolen = changes[b'origrepolen'] seenrevs = set() obsoleted = set() for mark in addedmarkers: diff --git a/tests/test-hooklib-changeset_obsoleted.t b/tests/test-hooklib-changeset_obsoleted.t --- a/tests/test-hooklib-changeset_obsoleted.t +++ b/tests/test-hooklib-changeset_obsoleted.t @@ -24,7 +24,7 @@ $ cat <> b/.hg/hgrc > [hooks] > incoming.notify = python:hgext.notify.hook - > pretxnclose.changeset_obsoleted = python:hgext.hooklib.changeset_obsoleted.hook + > txnclose.changeset_obsoleted = python:hgext.hooklib.changeset_obsoleted.hook > EOF $ hg --cwd b pull ../a | "$PYTHON" $TESTDIR/unwrap-message-id.py pulling from ../a @@ -72,6 +72,8 @@ pushing to ../b searching for changes no changes found + 1 new obsolescence markers + obsoleted 1 changesets Subject: changeset abandoned In-reply-to: Message-Id: @@ -80,5 +82,33 @@ To: baz@example.com This changeset has been abandoned. + +Check that known changesets with known successors do not result in a mail. + + $ hg init c + $ hg init d + $ cat <> d/.hg/hgrc + > [hooks] + > incoming.notify = python:hgext.notify.hook + > txnclose.changeset_obsoleted = python:hgext.hooklib.changeset_obsoleted.hook + > EOF + $ hg --cwd c debugbuilddag '.:parent.*parent' + $ hg --cwd c push ../d -r 1 + pushing to ../d + searching for changes + adding changesets + adding manifests + adding file changes + added 2 changesets with 0 changes to 0 files + $ hg --cwd c debugobsolete $(hg --cwd c log -T '{node}' -r 1) $(hg --cwd c log -T '{node}' -r 2) 1 new obsolescence markers obsoleted 1 changesets + $ hg --cwd c push ../d | "$PYTHON" $TESTDIR/unwrap-message-id.py + pushing to ../d + searching for changes + adding changesets + adding manifests + adding file changes + added 1 changesets with 0 changes to 0 files (+1 heads) + 1 new obsolescence markers + obsoleted 1 changesets