Patchwork D6825: contrib: start building a library for simple hooks

login
register
mail settings
Submitter phabricator
Date Sept. 7, 2019, 4:32 p.m.
Message ID <3c171c34887cd12f3f6d3fb38d2dee31@localhost.localdomain>
Download mbox | patch
Permalink /patch/41542/
State Not Applicable
Headers show

Comments

phabricator - Sept. 7, 2019, 4:32 p.m.
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




To: joerg.sonnenberger, #hg-reviewers
Cc: pulkit, mercurial-devel

Patch

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']))