##// END OF EJS Templates
rcextensions: added example for validation of commit messages for git.
marcink -
r3211:ab158566 default
parent child Browse files
Show More
@@ -0,0 +1,91 b''
1 # Example to validate commit message or author using some sort of rules
2
3
4 @has_kwargs({
5 'server_url': 'url of instance that triggered this hook',
6 'config': 'path to .ini config used',
7 'scm': 'type of version control "git", "hg", "svn"',
8 'username': 'username of actor who triggered this event',
9 'ip': 'ip address of actor who triggered this hook',
10 'action': '',
11 'repository': 'repository name',
12 'repo_store_path': 'full path to where repositories are stored',
13 'commit_ids': 'pre transaction metadata for commit ids',
14 'hook_type': '',
15 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
16 })
17 @has_kwargs({
18 'server_url': 'url of instance that triggered this hook',
19 'config': 'path to .ini config used',
20 'scm': 'type of version control "git", "hg", "svn"',
21 'username': 'username of actor who triggered this event',
22 'ip': 'ip address of actor who triggered this hook',
23 'action': '',
24 'repository': 'repository name',
25 'repo_store_path': 'full path to where repositories are stored',
26 'commit_ids': 'pre transaction metadata for commit ids',
27 'hook_type': '',
28 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
29 })
30 def _pre_push_hook(*args, **kwargs):
31 """
32 Post push hook
33 To stop version control from storing the transaction and send a message to user
34 use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed')
35
36 This message will be shown back to client during PUSH operation
37
38 Commit ids might look like that::
39
40 [{u'hg_env|git_env': ...,
41 u'multiple_heads': [],
42 u'name': u'default',
43 u'new_rev': u'd0befe0692e722e01d5677f27a104631cf798b69',
44 u'old_rev': u'd0befe0692e722e01d5677f27a104631cf798b69',
45 u'ref': u'',
46 u'total_commits': 2,
47 u'type': u'branch'}]
48 """
49 import re
50 from .helpers import extra_fields, extract_pre_commits
51 from .utils import str2bool
52
53 # returns list of dicts with key-val fetched from extra fields
54 repo_extra_fields = extra_fields.run(**kwargs)
55
56 # optionally use 'extra fields' to control the logic per repo
57 should_validate = str2bool(repo_extra_fields.get('validate_author', True))
58
59 # optionally store validation regex into extra fields
60 validation_regex = repo_extra_fields.get('validation_regex', '')
61
62 def validate_commit_message(commit_message, message_regex=None):
63 """
64 This function validates commit_message against some sort of rules.
65 It should return a valid boolean, and a reason for failure
66 """
67
68 if "secret_string" in commit_message:
69 msg = "!!Push forbidden: secret string found in commit messages"
70 return False, msg
71
72 if validation_regex:
73 regexp = re.compile(validation_regex)
74 if not regexp.match(message):
75 msg = "!!Push forbidden: commit message does not match regexp"
76 return False, msg
77
78 return True, ''
79
80 if should_validate:
81 # returns list of dicts with key-val fetched from extra fields
82 commit_list = extract_pre_commits.run(**kwargs)
83
84 for commit_data in commit_list:
85 message = commit_data['message']
86
87 message_valid, reason = validate_commit_message(message, validation_regex)
88 if not message_valid:
89 return HookResponse(1, reason)
90
91 return HookResponse(0, '')
@@ -27,6 +27,7 b' us in hooks::'
27 """
27 """
28 import re
28 import re
29 import collections
29 import collections
30 import json
30
31
31
32
32 def get_hg_commits(repo, refs):
33 def get_hg_commits(repo, refs):
@@ -36,6 +37,31 b' def get_hg_commits(repo, refs):'
36
37
37 def get_git_commits(repo, refs):
38 def get_git_commits(repo, refs):
38 commits = []
39 commits = []
40
41 for data in refs:
42 # we should now extract commit data
43 old_rev = data['old_rev']
44 new_rev = data['new_rev']
45
46 if '00000000' in old_rev:
47 # new branch, we don't need to extract nothing
48 return commits
49
50 git_env = dict(data['git_env'])
51 cmd = [
52 'log',
53 '--pretty=format:{"commit_id": "%H", "author": "%aN <%aE>", "date": "%ad", "message": "%f"}',
54 '{}...{}'.format(old_rev, new_rev)
55 ]
56
57 stdout, stderr = repo.run_git_command(cmd, env=git_env)
58 for line in stdout.splitlines():
59 try:
60 data = json.loads(line)
61 commits.append(data)
62 except Exception:
63 print('Failed to load data from GIT line')
64
39 return commits
65 return commits
40
66
41
67
@@ -51,13 +77,14 b' def run(*args, **kwargs):'
51
77
52 commits = []
78 commits = []
53
79
54 for rev_data in kwargs['commit_ids']:
55 new_environ = dict((k, v) for k, v in rev_data['hg_env'])
56
57 if vcs_type == 'git':
80 if vcs_type == 'git':
81 for rev_data in kwargs['commit_ids']:
82 new_environ = dict((k, v) for k, v in rev_data['git_env'])
58 commits = get_git_commits(vcs_repo, kwargs['commit_ids'])
83 commits = get_git_commits(vcs_repo, kwargs['commit_ids'])
59
84
60 if vcs_type == 'hg':
85 if vcs_type == 'hg':
86 for rev_data in kwargs['commit_ids']:
87 new_environ = dict((k, v) for k, v in rev_data['hg_env'])
61 commits = get_hg_commits(vcs_repo, kwargs['commit_ids'])
88 commits = get_hg_commits(vcs_repo, kwargs['commit_ids'])
62
89
63 return commits
90 return commits
@@ -145,3 +145,41 b' def maybe_log_call(name, args, kwargs):'
145 if hasattr(rcextensions, 'calls'):
145 if hasattr(rcextensions, 'calls'):
146 calls = rcextensions.calls
146 calls = rcextensions.calls
147 calls[name].append((args, kwargs))
147 calls[name].append((args, kwargs))
148
149
150 def str2bool(_str):
151 """
152 returns True/False value from given string, it tries to translate the
153 string into boolean
154
155 :param _str: string value to translate into boolean
156 :rtype: boolean
157 :returns: boolean from given string
158 """
159 if _str is None:
160 return False
161 if _str in (True, False):
162 return _str
163 _str = str(_str).strip().lower()
164 return _str in ('t', 'true', 'y', 'yes', 'on', '1')
165
166
167 def aslist(obj, sep=None, strip=True):
168 """
169 Returns given string separated by sep as list
170
171 :param obj:
172 :param sep:
173 :param strip:
174 """
175 if isinstance(obj, (basestring,)):
176 lst = obj.split(sep)
177 if strip:
178 lst = [v.strip() for v in lst]
179 return lst
180 elif isinstance(obj, (list, tuple)):
181 return obj
182 elif obj is None:
183 return []
184 else:
185 return [obj] No newline at end of file
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now