D6825: contrib: start building a library for simple hooks
joerg.sonnenberger (Joerg Sonnenberger)
phabricator at mercurial-scm.org
Sat Sep 7 12:32:02 EDT 2019
joerg.sonnenberger updated this revision to Diff 16431.
REPOSITORY
rHG Mercurial
CHANGES SINCE LAST UPDATE
https://phab.mercurial-scm.org/D6825?vs=16430&id=16431
CHANGES SINCE LAST ACTION
https://phab.mercurial-scm.org/D6825/new/
REVISION DETAIL
https://phab.mercurial-scm.org/D6825
AFFECTED FILES
contrib/hooks/enforce_draft_commits.py
contrib/hooks/reject_merge_commits.py
contrib/hooks/reject_new_heads.py
CHANGE DETAILS
diff --git a/contrib/hooks/reject_new_heads.py b/contrib/hooks/reject_new_heads.py
new file mode 100644
--- /dev/null
+++ b/contrib/hooks/reject_new_heads.py
@@ -0,0 +1,25 @@
+# This hook checks branches touched by new changesets have at most one
+# open head. It can be used to enforce policies for merge-before-push
+# or rebase-before-push. It does not handle pre-existing hydras.
+#
+# Usage:
+# [hooks]
+# pretxnclose.reject_new_heads = python:../reject_new_heads.py:hook
+
+from mercurial import (
+ error,
+)
+from mercurial.i18n import _
+
+def hook(ui, repo, hooktype, node = None, **kwargs):
+ if hooktype != "pretxnclose":
+ raise error.Abort(_('Unsupported hook type %s') % hooktype)
+ ctx = repo.unfiltered()[node]
+ branches = set()
+ for rev in repo.changelog.revs(start=ctx.rev()):
+ rev = repo[rev]
+ branches.add(rev.branch())
+ for branch in branches:
+ if len(repo.revs("head() and not closed() and branch(%s)", branch)) > 1:
+ raise error.Abort(_('Changes on branch "%s" resulted '
+ 'in multiple heads') % branch)
diff --git a/contrib/hooks/reject_merge_commits.py b/contrib/hooks/reject_merge_commits.py
new file mode 100644
--- /dev/null
+++ b/contrib/hooks/reject_merge_commits.py
@@ -0,0 +1,27 @@
+# This hook checks new changesets for merge commits. Merge commits are allowed
+# only between different branches, i.e. merging a feature branch into the main
+# development branch. This can be used to enforce policies for linear commit
+# histories.
+#
+# Usage:
+# [hooks]
+# pretxnchangegroup.reject_merge_commits = python:../reject_merge_commits.py:hook
+
+from mercurial import (
+ error,
+)
+from mercurial.i18n import _
+
+def hook(ui, repo, hooktype, node = None, **kwargs):
+ if hooktype != "pretxnchangegroup":
+ raise error.Abort(_('Unsupported hook type %s'), hooktype)
+
+ ctx = repo.unfiltered()[node]
+ for rev in repo.changelog.revs(start=ctx.rev()):
+ rev = repo[rev]
+ parents = rev.parents()
+ if len(parents) < 2:
+ continue
+ if all(repo[p].branch() == rev.branch() for p in parents):
+ raise error.Abort(_('%s rejected as merge on the same branch. '
+ 'Please consider rebase.') % rev)
diff --git a/contrib/hooks/enforce_draft_commits.py b/contrib/hooks/enforce_draft_commits.py
new file mode 100644
--- /dev/null
+++ b/contrib/hooks/enforce_draft_commits.py
@@ -0,0 +1,25 @@
+# This hook checks that all new changesets are in the draft phase. This allows
+# enforcing policies for work-in-progress changes in overlay repositories,
+# i.e. a shared hidden repositories with different views for work-in-progress
+# code and public history.
+#
+# Usage:
+# [hooks]
+# pretxnclose-phase.enforce_draft_commits = python:../enforce_draft_commits.py:hook
+
+from mercurial import (
+ error,
+ phases,
+)
+from mercurial.i18n import _
+
+def hook(ui, repo, hooktype, node = None, **kwargs):
+ if hooktype != "pretxnclose-phase":
+ raise error.Abort(_('Unsupported hook type %s'), hooktype)
+ ctx = repo.unfiltered()[node]
+ if kwargs['oldphase']:
+ raise error.Abort(_('Phase change from %s to %s for %s rejected') %
+ (kwargs['oldphase'], kwargs['phase'], ctx))
+ elif kwargs['phase'] != 'draft':
+ raise error.Abort(_('New changeset %s in phase %s rejected') %
+ (ctx, kwargs['phase']))
To: joerg.sonnenberger, #hg-reviewers
Cc: pulkit, mercurial-devel
More information about the Mercurial-devel
mailing list