##// END OF EJS Templates
Fixed githooks for fetching multiple tags and branches....
marcink -
r2617:c0ec29b2 beta
parent child Browse files
Show More
@@ -1,29 +1,31 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 import os
2 import os
3 import sys
3 import sys
4
4
5 try:
5 try:
6 import rhodecode
6 import rhodecode
7 RC_HOOK_VER = '_TMPL_'
8 os.environ['RC_HOOK_VER'] = RC_HOOK_VER
7 from rhodecode.lib.hooks import handle_git_post_receive
9 from rhodecode.lib.hooks import handle_git_post_receive
8 except ImportError:
10 except ImportError:
9 rhodecode = None
11 rhodecode = None
10
12
11
13
12 def main():
14 def main():
13 if rhodecode is None:
15 if rhodecode is None:
14 # exit with success if we cannot import rhodecode !!
16 # exit with success if we cannot import rhodecode !!
15 # this allows simply push to this repo even without
17 # this allows simply push to this repo even without
16 # rhodecode
18 # rhodecode
17 sys.exit(0)
19 sys.exit(0)
18
20
19 repo_path = os.path.abspath('.')
21 repo_path = os.path.abspath('.')
20 push_data = sys.stdin.read().strip().split(' ')
22 push_data = sys.stdin.readlines()
21 # os.environ is modified here by a subprocess call that
23 # os.environ is modified here by a subprocess call that
22 # runs git and later git executes this hook.
24 # runs git and later git executes this hook.
23 # Environ get's some additional info from rhodecode system
25 # Environ get's some additional info from rhodecode system
24 # like IP or username from basic-auth
26 # like IP or username from basic-auth
25 handle_git_post_receive(repo_path, push_data, os.environ)
27 handle_git_post_receive(repo_path, push_data, os.environ)
26 sys.exit(0)
28 sys.exit(0)
27
29
28 if __name__ == '__main__':
30 if __name__ == '__main__':
29 main()
31 main()
@@ -1,259 +1,278 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.hooks
3 rhodecode.lib.hooks
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Hooks runned by rhodecode
6 Hooks runned by rhodecode
7
7
8 :created_on: Aug 6, 2010
8 :created_on: Aug 6, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 import os
25 import os
26 import sys
26 import sys
27 import binascii
27 import binascii
28 from inspect import isfunction
28 from inspect import isfunction
29
29
30 from mercurial.scmutil import revrange
30 from mercurial.scmutil import revrange
31 from mercurial.node import nullrev
31 from mercurial.node import nullrev
32
32
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.lib.utils import action_logger
34 from rhodecode.lib.utils import action_logger
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
35 from rhodecode.lib.vcs.backends.base import EmptyChangeset
36
36
37
37
38 def _get_scm_size(alias, root_path):
38 def _get_scm_size(alias, root_path):
39
39
40 if not alias.startswith('.'):
40 if not alias.startswith('.'):
41 alias += '.'
41 alias += '.'
42
42
43 size_scm, size_root = 0, 0
43 size_scm, size_root = 0, 0
44 for path, dirs, files in os.walk(root_path):
44 for path, dirs, files in os.walk(root_path):
45 if path.find(alias) != -1:
45 if path.find(alias) != -1:
46 for f in files:
46 for f in files:
47 try:
47 try:
48 size_scm += os.path.getsize(os.path.join(path, f))
48 size_scm += os.path.getsize(os.path.join(path, f))
49 except OSError:
49 except OSError:
50 pass
50 pass
51 else:
51 else:
52 for f in files:
52 for f in files:
53 try:
53 try:
54 size_root += os.path.getsize(os.path.join(path, f))
54 size_root += os.path.getsize(os.path.join(path, f))
55 except OSError:
55 except OSError:
56 pass
56 pass
57
57
58 size_scm_f = h.format_byte_size(size_scm)
58 size_scm_f = h.format_byte_size(size_scm)
59 size_root_f = h.format_byte_size(size_root)
59 size_root_f = h.format_byte_size(size_root)
60 size_total_f = h.format_byte_size(size_root + size_scm)
60 size_total_f = h.format_byte_size(size_root + size_scm)
61
61
62 return size_scm_f, size_root_f, size_total_f
62 return size_scm_f, size_root_f, size_total_f
63
63
64
64
65 def repo_size(ui, repo, hooktype=None, **kwargs):
65 def repo_size(ui, repo, hooktype=None, **kwargs):
66 """
66 """
67 Presents size of repository after push
67 Presents size of repository after push
68
68
69 :param ui:
69 :param ui:
70 :param repo:
70 :param repo:
71 :param hooktype:
71 :param hooktype:
72 """
72 """
73
73
74 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
74 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
75
75
76 last_cs = repo[len(repo) - 1]
76 last_cs = repo[len(repo) - 1]
77
77
78 msg = ('Repository size .hg:%s repo:%s total:%s\n'
78 msg = ('Repository size .hg:%s repo:%s total:%s\n'
79 'Last revision is now r%s:%s\n') % (
79 'Last revision is now r%s:%s\n') % (
80 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
80 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
81 )
81 )
82
82
83 sys.stdout.write(msg)
83 sys.stdout.write(msg)
84
84
85
85
86 def log_pull_action(ui, repo, **kwargs):
86 def log_pull_action(ui, repo, **kwargs):
87 """
87 """
88 Logs user last pull action
88 Logs user last pull action
89
89
90 :param ui:
90 :param ui:
91 :param repo:
91 :param repo:
92 """
92 """
93 extras = dict(repo.ui.configitems('rhodecode_extras'))
93 extras = dict(repo.ui.configitems('rhodecode_extras'))
94 username = extras['username']
94 username = extras['username']
95 repository = extras['repository']
95 repository = extras['repository']
96 scm = extras['scm']
96 scm = extras['scm']
97 action = 'pull'
97 action = 'pull'
98
98
99 action_logger(username, action, repository, extras['ip'], commit=True)
99 action_logger(username, action, repository, extras['ip'], commit=True)
100 # extension hook call
100 # extension hook call
101 from rhodecode import EXTENSIONS
101 from rhodecode import EXTENSIONS
102 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
102 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
103
103
104 if isfunction(callback):
104 if isfunction(callback):
105 kw = {}
105 kw = {}
106 kw.update(extras)
106 kw.update(extras)
107 callback(**kw)
107 callback(**kw)
108 return 0
108 return 0
109
109
110
110
111 def log_push_action(ui, repo, **kwargs):
111 def log_push_action(ui, repo, **kwargs):
112 """
112 """
113 Maps user last push action to new changeset id, from mercurial
113 Maps user last push action to new changeset id, from mercurial
114
114
115 :param ui:
115 :param ui:
116 :param repo: repo object containing the `ui` object
116 :param repo: repo object containing the `ui` object
117 """
117 """
118
118
119 extras = dict(repo.ui.configitems('rhodecode_extras'))
119 extras = dict(repo.ui.configitems('rhodecode_extras'))
120 username = extras['username']
120 username = extras['username']
121 repository = extras['repository']
121 repository = extras['repository']
122 action = extras['action'] + ':%s'
122 action = extras['action'] + ':%s'
123 scm = extras['scm']
123 scm = extras['scm']
124
124
125 if scm == 'hg':
125 if scm == 'hg':
126 node = kwargs['node']
126 node = kwargs['node']
127
127
128 def get_revs(repo, rev_opt):
128 def get_revs(repo, rev_opt):
129 if rev_opt:
129 if rev_opt:
130 revs = revrange(repo, rev_opt)
130 revs = revrange(repo, rev_opt)
131
131
132 if len(revs) == 0:
132 if len(revs) == 0:
133 return (nullrev, nullrev)
133 return (nullrev, nullrev)
134 return (max(revs), min(revs))
134 return (max(revs), min(revs))
135 else:
135 else:
136 return (len(repo) - 1, 0)
136 return (len(repo) - 1, 0)
137
137
138 stop, start = get_revs(repo, [node + ':'])
138 stop, start = get_revs(repo, [node + ':'])
139 h = binascii.hexlify
139 h = binascii.hexlify
140 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
140 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
141 elif scm == 'git':
141 elif scm == 'git':
142 revs = kwargs.get('_git_revs', [])
142 revs = kwargs.get('_git_revs', [])
143 if '_git_revs' in kwargs:
143 if '_git_revs' in kwargs:
144 kwargs.pop('_git_revs')
144 kwargs.pop('_git_revs')
145
145
146 action = action % ','.join(revs)
146 action = action % ','.join(revs)
147
147
148 action_logger(username, action, repository, extras['ip'], commit=True)
148 action_logger(username, action, repository, extras['ip'], commit=True)
149
149
150 # extension hook call
150 # extension hook call
151 from rhodecode import EXTENSIONS
151 from rhodecode import EXTENSIONS
152 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
152 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
153 if isfunction(callback):
153 if isfunction(callback):
154 kw = {'pushed_revs': revs}
154 kw = {'pushed_revs': revs}
155 kw.update(extras)
155 kw.update(extras)
156 callback(**kw)
156 callback(**kw)
157 return 0
157 return 0
158
158
159
159
160 def log_create_repository(repository_dict, created_by, **kwargs):
160 def log_create_repository(repository_dict, created_by, **kwargs):
161 """
161 """
162 Post create repository Hook. This is a dummy function for admins to re-use
162 Post create repository Hook. This is a dummy function for admins to re-use
163 if needed. It's taken from rhodecode-extensions module and executed
163 if needed. It's taken from rhodecode-extensions module and executed
164 if present
164 if present
165
165
166 :param repository: dict dump of repository object
166 :param repository: dict dump of repository object
167 :param created_by: username who created repository
167 :param created_by: username who created repository
168 :param created_date: date of creation
168 :param created_date: date of creation
169
169
170 available keys of repository_dict:
170 available keys of repository_dict:
171
171
172 'repo_type',
172 'repo_type',
173 'description',
173 'description',
174 'private',
174 'private',
175 'created_on',
175 'created_on',
176 'enable_downloads',
176 'enable_downloads',
177 'repo_id',
177 'repo_id',
178 'user_id',
178 'user_id',
179 'enable_statistics',
179 'enable_statistics',
180 'clone_uri',
180 'clone_uri',
181 'fork_id',
181 'fork_id',
182 'group_id',
182 'group_id',
183 'repo_name'
183 'repo_name'
184
184
185 """
185 """
186 from rhodecode import EXTENSIONS
186 from rhodecode import EXTENSIONS
187 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
187 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
188 if isfunction(callback):
188 if isfunction(callback):
189 kw = {}
189 kw = {}
190 kw.update(repository_dict)
190 kw.update(repository_dict)
191 kw.update({'created_by': created_by})
191 kw.update({'created_by': created_by})
192 kw.update(kwargs)
192 kw.update(kwargs)
193 return callback(**kw)
193 return callback(**kw)
194
194
195 return 0
195 return 0
196
196
197
197
198 def handle_git_post_receive(repo_path, revs, env):
198 def handle_git_post_receive(repo_path, revs, env):
199 """
199 """
200 A really hacky method that is runned by git post-receive hook and logs
200 A really hacky method that is runned by git post-receive hook and logs
201 an push action together with pushed revisions. It's executed by subprocess
201 an push action together with pushed revisions. It's executed by subprocess
202 thus needs all info to be able to create a on the fly pylons enviroment,
202 thus needs all info to be able to create a on the fly pylons enviroment,
203 connect to database and run the logging code. Hacky as sh*t but works.
203 connect to database and run the logging code. Hacky as sh*t but works.
204
204
205 :param repo_path:
205 :param repo_path:
206 :type repo_path:
206 :type repo_path:
207 :param revs:
207 :param revs:
208 :type revs:
208 :type revs:
209 :param env:
209 :param env:
210 :type env:
210 :type env:
211 """
211 """
212 from paste.deploy import appconfig
212 from paste.deploy import appconfig
213 from sqlalchemy import engine_from_config
213 from sqlalchemy import engine_from_config
214 from rhodecode.config.environment import load_environment
214 from rhodecode.config.environment import load_environment
215 from rhodecode.model import init_model
215 from rhodecode.model import init_model
216 from rhodecode.model.db import RhodeCodeUi
216 from rhodecode.model.db import RhodeCodeUi
217 from rhodecode.lib.utils import make_ui
217 from rhodecode.lib.utils import make_ui
218 from rhodecode.model.db import Repository
218 from rhodecode.model.db import Repository
219
219
220 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
220 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
221 conf = appconfig('config:%s' % ini_name, relative_to=path)
221 conf = appconfig('config:%s' % ini_name, relative_to=path)
222 load_environment(conf.global_conf, conf.local_conf)
222 load_environment(conf.global_conf, conf.local_conf)
223
223
224 engine = engine_from_config(conf, 'sqlalchemy.db1.')
224 engine = engine_from_config(conf, 'sqlalchemy.db1.')
225 init_model(engine)
225 init_model(engine)
226
226
227 baseui = make_ui('db')
227 baseui = make_ui('db')
228 # fix if it's not a bare repo
229 if repo_path.endswith('.git'):
230 repo_path = repo_path[:-4]
228 repo = Repository.get_by_full_path(repo_path)
231 repo = Repository.get_by_full_path(repo_path)
229
230 _hooks = dict(baseui.configitems('hooks')) or {}
232 _hooks = dict(baseui.configitems('hooks')) or {}
231 # if push hook is enabled via web interface
233 # if push hook is enabled via web interface
232 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
234 if repo and _hooks.get(RhodeCodeUi.HOOK_PUSH):
233
235
234 extras = {
236 extras = {
235 'username': env['RHODECODE_USER'],
237 'username': env['RHODECODE_USER'],
236 'repository': repo.repo_name,
238 'repository': repo.repo_name,
237 'scm': 'git',
239 'scm': 'git',
238 'action': 'push',
240 'action': 'push',
239 'ip': env['RHODECODE_CONFIG_IP'],
241 'ip': env['RHODECODE_CONFIG_IP'],
240 }
242 }
241 for k, v in extras.items():
243 for k, v in extras.items():
242 baseui.setconfig('rhodecode_extras', k, v)
244 baseui.setconfig('rhodecode_extras', k, v)
243 repo = repo.scm_instance
245 repo = repo.scm_instance
244 repo.ui = baseui
246 repo.ui = baseui
245 old_rev, new_rev, ref = revs
247
246 if old_rev == EmptyChangeset().raw_id:
248 rev_data = []
247 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
249 for l in revs:
248 heads = repo.run_git_command(cmd)[0]
250 old_rev, new_rev, ref = l.split(' ')
249 heads = heads.replace(ref, '')
251 _ref_data = ref.split('/')
250 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
252 if _ref_data[1] in ['tags', 'heads']:
251 heads.splitlines()))
253 rev_data.append({'old_rev': old_rev,
252 cmd = ('log ' + new_rev +
254 'new_rev': new_rev,
253 ' --reverse --pretty=format:"%H" --not ' + heads)
255 'ref': ref,
254 else:
256 'type': _ref_data[1],
255 cmd = ('log ' + old_rev + '..' + new_rev +
257 'name': _ref_data[2].strip()})
256 ' --reverse --pretty=format:"%H"')
258
257 git_revs = repo.run_git_command(cmd)[0].splitlines()
259 git_revs = []
260 for push_ref in rev_data:
261 _type = push_ref['type']
262 if _type == 'heads':
263 if push_ref['old_rev'] == EmptyChangeset().raw_id:
264 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
265 heads = repo.run_git_command(cmd)[0]
266 heads = heads.replace(push_ref['ref'], '')
267 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
268 heads.splitlines()))
269 cmd = (('log %(new_rev)s' % push_ref) +
270 ' --reverse --pretty=format:"%H" --not ' + heads)
271 else:
272 cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
273 ' --reverse --pretty=format:"%H"')
274 git_revs += repo.run_git_command(cmd)[0].splitlines()
275 elif _type == 'tags':
276 git_revs += [push_ref['name']]
258
277
259 log_push_action(baseui, repo, _git_revs=git_revs)
278 log_push_action(baseui, repo, _git_revs=git_revs)
General Comments 0
You need to be logged in to leave comments. Login now