##// END OF EJS Templates
rcextensions: improve example
milka -
r4603:42274a1d stable
parent child Browse files
Show More
@@ -1,120 +1,120 b''
1 # Example to validate pushed files names and size using some sort of rules
1 # Example to validate pushed files names and size using some sort of rules
2
2
3
3
4
4
5 @has_kwargs({
5 @has_kwargs({
6 'server_url': 'url of instance that triggered this hook',
6 'server_url': 'url of instance that triggered this hook',
7 'config': 'path to .ini config used',
7 'config': 'path to .ini config used',
8 'scm': 'type of version control "git", "hg", "svn"',
8 'scm': 'type of version control "git", "hg", "svn"',
9 'username': 'username of actor who triggered this event',
9 'username': 'username of actor who triggered this event',
10 'ip': 'ip address of actor who triggered this hook',
10 'ip': 'ip address of actor who triggered this hook',
11 'action': '',
11 'action': '',
12 'repository': 'repository name',
12 'repository': 'repository name',
13 'repo_store_path': 'full path to where repositories are stored',
13 'repo_store_path': 'full path to where repositories are stored',
14 'commit_ids': 'pre transaction metadata for commit ids',
14 'commit_ids': 'pre transaction metadata for commit ids',
15 'hook_type': '',
15 'hook_type': '',
16 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
16 'user_agent': 'Client user agent, e.g git or mercurial CLI version',
17 })
17 })
18 def _pre_push_hook(*args, **kwargs):
18 def _pre_push_hook(*args, **kwargs):
19 """
19 """
20 Post push hook
20 Post push hook
21 To stop version control from storing the transaction and send a message to user
21 To stop version control from storing the transaction and send a message to user
22 use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed')
22 use non-zero HookResponse with a message, e.g return HookResponse(1, 'Not allowed')
23
23
24 This message will be shown back to client during PUSH operation
24 This message will be shown back to client during PUSH operation
25
25
26 Commit ids might look like that::
26 Commit ids might look like that::
27
27
28 [{u'hg_env|git_env': ...,
28 [{u'hg_env|git_env': ...,
29 u'multiple_heads': [],
29 u'multiple_heads': [],
30 u'name': u'default',
30 u'name': u'default',
31 u'new_rev': u'd0b2ae0692e722e01d5677f27a104631cf798b69',
31 u'new_rev': u'd0b2ae0692e722e01d5677f27a104631cf798b69',
32 u'old_rev': u'd0b1ae0692e722e01d5677f27a104631cf798b69',
32 u'old_rev': u'd0b1ae0692e722e01d5677f27a104631cf798b69',
33 u'ref': u'',
33 u'ref': u'',
34 u'total_commits': 2,
34 u'total_commits': 2,
35 u'type': u'branch'}]
35 u'type': u'branch'}]
36 """
36 """
37 import fnmatch
37 import fnmatch
38 from .helpers import extra_fields, extract_pre_files
38 from .helpers import extra_fields, extract_pre_files
39 from .utils import str2bool, aslist
39 from .utils import str2bool, aslist
40 from rhodecode.lib.helpers import format_byte_size_binary
40 from rhodecode.lib.helpers import format_byte_size_binary
41
41
42 # returns list of dicts with key-val fetched from extra fields
42 # returns list of dicts with key-val fetched from extra fields
43 repo_extra_fields = extra_fields.run(**kwargs)
43 repo_extra_fields = extra_fields.run(**kwargs)
44
44
45 # optionally use 'extra fields' to control the logic per repo
45 # optionally use 'extra fields' to control the logic per repo
46 # e.g store a list of patterns to be forbidden e.g `*.exe, *.dump`
46 # e.g store a list of patterns to be forbidden e.g `*.exe, *.dump`
47 forbid_files = extra_fields.get_field(repo_extra_fields, key='forbid_files_glob',
47 forbid_files = extra_fields.get_field(repo_extra_fields, key='forbid_files_glob',
48 convert_type=False, default=[])
48 convert_type=False, default=[])
49 forbid_files = aslist(forbid_files)
49 forbid_files = aslist(forbid_files, sep=',')
50
50
51 # forbid_files = ['*'] # example pattern
51 # forbid_files = ['*'] # example pattern
52
52
53 # optionally get bytes limit for a single file, e.g 1024 for 1KB
53 # optionally get bytes limit for a single file, e.g 1024 for 1KB
54 forbid_size_over = extra_fields.get_field(repo_extra_fields, key='forbid_size_over',
54 forbid_size_over = extra_fields.get_field(repo_extra_fields, key='forbid_size_over',
55 convert_type=False, default=0)
55 convert_type=False, default=0)
56
56
57 forbid_size_over = int(forbid_size_over or 0)
57 forbid_size_over = int(forbid_size_over or 0)
58
58
59 # forbid_size_over = 1024 # example 1024
59 # forbid_size_over = 1024 # example 1024
60
60
61 def validate_file_name_and_size(file_data, forbidden_files=None, size_limit=None):
61 def validate_file_name_and_size(file_data, forbidden_files=None, size_limit=None):
62 """
62 """
63 This function validates comited files against some sort of rules.
63 This function validates comited files against some sort of rules.
64 It should return a valid boolean, and a reason for failure
64 It should return a valid boolean, and a reason for failure
65
65
66 file_data =[
66 file_data =[
67 'raw_diff', 'old_revision', 'stats', 'original_filename', 'is_limited_diff',
67 'raw_diff', 'old_revision', 'stats', 'original_filename', 'is_limited_diff',
68 'chunks', 'new_revision', 'operation', 'exceeds_limit', 'filename'
68 'chunks', 'new_revision', 'operation', 'exceeds_limit', 'filename'
69 ]
69 ]
70 file_data['ops'] = {
70 file_data['ops'] = {
71 # is file binary
71 # is file binary
72 'binary': False,
72 'binary': False,
73
73
74 # lines
74 # lines
75 'added': 32,
75 'added': 32,
76 'deleted': 0
76 'deleted': 0
77
77
78 'ops': {3: 'modified file'},
78 'ops': {3: 'modified file'},
79 'new_mode': '100644',
79 'new_mode': '100644',
80 'old_mode': None
80 'old_mode': None
81 }
81 }
82 """
82 """
83 file_name = file_data['filename']
83 file_name = file_data['filename']
84 operation = file_data['operation'] # can be A(dded), M(odified), D(eleted)
84 operation = file_data['operation'] # can be A(dded), M(odified), D(eleted)
85
85
86 # check files names
86 # check files names
87 if forbidden_files:
87 if forbidden_files:
88 reason = 'File {} is forbidden to be pushed'.format(file_name)
88 reason = 'File {} is forbidden to be pushed'.format(file_name)
89 for forbidden_pattern in forbid_files:
89 for forbidden_pattern in forbid_files:
90 # here we can also filter for operation, e.g if check for only ADDED files
90 # here we can also filter for operation, e.g if check for only ADDED files
91 # if operation == 'A':
91 # if operation == 'A':
92 if fnmatch.fnmatch(file_name, forbidden_pattern):
92 if fnmatch.fnmatch(file_name, forbidden_pattern):
93 return False, reason
93 return False, reason
94
94
95 # validate A(dded) files and size
95 # validate A(dded) files and size
96 if size_limit and operation == 'A':
96 if size_limit and operation == 'A':
97 if 'file_size' in file_data:
97 if 'file_size' in file_data:
98 size = file_data['file_size']
98 size = file_data['file_size']
99 else:
99 else:
100 size = len(file_data['raw_diff'])
100 size = len(file_data['raw_diff'])
101
101
102 reason = 'File {} size of {} bytes exceeds limit {}'.format(
102 reason = 'File {} size of {} bytes exceeds limit {}'.format(
103 file_name, format_byte_size_binary(size),
103 file_name, format_byte_size_binary(size),
104 format_byte_size_binary(size_limit))
104 format_byte_size_binary(size_limit))
105 if size > size_limit:
105 if size > size_limit:
106 return False, reason
106 return False, reason
107
107
108 return True, ''
108 return True, ''
109
109
110 if forbid_files or forbid_size_over:
110 if forbid_files or forbid_size_over:
111 # returns list of dicts with key-val fetched from extra fields
111 # returns list of dicts with key-val fetched from extra fields
112 file_list = extract_pre_files.run(**kwargs)
112 file_list = extract_pre_files.run(**kwargs)
113
113
114 for file_data in file_list:
114 for file_data in file_list:
115 file_valid, reason = validate_file_name_and_size(
115 file_valid, reason = validate_file_name_and_size(
116 file_data, forbid_files, forbid_size_over)
116 file_data, forbid_files, forbid_size_over)
117 if not file_valid:
117 if not file_valid:
118 return HookResponse(1, reason)
118 return HookResponse(1, reason)
119
119
120 return HookResponse(0, '')
120 return HookResponse(0, '')
General Comments 0
You need to be logged in to leave comments. Login now