# HG changeset patch # User Boris Feld # Date 1507481414 -7200 # Node ID c212947273a70d528cd5f2e8b8b356fcd4762e52 # Parent ee5f0d047b41452e2263b307a82e77af4735500d bookmark: add a dedicated pretxnclose-bookmark hook This new hook mirror the newly introduced 'txnclose-bookmark' but can abort the transaction. diff -r ee5f0d047b41 -r c212947273a7 mercurial/help/config.txt --- a/mercurial/help/config.txt Tue Oct 10 17:53:42 2017 +0200 +++ b/mercurial/help/config.txt Sun Oct 08 18:50:14 2017 +0200 @@ -988,6 +988,20 @@ phase changes will set ``HG_BOOKMARK_MOVED`` and ``HG_PHASES_MOVED`` to ``1`` respectively, etc. +``pretxnclose-bookmark`` + Run right before a bookmark change is actually finalized. Any repository + change will be visible to the hook program. This lets you validate the + transaction content or change it. Exit status 0 allows the commit to + proceed. A non-zero status will cause the transaction to be rolled back. + The name of the bookmark will be available in ``$HG_BOOKMARK``, the new + bookmark location will be available in ``$HG_NODE`` while the previous + location will be available in ``$HG_OLDNODE``. In case of a bookmark + creation ``$HG_OLDNODE`` will be empty. In case of deletion ``$HG_NODE`` + will be empty. + In addition, the reason for the transaction opening will be in + ``$HG_TXNNAME``, and a unique identifier for the transaction will be in + ``HG_TXNID``. + ``txnclose`` Run after any repository transaction has been committed. At this point, the transaction can no longer be rolled back. The hook will run @@ -997,14 +1011,8 @@ ``txnclose-bookmark`` Run after any bookmark change has been committed. At this point, the transaction can no longer be rolled back. The hook will run after the lock - is released. - The name of the bookmark will be available in ``$HG_BOOKMARK``, the new - bookmark location will be available in ``$HG_NODE`` while the previous - location will be available in ``$HG_OLDNODE``. In case of a bookmark - creation ``$HG_OLDNODE`` will be empty. In case of deletion ``$HG_NODE`` - will be empty. In addition, the reason for the transaction opening will be - in ``$HG_TXNNAME``, and a unique identifier for the transaction will be in - ``HG_TXNID``. + is released. See :hg:`help config.hooks.pretxnclose-bookmark` for details + about available variables. ``txnabort`` Run when a transaction is aborted. See :hg:`help config.hooks.pretxnclose` diff -r ee5f0d047b41 -r c212947273a7 mercurial/localrepo.py --- a/mercurial/localrepo.py Tue Oct 10 17:53:42 2017 +0200 +++ b/mercurial/localrepo.py Sun Oct 08 18:50:14 2017 +0200 @@ -1235,8 +1235,17 @@ # This will have to be fixed before we remove the experimental # gating. tracktags(tr2) - reporef().hook('pretxnclose', throw=True, - txnname=desc, **pycompat.strkwargs(tr.hookargs)) + repo = reporef() + if hook.hashook(repo.ui, 'pretxnclose-bookmark'): + for name, (old, new) in sorted(tr.changes['bookmarks'].items()): + args = tr.hookargs.copy() + args.update(bookmarks.preparehookargs(name, old, new)) + repo.hook('pretxnclose-bookmark', throw=True, + txnname=desc, + **pycompat.strkwargs(args)) + + repo.hook('pretxnclose', throw=True, + txnname=desc, **pycompat.strkwargs(tr.hookargs)) def releasefn(tr, success): repo = reporef() if success: diff -r ee5f0d047b41 -r c212947273a7 tests/test-bookmarks.t --- a/tests/test-bookmarks.t Tue Oct 10 17:53:42 2017 +0200 +++ b/tests/test-bookmarks.t Sun Oct 08 18:50:14 2017 +0200 @@ -1063,3 +1063,99 @@ rollback completed abort: pretxnclose hook exited with status 1 [255] + +Check pretxnclose-bookmark can abort a transaction +-------------------------------------------------- + +add hooks: + +* to prevent NEW bookmark on a non-public changeset +* to prevent non-forward move of NEW bookmark + + $ cat << EOF >> .hg/hgrc + > [hooks] + > pretxnclose-bookmark.force-public = (echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z "\$HG_NODE" ] || (hg log -r "\$HG_NODE" -T '{phase}' | grep public > /dev/null) + > pretxnclose-bookmark.force-forward = (echo \$HG_BOOKMARK| grep -v NEW > /dev/null) || [ -z "\$HG_NODE" ] || (hg log -r "max(\$HG_OLDNODE::\$HG_NODE)" -T 'MATCH' | grep MATCH > /dev/null) + > EOF + + $ hg log -G -T phases + @ changeset: 6:81dcce76aa0b + | tag: tip + | phase: draft + | parent: 4:125c9a1d6df6 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: xx + | + | o changeset: 5:5fb12f0f2d51 + | | branch: test + | | bookmark: Z + | | phase: draft + | | parent: 3:9ba5f110a0b3 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: yy + | | + o | changeset: 4:125c9a1d6df6 + | | bookmark: Y + | | bookmark: Z@2 + | | phase: public + | | parent: 2:db815d6d32e6 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: x + | | + | o changeset: 3:9ba5f110a0b3 + |/ branch: test + | bookmark: foo + | bookmark: four + | phase: public + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: y + | + o changeset: 2:db815d6d32e6 + | bookmark: foo@2 + | bookmark: should-end-on-two + | bookmark: x y + | phase: public + | parent: 0:f7b1eb17ad24 + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: 2 + | + | o changeset: 1:925d80f479bb + |/ bookmark: X2 + | bookmark: Z@1 + | phase: public + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: 1 + | + o changeset: 0:f7b1eb17ad24 + bookmark: foo@1 + phase: public + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: 0 + + +attempt to create on a default changeset + + $ hg bookmark -r 81dcce76aa0b NEW + transaction abort! + rollback completed + abort: pretxnclose-bookmark.force-public hook exited with status 1 + [255] + +create on a public changeset + + $ hg bookmark -r 9ba5f110a0b3 NEW + +move to the other branch + + $ hg bookmark -f -r 125c9a1d6df6 NEW + transaction abort! + rollback completed + abort: pretxnclose-bookmark.force-forward hook exited with status 1 + [255]