phase: add a dedicated pretxnclose-phase hook
This new hook mirror the newly introduced 'txnclose-phase' but can abort the
transaction.
--- 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`
--- 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))
--- 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]