# HG changeset patch # User Boris Feld # Date 1507476198 -7200 # Node ID f6d17075608ff6913df0551ac35050a46365bdd2 # Parent cdf833d7de98af9287cc126adb8fefae32922e70 phase: add a dedicated pretxnclose-phase hook This new hook mirror the newly introduced 'txnclose-phase' but can abort the transaction. diff -r cdf833d7de98 -r f6d17075608f mercurial/help/config.txt --- a/mercurial/help/config.txt Sun Oct 08 17:50:46 2017 +0200 +++ b/mercurial/help/config.txt Sun Oct 08 17:23:18 2017 +0200 @@ -1002,6 +1002,17 @@ ``$HG_TXNNAME``, and a unique identifier for the transaction will be in ``HG_TXNID``. +``pretxnclose-phase`` + Run right before a phase 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 affected node is available in ``$HG_NODE``, the phase in ``$HG_PHASE`` + while the previous ``$HG_OLDPHASE``. In case of new node, ``$HG_OLDPHASE`` + 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 @@ -1017,12 +1028,8 @@ ``txnclose-phase`` Run after any phase 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 affected node is available in ``$HG_NODE``, the new phase will be - available in ``$HG_PHASE`` while the previous phase will be available in - ``$HG_OLDPHASE``. In case of new node, ``$HG_OLDPHASE`` 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-phase` for details about + available variables. ``txnabort`` Run when a transaction is aborted. See :hg:`help config.hooks.pretxnclose` diff -r cdf833d7de98 -r f6d17075608f mercurial/localrepo.py --- a/mercurial/localrepo.py Sun Oct 08 17:50:46 2017 +0200 +++ b/mercurial/localrepo.py Sun Oct 08 17:23:18 2017 +0200 @@ -1243,6 +1243,14 @@ repo.hook('pretxnclose-bookmark', throw=True, txnname=desc, **pycompat.strkwargs(args)) + if hook.hashook(repo.ui, 'pretxnclose-phase'): + cl = repo.unfiltered().changelog + for rev, (old, new) in tr.changes['phases'].items(): + args = tr.hookargs.copy() + node = hex(cl.node(rev)) + args.update(phases.preparehookargs(node, old, new)) + repo.hook('pretxnclose-phase', throw=True, txnname=desc, + **pycompat.strkwargs(args)) repo.hook('pretxnclose', throw=True, txnname=desc, **pycompat.strkwargs(tr.hookargs)) diff -r cdf833d7de98 -r f6d17075608f tests/test-phases.t --- a/tests/test-phases.t Sun Oct 08 17:50:46 2017 +0200 +++ b/tests/test-phases.t Sun Oct 08 17:23:18 2017 +0200 @@ -732,3 +732,94 @@ rollback completed abort: pretxnclose hook exited with status 1 [255] + +Check that pretxnclose-phase hook can control phase movement + + $ hg phase --force b3325c91a4d9 --secret + test-debug-phase: move rev 3: 0 -> 2 + test-debug-phase: move rev 4: 0 -> 2 + test-debug-phase: move rev 5: 1 -> 2 + test-debug-phase: move rev 7: 0 -> 2 + test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: 0 -> 2 + test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 0 -> 2 + test-hook-close-phase: a030c6be5127abc010fcbff1851536552e6951a8: 1 -> 2 + test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: 0 -> 2 + $ hg log -G -T phases + @ changeset: 7:17a481b3bccb + |\ tag: tip + | | phase: secret + | | parent: 6:cf9fe039dfd6 + | | parent: 4:a603bfb5a83e + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: merge B' and E + | | + | o changeset: 6:cf9fe039dfd6 + | | phase: public + | | parent: 1:27547f69f254 + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: B' + | | + o | changeset: 4:a603bfb5a83e + | | phase: secret + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: E + | | + o | changeset: 3:b3325c91a4d9 + | | phase: secret + | | user: test + | | date: Thu Jan 01 00:00:00 1970 +0000 + | | summary: D + | | + o | changeset: 2:f838bfaca5c7 + |/ phase: public + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: C + | + o changeset: 1:27547f69f254 + | phase: public + | user: test + | date: Thu Jan 01 00:00:00 1970 +0000 + | summary: B + | + o changeset: 0:4a2df7238c3b + phase: public + user: test + date: Thu Jan 01 00:00:00 1970 +0000 + summary: A + + +Install a hook that prevent b3325c91a4d9 to become public + + $ cat >> .hg/hgrc << EOF + > [hooks] + > pretxnclose-phase.nopublish_D = (echo \$HG_NODE| grep -v b3325c91a4d9>/dev/null) || [ 0 -lt \$HG_PHASE ] + > EOF + +Try various actions. only the draft move should succeed + + $ hg phase --public b3325c91a4d9 + transaction abort! + rollback completed + abort: pretxnclose-phase.nopublish_D hook exited with status 1 + [255] + $ hg phase --public a603bfb5a83e + transaction abort! + rollback completed + abort: pretxnclose-phase.nopublish_D hook exited with status 1 + [255] + $ hg phase --draft 17a481b3bccb + test-debug-phase: move rev 3: 2 -> 1 + test-debug-phase: move rev 4: 2 -> 1 + test-debug-phase: move rev 7: 2 -> 1 + test-hook-close-phase: b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e: 2 -> 1 + test-hook-close-phase: a603bfb5a83e312131cebcd05353c217d4d21dde: 2 -> 1 + test-hook-close-phase: 17a481b3bccb796c0521ae97903d81c52bfee4af: 2 -> 1 + $ hg phase --public 17a481b3bccb + transaction abort! + rollback completed + abort: pretxnclose-phase.nopublish_D hook exited with status 1 + [255]