1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import re
from sys import stderr
import pygit2
from distgit.hooks import CommitMsg, Hook, HookResult
"""
Commit-Msg Pattern Hook (Client-side)
Validates the commit message against a regular expression.
"""
class CommitMsgPattern(CommitMsg):
def __init__(self, repo: pygit2.Repository, pattern: str):
super().__init__(repo)
self.exp = re.compile(pattern)
def run(self, message_file: str) -> HookResult:
with open(message_file) as f:
message = f.read()
if not self.exp.match(message):
stderr.write(f"Commit message does not match pattern: {self.exp.pattern}\n")
return HookResult.FAILURE
return HookResult.SUCCESS
"""
Update Pattern Hook (Server-side)
Invoked by git-receive-pack once per ref being updated, before the ref is updated.
Use this hook to:
- Enforce fast-forward only (reject non-FF updates)
- Implement per-ref access control
- Log or validate old → new for specific refs
Takes three parameters: ref name, old object name, new object name.
"""
class UpdatePattern(Hook):
def __init__(self, repo: pygit2.Repository, ref_pattern: str, msg_pattern: str):
super().__init__(repo)
self.ref_exp = re.compile(ref_pattern)
self.msg_exp = re.compile(msg_pattern)
def run(self, ref_name: str, old_oid: str, new_oid: str) -> HookResult:
if self.ref_exp.match(ref_name):
commit = self.repo.revparse_single(new_oid).peel(pygit2.Commit)
if not self.msg_exp.match(commit.message):
stderr.write(f"Commit message does not match pattern: {self.msg_exp.pattern}\n")
return HookResult.FAILURE
return HookResult.SUCCESS