bookmark: add a dedicated pretxnclose-bookmark hook
authorBoris Feld <boris.feld@octobus.net>
Sun, 08 Oct 2017 18:50:14 +0200
changeset 34709 c212947273a7
parent 34708 ee5f0d047b41
child 34710 cdf833d7de98
bookmark: add a dedicated pretxnclose-bookmark hook This new hook mirror the newly introduced 'txnclose-bookmark' but can abort the transaction.
mercurial/help/config.txt
mercurial/localrepo.py
tests/test-bookmarks.t
--- 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`
--- 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:
--- 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]