##// END OF EJS Templates
Added handling of git hooks, extract pushed revisions and store them inside...
marcink -
r2402:2eeb2ed7 beta
parent child Browse files
Show More
@@ -0,0 +1,29 b''
1 #!/usr/bin/env python
2 import os
3 import sys
4
5 try:
6 import rhodecode
7 from rhodecode.lib.hooks import handle_git_post_receive
8 except ImportError:
9 rhodecode = None
10
11
12 def main():
13 if rhodecode is None:
14 # exit with success if we cannot import rhodecode !!
15 # this allows simply push to this repo even without
16 # rhodecode
17 sys.exit(0)
18
19 repo_path = os.path.abspath('.')
20 push_data = sys.stdin.read().strip().split(' ')
21 # os.environ is modified here by a subprocess call that
22 # runs git and later git executes this hook.
23 # Environ get's some additional info from rhodecode system
24 # like IP or username from basic-auth
25 handle_git_post_receive(repo_path, push_data, os.environ)
26 sys.exit(0)
27
28 if __name__ == '__main__':
29 main() No newline at end of file
@@ -139,7 +139,9 b' def log_push_action(ui, repo, **kwargs):'
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 = []
142 revs = kwargs.get('_git_revs', [])
143 if '_git_revs' in kwargs:
144 kwargs.pop('_git_revs')
143
145
144 action = action % ','.join(revs)
146 action = action % ','.join(revs)
145
147
@@ -190,3 +192,59 b' def log_create_repository(repository_dic'
190 return callback(**kw)
192 return callback(**kw)
191
193
192 return 0
194 return 0
195
196
197 def handle_git_post_receive(repo_path, revs, env):
198 """
199 A really hacky method that is runned by git pre-receive hook and logs
200 an push action together with pushed revisions. It's runned by subprocess
201 thus needs all info to be able to create a temp pylons enviroment, connect
202 to database and run the logging code. Hacky as sh**t but works. ps.
203 GIT SUCKS
204
205 :param repo_path:
206 :type repo_path:
207 :param revs:
208 :type revs:
209 :param env:
210 :type env:
211 """
212 from paste.deploy import appconfig
213 from sqlalchemy import engine_from_config
214 from rhodecode.config.environment import load_environment
215 from rhodecode.model import init_model
216 from rhodecode.model.db import RhodeCodeUi
217 from rhodecode.lib.utils import make_ui
218 from rhodecode.model.db import Repository
219
220 path, ini_name = os.path.split(env['RHODECODE_CONFIG_FILE'])
221 conf = appconfig('config:%s' % ini_name, relative_to=path)
222 load_environment(conf.global_conf, conf.local_conf)
223
224 engine = engine_from_config(conf, 'sqlalchemy.db1.')
225 init_model(engine)
226
227 baseui = make_ui('db')
228 repo = Repository.get_by_full_path(repo_path)
229
230 _hooks = dict(baseui.configitems('hooks')) or {}
231 # if push hook is enabled via web interface
232 if _hooks.get(RhodeCodeUi.HOOK_PUSH):
233
234 extras = {
235 'username': env['RHODECODE_USER'],
236 'repository': repo.repo_name,
237 'scm': 'git',
238 'action': 'push',
239 'ip': env['RHODECODE_CONFIG_IP'],
240 }
241 for k, v in extras.items():
242 baseui.setconfig('rhodecode_extras', k, v)
243 repo = repo.scm_instance
244 repo.ui = baseui
245 old_rev, new_rev = revs[0:-1]
246
247 cmd = 'log ' + old_rev + '..' + new_rev + ' --reverse --pretty=format:"%H"'
248 git_revs = repo.run_git_command(cmd)[0].splitlines()
249
250 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -41,7 +41,7 b' class GitRepository(object):'
41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
41 git_folder_signature = set(['config', 'head', 'info', 'objects', 'refs'])
42 commands = ['git-upload-pack', 'git-receive-pack']
42 commands = ['git-upload-pack', 'git-receive-pack']
43
43
44 def __init__(self, repo_name, content_path):
44 def __init__(self, repo_name, content_path, username):
45 files = set([f.lower() for f in os.listdir(content_path)])
45 files = set([f.lower() for f in os.listdir(content_path)])
46 if not (self.git_folder_signature.intersection(files)
46 if not (self.git_folder_signature.intersection(files)
47 == self.git_folder_signature):
47 == self.git_folder_signature):
@@ -50,6 +50,7 b' class GitRepository(object):'
50 self.valid_accepts = ['application/x-%s-result' %
50 self.valid_accepts = ['application/x-%s-result' %
51 c for c in self.commands]
51 c for c in self.commands]
52 self.repo_name = repo_name
52 self.repo_name = repo_name
53 self.username = username
53
54
54 def _get_fixedpath(self, path):
55 def _get_fixedpath(self, path):
55 """
56 """
@@ -115,11 +116,25 b' class GitRepository(object):'
115 inputstream = environ['wsgi.input']
116 inputstream = environ['wsgi.input']
116
117
117 try:
118 try:
119 gitenv = os.environ
120 from rhodecode import CONFIG
121 from rhodecode.lib.base import _get_ip_addr
122 gitenv['RHODECODE_USER'] = self.username
123 gitenv['RHODECODE_CONFIG_IP'] = _get_ip_addr(environ)
124 # forget all configs
125 gitenv['GIT_CONFIG_NOGLOBAL'] = '1'
126 # we need current .ini file used to later initialize rhodecode
127 # env and connect to db
128 gitenv['RHODECODE_CONFIG_FILE'] = CONFIG['__file__']
129 opts = dict(
130 env=gitenv
131 )
118 out = subprocessio.SubprocessIOChunker(
132 out = subprocessio.SubprocessIOChunker(
119 r'git %s --stateless-rpc "%s"' % (git_command[4:],
133 r'git %s --stateless-rpc "%s"' % (git_command[4:],
120 self.content_path),
134 self.content_path),
121 inputstream=inputstream
135 inputstream=inputstream,
122 )
136 **opts
137 )
123 except EnvironmentError, e:
138 except EnvironmentError, e:
124 log.exception(e)
139 log.exception(e)
125 raise exc.HTTPExpectationFailed()
140 raise exc.HTTPExpectationFailed()
@@ -156,7 +171,7 b' class GitRepository(object):'
156
171
157 class GitDirectory(object):
172 class GitDirectory(object):
158
173
159 def __init__(self, repo_root, repo_name):
174 def __init__(self, repo_root, repo_name, username):
160 repo_location = os.path.join(repo_root, repo_name)
175 repo_location = os.path.join(repo_root, repo_name)
161 if not os.path.isdir(repo_location):
176 if not os.path.isdir(repo_location):
162 raise OSError(repo_location)
177 raise OSError(repo_location)
@@ -164,19 +179,20 b' class GitDirectory(object):'
164 self.content_path = repo_location
179 self.content_path = repo_location
165 self.repo_name = repo_name
180 self.repo_name = repo_name
166 self.repo_location = repo_location
181 self.repo_location = repo_location
182 self.username = username
167
183
168 def __call__(self, environ, start_response):
184 def __call__(self, environ, start_response):
169 content_path = self.content_path
185 content_path = self.content_path
170 try:
186 try:
171 app = GitRepository(self.repo_name, content_path)
187 app = GitRepository(self.repo_name, content_path, self.username)
172 except (AssertionError, OSError):
188 except (AssertionError, OSError):
173 if os.path.isdir(os.path.join(content_path, '.git')):
189 if os.path.isdir(os.path.join(content_path, '.git')):
174 app = GitRepository(self.repo_name,
190 app = GitRepository(self.repo_name,
175 os.path.join(content_path, '.git'))
191 os.path.join(content_path, '.git'))
176 else:
192 else:
177 return exc.HTTPNotFound()(environ, start_response)
193 return exc.HTTPNotFound()(environ, start_response, self.username)
178 return app(environ, start_response)
194 return app(environ, start_response)
179
195
180
196
181 def make_wsgi_app(repo_name, repo_root):
197 def make_wsgi_app(repo_name, repo_root, username):
182 return GitDirectory(repo_root, repo_name)
198 return GitDirectory(repo_root, repo_name, username)
@@ -68,8 +68,9 b' dulserver.DEFAULT_HANDLERS = {'
68 'git-receive-pack': dulserver.ReceivePackHandler,
68 'git-receive-pack': dulserver.ReceivePackHandler,
69 }
69 }
70
70
71 from dulwich.repo import Repo
71 # not used for now until dulwich get's fixed
72 from dulwich.web import make_wsgi_chain
72 #from dulwich.repo import Repo
73 #from dulwich.web import make_wsgi_chain
73
74
74 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
75 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
75
76
@@ -77,7 +78,7 b' from rhodecode.lib.utils2 import safe_st'
77 from rhodecode.lib.base import BaseVCSController
78 from rhodecode.lib.base import BaseVCSController
78 from rhodecode.lib.auth import get_container_username
79 from rhodecode.lib.auth import get_container_username
79 from rhodecode.lib.utils import is_valid_repo, make_ui
80 from rhodecode.lib.utils import is_valid_repo, make_ui
80 from rhodecode.model.db import User
81 from rhodecode.model.db import User, RhodeCodeUi
81
82
82 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
83 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
83
84
@@ -205,13 +206,13 b' class SimpleGit(BaseVCSController):'
205 self._handle_githooks(repo_name, action, baseui, environ)
206 self._handle_githooks(repo_name, action, baseui, environ)
206
207
207 log.info('%s action on GIT repo "%s"' % (action, repo_name))
208 log.info('%s action on GIT repo "%s"' % (action, repo_name))
208 app = self.__make_app(repo_name, repo_path)
209 app = self.__make_app(repo_name, repo_path, username)
209 return app(environ, start_response)
210 return app(environ, start_response)
210 except Exception:
211 except Exception:
211 log.error(traceback.format_exc())
212 log.error(traceback.format_exc())
212 return HTTPInternalServerError()(environ, start_response)
213 return HTTPInternalServerError()(environ, start_response)
213
214
214 def __make_app(self, repo_name, repo_path):
215 def __make_app(self, repo_name, repo_path, username):
215 """
216 """
216 Make an wsgi application using dulserver
217 Make an wsgi application using dulserver
217
218
@@ -223,6 +224,7 b' class SimpleGit(BaseVCSController):'
223 app = make_wsgi_app(
224 app = make_wsgi_app(
224 repo_root=os.path.dirname(repo_path),
225 repo_root=os.path.dirname(repo_path),
225 repo_name=repo_name,
226 repo_name=repo_name,
227 username=username,
226 )
228 )
227 return app
229 return app
228
230
@@ -268,7 +270,10 b' class SimpleGit(BaseVCSController):'
268 return op
270 return op
269
271
270 def _handle_githooks(self, repo_name, action, baseui, environ):
272 def _handle_githooks(self, repo_name, action, baseui, environ):
271 from rhodecode.lib.hooks import log_pull_action, log_push_action
273 """
274 Handles pull action, push is handled by pre-receive hook
275 """
276 from rhodecode.lib.hooks import log_pull_action
272 service = environ['QUERY_STRING'].split('=')
277 service = environ['QUERY_STRING'].split('=')
273 if len(service) < 2:
278 if len(service) < 2:
274 return
279 return
@@ -278,12 +283,8 b' class SimpleGit(BaseVCSController):'
278 _repo = _repo.scm_instance
283 _repo = _repo.scm_instance
279 _repo._repo.ui = baseui
284 _repo._repo.ui = baseui
280
285
281 push_hook = 'pretxnchangegroup.push_logger'
282 pull_hook = 'preoutgoing.pull_logger'
283 _hooks = dict(baseui.configitems('hooks')) or {}
286 _hooks = dict(baseui.configitems('hooks')) or {}
284 if action == 'push' and _hooks.get(push_hook):
287 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
285 log_push_action(ui=baseui, repo=_repo._repo)
286 elif action == 'pull' and _hooks.get(pull_hook):
287 log_pull_action(ui=baseui, repo=_repo._repo)
288 log_pull_action(ui=baseui, repo=_repo._repo)
288
289
289 def __inject_extras(self, repo_path, baseui, extras={}):
290 def __inject_extras(self, repo_path, baseui, extras={}):
General Comments 0
You need to be logged in to leave comments. Login now