##// END OF EJS Templates
hooks: added new hooks for ssh support
marcink -
r276:c5ac49cc default
parent child Browse files
Show More
@@ -1,426 +1,475 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # RhodeCode VCSServer provides access to different vcs backends via network.
3 # RhodeCode VCSServer provides access to different vcs backends via network.
4 # Copyright (C) 2014-2017 RodeCode GmbH
4 # Copyright (C) 2014-2017 RodeCode GmbH
5 #
5 #
6 # This program is free software; you can redistribute it and/or modify
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
9 # (at your option) any later version.
10 #
10 #
11 # This program is distributed in the hope that it will be useful,
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
14 # GNU General Public License for more details.
15 #
15 #
16 # You should have received a copy of the GNU General Public License
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software Foundation,
17 # along with this program; if not, write to the Free Software Foundation,
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
19
20 import io
20 import io
21 import os
21 import sys
22 import sys
22 import json
23 import json
23 import logging
24 import logging
24 import collections
25 import collections
25 import importlib
26 import importlib
26 import subprocess
27 import subprocess
27
28
28 from httplib import HTTPConnection
29 from httplib import HTTPConnection
29
30
30
31
31 import mercurial.scmutil
32 import mercurial.scmutil
32 import mercurial.node
33 import mercurial.node
33 import simplejson as json
34 import simplejson as json
34
35
35 from vcsserver import exceptions
36 from vcsserver import exceptions
36
37
37 log = logging.getLogger(__name__)
38 log = logging.getLogger(__name__)
38
39
39
40
40 class HooksHttpClient(object):
41 class HooksHttpClient(object):
41 connection = None
42 connection = None
42
43
43 def __init__(self, hooks_uri):
44 def __init__(self, hooks_uri):
44 self.hooks_uri = hooks_uri
45 self.hooks_uri = hooks_uri
45
46
46 def __call__(self, method, extras):
47 def __call__(self, method, extras):
47 connection = HTTPConnection(self.hooks_uri)
48 connection = HTTPConnection(self.hooks_uri)
48 body = self._serialize(method, extras)
49 body = self._serialize(method, extras)
49 connection.request('POST', '/', body)
50 connection.request('POST', '/', body)
50 response = connection.getresponse()
51 response = connection.getresponse()
51 return json.loads(response.read())
52 return json.loads(response.read())
52
53
53 def _serialize(self, hook_name, extras):
54 def _serialize(self, hook_name, extras):
54 data = {
55 data = {
55 'method': hook_name,
56 'method': hook_name,
56 'extras': extras
57 'extras': extras
57 }
58 }
58 return json.dumps(data)
59 return json.dumps(data)
59
60
60
61
61 class HooksDummyClient(object):
62 class HooksDummyClient(object):
62 def __init__(self, hooks_module):
63 def __init__(self, hooks_module):
63 self._hooks_module = importlib.import_module(hooks_module)
64 self._hooks_module = importlib.import_module(hooks_module)
64
65
65 def __call__(self, hook_name, extras):
66 def __call__(self, hook_name, extras):
66 with self._hooks_module.Hooks() as hooks:
67 with self._hooks_module.Hooks() as hooks:
67 return getattr(hooks, hook_name)(extras)
68 return getattr(hooks, hook_name)(extras)
68
69
69
70
70 class RemoteMessageWriter(object):
71 class RemoteMessageWriter(object):
71 """Writer base class."""
72 """Writer base class."""
72 def write(self, message):
73 def write(self, message):
73 raise NotImplementedError()
74 raise NotImplementedError()
74
75
75
76
76 class HgMessageWriter(RemoteMessageWriter):
77 class HgMessageWriter(RemoteMessageWriter):
77 """Writer that knows how to send messages to mercurial clients."""
78 """Writer that knows how to send messages to mercurial clients."""
78
79
79 def __init__(self, ui):
80 def __init__(self, ui):
80 self.ui = ui
81 self.ui = ui
81
82
82 def write(self, message):
83 def write(self, message):
83 # TODO: Check why the quiet flag is set by default.
84 # TODO: Check why the quiet flag is set by default.
84 old = self.ui.quiet
85 old = self.ui.quiet
85 self.ui.quiet = False
86 self.ui.quiet = False
86 self.ui.status(message.encode('utf-8'))
87 self.ui.status(message.encode('utf-8'))
87 self.ui.quiet = old
88 self.ui.quiet = old
88
89
89
90
90 class GitMessageWriter(RemoteMessageWriter):
91 class GitMessageWriter(RemoteMessageWriter):
91 """Writer that knows how to send messages to git clients."""
92 """Writer that knows how to send messages to git clients."""
92
93
93 def __init__(self, stdout=None):
94 def __init__(self, stdout=None):
94 self.stdout = stdout or sys.stdout
95 self.stdout = stdout or sys.stdout
95
96
96 def write(self, message):
97 def write(self, message):
97 self.stdout.write(message.encode('utf-8'))
98 self.stdout.write(message.encode('utf-8'))
98
99
99
100
100 def _handle_exception(result):
101 def _handle_exception(result):
101 exception_class = result.get('exception')
102 exception_class = result.get('exception')
102 exception_traceback = result.get('exception_traceback')
103 exception_traceback = result.get('exception_traceback')
103
104
104 if exception_traceback:
105 if exception_traceback:
105 log.error('Got traceback from remote call:%s', exception_traceback)
106 log.error('Got traceback from remote call:%s', exception_traceback)
106
107
107 if exception_class == 'HTTPLockedRC':
108 if exception_class == 'HTTPLockedRC':
108 raise exceptions.RepositoryLockedException(*result['exception_args'])
109 raise exceptions.RepositoryLockedException(*result['exception_args'])
109 elif exception_class == 'RepositoryError':
110 elif exception_class == 'RepositoryError':
110 raise exceptions.VcsException(*result['exception_args'])
111 raise exceptions.VcsException(*result['exception_args'])
111 elif exception_class:
112 elif exception_class:
112 raise Exception('Got remote exception "%s" with args "%s"' %
113 raise Exception('Got remote exception "%s" with args "%s"' %
113 (exception_class, result['exception_args']))
114 (exception_class, result['exception_args']))
114
115
115
116
116 def _get_hooks_client(extras):
117 def _get_hooks_client(extras):
117 if 'hooks_uri' in extras:
118 if 'hooks_uri' in extras:
118 protocol = extras.get('hooks_protocol')
119 protocol = extras.get('hooks_protocol')
119 return HooksHttpClient(extras['hooks_uri'])
120 return HooksHttpClient(extras['hooks_uri'])
120 else:
121 else:
121 return HooksDummyClient(extras['hooks_module'])
122 return HooksDummyClient(extras['hooks_module'])
122
123
123
124
124 def _call_hook(hook_name, extras, writer):
125 def _call_hook(hook_name, extras, writer):
125 hooks = _get_hooks_client(extras)
126 hooks = _get_hooks_client(extras)
126 result = hooks(hook_name, extras)
127 result = hooks(hook_name, extras)
128 log.debug('Hooks got result: %s', result)
127 writer.write(result['output'])
129 writer.write(result['output'])
128 _handle_exception(result)
130 _handle_exception(result)
129
131
130 return result['status']
132 return result['status']
131
133
132
134
133 def _extras_from_ui(ui):
135 def _extras_from_ui(ui):
134 extras = json.loads(ui.config('rhodecode', 'RC_SCM_DATA'))
136 hook_data = ui.config('rhodecode', 'RC_SCM_DATA')
137 if not hook_data:
138 # maybe it's inside environ ?
139 hook_data = os.environ.get('RC_SCM_DATA')
140 extras = json.loads(hook_data)
135 return extras
141 return extras
136
142
137
143
138 def repo_size(ui, repo, **kwargs):
139 return _call_hook('repo_size', _extras_from_ui(ui), HgMessageWriter(ui))
140
141
142 def pre_pull(ui, repo, **kwargs):
143 return _call_hook('pre_pull', _extras_from_ui(ui), HgMessageWriter(ui))
144
145
146 def post_pull(ui, repo, **kwargs):
147 return _call_hook('post_pull', _extras_from_ui(ui), HgMessageWriter(ui))
148
149
150 def _rev_range_hash(repo, node):
144 def _rev_range_hash(repo, node):
151
145
152 commits = []
146 commits = []
153 for rev in xrange(repo[node], len(repo)):
147 for rev in xrange(repo[node], len(repo)):
154 ctx = repo[rev]
148 ctx = repo[rev]
155 commit_id = mercurial.node.hex(ctx.node())
149 commit_id = mercurial.node.hex(ctx.node())
156 branch = ctx.branch()
150 branch = ctx.branch()
157 commits.append((commit_id, branch))
151 commits.append((commit_id, branch))
158
152
159 return commits
153 return commits
160
154
161
155
156 def repo_size(ui, repo, **kwargs):
157 extras = _extras_from_ui(ui)
158 return _call_hook('repo_size', extras, HgMessageWriter(ui))
159
160
161 def pre_pull(ui, repo, **kwargs):
162 extras = _extras_from_ui(ui)
163 return _call_hook('pre_pull', extras, HgMessageWriter(ui))
164
165
166 def pre_pull_ssh(ui, repo, **kwargs):
167 if _extras_from_ui(ui).get('SSH'):
168 return pre_pull(ui, repo, **kwargs)
169 return 0
170
171
172 def post_pull(ui, repo, **kwargs):
173 extras = _extras_from_ui(ui)
174 return _call_hook('post_pull', extras, HgMessageWriter(ui))
175
176
177 def post_pull_ssh(ui, repo, **kwargs):
178 if _extras_from_ui(ui).get('SSH'):
179 return post_pull(ui, repo, **kwargs)
180 return 0
181
182
162 def pre_push(ui, repo, node=None, **kwargs):
183 def pre_push(ui, repo, node=None, **kwargs):
163 extras = _extras_from_ui(ui)
184 extras = _extras_from_ui(ui)
164
185
165 rev_data = []
186 rev_data = []
166 if node and kwargs.get('hooktype') == 'pretxnchangegroup':
187 if node and kwargs.get('hooktype') == 'pretxnchangegroup':
167 branches = collections.defaultdict(list)
188 branches = collections.defaultdict(list)
168 for commit_id, branch in _rev_range_hash(repo, node):
189 for commit_id, branch in _rev_range_hash(repo, node):
169 branches[branch].append(commit_id)
190 branches[branch].append(commit_id)
170
191
171 for branch, commits in branches.iteritems():
192 for branch, commits in branches.iteritems():
172 old_rev = kwargs.get('node_last') or commits[0]
193 old_rev = kwargs.get('node_last') or commits[0]
173 rev_data.append({
194 rev_data.append({
174 'old_rev': old_rev,
195 'old_rev': old_rev,
175 'new_rev': commits[-1],
196 'new_rev': commits[-1],
176 'ref': '',
197 'ref': '',
177 'type': 'branch',
198 'type': 'branch',
178 'name': branch,
199 'name': branch,
179 })
200 })
180
201
181 extras['commit_ids'] = rev_data
202 extras['commit_ids'] = rev_data
182 return _call_hook('pre_push', extras, HgMessageWriter(ui))
203 return _call_hook('pre_push', extras, HgMessageWriter(ui))
183
204
184
205
206 def pre_push_ssh(ui, repo, node=None, **kwargs):
207 if _extras_from_ui(ui).get('SSH'):
208 return pre_push(ui, repo, node, **kwargs)
209
210 return 0
211
212
213 def pre_push_ssh_auth(ui, repo, node=None, **kwargs):
214 extras = _extras_from_ui(ui)
215 if extras.get('SSH'):
216 permission = extras['SSH_PERMISSIONS']
217
218 if 'repository.write' == permission or 'repository.admin' == permission:
219 return 0
220
221 # non-zero ret code
222 return 1
223
224 return 0
225
226
185 def post_push(ui, repo, node, **kwargs):
227 def post_push(ui, repo, node, **kwargs):
186 extras = _extras_from_ui(ui)
228 extras = _extras_from_ui(ui)
187
229
188 commit_ids = []
230 commit_ids = []
189 branches = []
231 branches = []
190 bookmarks = []
232 bookmarks = []
191 tags = []
233 tags = []
192
234
193 for commit_id, branch in _rev_range_hash(repo, node):
235 for commit_id, branch in _rev_range_hash(repo, node):
194 commit_ids.append(commit_id)
236 commit_ids.append(commit_id)
195 if branch not in branches:
237 if branch not in branches:
196 branches.append(branch)
238 branches.append(branch)
197
239
198 if hasattr(ui, '_rc_pushkey_branches'):
240 if hasattr(ui, '_rc_pushkey_branches'):
199 bookmarks = ui._rc_pushkey_branches
241 bookmarks = ui._rc_pushkey_branches
200
242
201 extras['commit_ids'] = commit_ids
243 extras['commit_ids'] = commit_ids
202 extras['new_refs'] = {
244 extras['new_refs'] = {
203 'branches': branches,
245 'branches': branches,
204 'bookmarks': bookmarks,
246 'bookmarks': bookmarks,
205 'tags': tags
247 'tags': tags
206 }
248 }
207
249
208 return _call_hook('post_push', extras, HgMessageWriter(ui))
250 return _call_hook('post_push', extras, HgMessageWriter(ui))
209
251
210
252
253 def post_push_ssh(ui, repo, node, **kwargs):
254 if _extras_from_ui(ui).get('SSH'):
255 return post_push(ui, repo, node, **kwargs)
256 return 0
257
258
211 def key_push(ui, repo, **kwargs):
259 def key_push(ui, repo, **kwargs):
212 if kwargs['new'] != '0' and kwargs['namespace'] == 'bookmarks':
260 if kwargs['new'] != '0' and kwargs['namespace'] == 'bookmarks':
213 # store new bookmarks in our UI object propagated later to post_push
261 # store new bookmarks in our UI object propagated later to post_push
214 ui._rc_pushkey_branches = repo[kwargs['key']].bookmarks()
262 ui._rc_pushkey_branches = repo[kwargs['key']].bookmarks()
215 return
263 return
216
264
265
217 # backward compat
266 # backward compat
218 log_pull_action = post_pull
267 log_pull_action = post_pull
219
268
220 # backward compat
269 # backward compat
221 log_push_action = post_push
270 log_push_action = post_push
222
271
223
272
224 def handle_git_pre_receive(unused_repo_path, unused_revs, unused_env):
273 def handle_git_pre_receive(unused_repo_path, unused_revs, unused_env):
225 """
274 """
226 Old hook name: keep here for backward compatibility.
275 Old hook name: keep here for backward compatibility.
227
276
228 This is only required when the installed git hooks are not upgraded.
277 This is only required when the installed git hooks are not upgraded.
229 """
278 """
230 pass
279 pass
231
280
232
281
233 def handle_git_post_receive(unused_repo_path, unused_revs, unused_env):
282 def handle_git_post_receive(unused_repo_path, unused_revs, unused_env):
234 """
283 """
235 Old hook name: keep here for backward compatibility.
284 Old hook name: keep here for backward compatibility.
236
285
237 This is only required when the installed git hooks are not upgraded.
286 This is only required when the installed git hooks are not upgraded.
238 """
287 """
239 pass
288 pass
240
289
241
290
242 HookResponse = collections.namedtuple('HookResponse', ('status', 'output'))
291 HookResponse = collections.namedtuple('HookResponse', ('status', 'output'))
243
292
244
293
245 def git_pre_pull(extras):
294 def git_pre_pull(extras):
246 """
295 """
247 Pre pull hook.
296 Pre pull hook.
248
297
249 :param extras: dictionary containing the keys defined in simplevcs
298 :param extras: dictionary containing the keys defined in simplevcs
250 :type extras: dict
299 :type extras: dict
251
300
252 :return: status code of the hook. 0 for success.
301 :return: status code of the hook. 0 for success.
253 :rtype: int
302 :rtype: int
254 """
303 """
255 if 'pull' not in extras['hooks']:
304 if 'pull' not in extras['hooks']:
256 return HookResponse(0, '')
305 return HookResponse(0, '')
257
306
258 stdout = io.BytesIO()
307 stdout = io.BytesIO()
259 try:
308 try:
260 status = _call_hook('pre_pull', extras, GitMessageWriter(stdout))
309 status = _call_hook('pre_pull', extras, GitMessageWriter(stdout))
261 except Exception as error:
310 except Exception as error:
262 status = 128
311 status = 128
263 stdout.write('ERROR: %s\n' % str(error))
312 stdout.write('ERROR: %s\n' % str(error))
264
313
265 return HookResponse(status, stdout.getvalue())
314 return HookResponse(status, stdout.getvalue())
266
315
267
316
268 def git_post_pull(extras):
317 def git_post_pull(extras):
269 """
318 """
270 Post pull hook.
319 Post pull hook.
271
320
272 :param extras: dictionary containing the keys defined in simplevcs
321 :param extras: dictionary containing the keys defined in simplevcs
273 :type extras: dict
322 :type extras: dict
274
323
275 :return: status code of the hook. 0 for success.
324 :return: status code of the hook. 0 for success.
276 :rtype: int
325 :rtype: int
277 """
326 """
278 if 'pull' not in extras['hooks']:
327 if 'pull' not in extras['hooks']:
279 return HookResponse(0, '')
328 return HookResponse(0, '')
280
329
281 stdout = io.BytesIO()
330 stdout = io.BytesIO()
282 try:
331 try:
283 status = _call_hook('post_pull', extras, GitMessageWriter(stdout))
332 status = _call_hook('post_pull', extras, GitMessageWriter(stdout))
284 except Exception as error:
333 except Exception as error:
285 status = 128
334 status = 128
286 stdout.write('ERROR: %s\n' % error)
335 stdout.write('ERROR: %s\n' % error)
287
336
288 return HookResponse(status, stdout.getvalue())
337 return HookResponse(status, stdout.getvalue())
289
338
290
339
291 def _parse_git_ref_lines(revision_lines):
340 def _parse_git_ref_lines(revision_lines):
292 rev_data = []
341 rev_data = []
293 for revision_line in revision_lines or []:
342 for revision_line in revision_lines or []:
294 old_rev, new_rev, ref = revision_line.strip().split(' ')
343 old_rev, new_rev, ref = revision_line.strip().split(' ')
295 ref_data = ref.split('/', 2)
344 ref_data = ref.split('/', 2)
296 if ref_data[1] in ('tags', 'heads'):
345 if ref_data[1] in ('tags', 'heads'):
297 rev_data.append({
346 rev_data.append({
298 'old_rev': old_rev,
347 'old_rev': old_rev,
299 'new_rev': new_rev,
348 'new_rev': new_rev,
300 'ref': ref,
349 'ref': ref,
301 'type': ref_data[1],
350 'type': ref_data[1],
302 'name': ref_data[2],
351 'name': ref_data[2],
303 })
352 })
304 return rev_data
353 return rev_data
305
354
306
355
307 def git_pre_receive(unused_repo_path, revision_lines, env):
356 def git_pre_receive(unused_repo_path, revision_lines, env):
308 """
357 """
309 Pre push hook.
358 Pre push hook.
310
359
311 :param extras: dictionary containing the keys defined in simplevcs
360 :param extras: dictionary containing the keys defined in simplevcs
312 :type extras: dict
361 :type extras: dict
313
362
314 :return: status code of the hook. 0 for success.
363 :return: status code of the hook. 0 for success.
315 :rtype: int
364 :rtype: int
316 """
365 """
317 extras = json.loads(env['RC_SCM_DATA'])
366 extras = json.loads(env['RC_SCM_DATA'])
318 rev_data = _parse_git_ref_lines(revision_lines)
367 rev_data = _parse_git_ref_lines(revision_lines)
319 if 'push' not in extras['hooks']:
368 if 'push' not in extras['hooks']:
320 return 0
369 return 0
321 extras['commit_ids'] = rev_data
370 extras['commit_ids'] = rev_data
322 return _call_hook('pre_push', extras, GitMessageWriter())
371 return _call_hook('pre_push', extras, GitMessageWriter())
323
372
324
373
325 def _run_command(arguments):
374 def _run_command(arguments):
326 """
375 """
327 Run the specified command and return the stdout.
376 Run the specified command and return the stdout.
328
377
329 :param arguments: sequence of program arguments (including the program name)
378 :param arguments: sequence of program arguments (including the program name)
330 :type arguments: list[str]
379 :type arguments: list[str]
331 """
380 """
332 # TODO(skreft): refactor this method and all the other similar ones.
381 # TODO(skreft): refactor this method and all the other similar ones.
333 # Probably this should be using subprocessio.
382 # Probably this should be using subprocessio.
334 process = subprocess.Popen(
383 process = subprocess.Popen(
335 arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
384 arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
336 stdout, stderr = process.communicate()
385 stdout, stderr = process.communicate()
337
386
338 if process.returncode != 0:
387 if process.returncode != 0:
339 raise Exception(
388 raise Exception(
340 'Command %s exited with exit code %s: stderr:%s' % (
389 'Command %s exited with exit code %s: stderr:%s' % (
341 arguments, process.returncode, stderr))
390 arguments, process.returncode, stderr))
342
391
343 return stdout
392 return stdout
344
393
345
394
346 def git_post_receive(unused_repo_path, revision_lines, env):
395 def git_post_receive(unused_repo_path, revision_lines, env):
347 """
396 """
348 Post push hook.
397 Post push hook.
349
398
350 :param extras: dictionary containing the keys defined in simplevcs
399 :param extras: dictionary containing the keys defined in simplevcs
351 :type extras: dict
400 :type extras: dict
352
401
353 :return: status code of the hook. 0 for success.
402 :return: status code of the hook. 0 for success.
354 :rtype: int
403 :rtype: int
355 """
404 """
356 extras = json.loads(env['RC_SCM_DATA'])
405 extras = json.loads(env['RC_SCM_DATA'])
357 if 'push' not in extras['hooks']:
406 if 'push' not in extras['hooks']:
358 return 0
407 return 0
359
408
360 rev_data = _parse_git_ref_lines(revision_lines)
409 rev_data = _parse_git_ref_lines(revision_lines)
361
410
362 git_revs = []
411 git_revs = []
363
412
364 # N.B.(skreft): it is ok to just call git, as git before calling a
413 # N.B.(skreft): it is ok to just call git, as git before calling a
365 # subcommand sets the PATH environment variable so that it point to the
414 # subcommand sets the PATH environment variable so that it point to the
366 # correct version of the git executable.
415 # correct version of the git executable.
367 empty_commit_id = '0' * 40
416 empty_commit_id = '0' * 40
368 branches = []
417 branches = []
369 tags = []
418 tags = []
370 for push_ref in rev_data:
419 for push_ref in rev_data:
371 type_ = push_ref['type']
420 type_ = push_ref['type']
372
421
373 if type_ == 'heads':
422 if type_ == 'heads':
374 if push_ref['old_rev'] == empty_commit_id:
423 if push_ref['old_rev'] == empty_commit_id:
375 # starting new branch case
424 # starting new branch case
376 if push_ref['name'] not in branches:
425 if push_ref['name'] not in branches:
377 branches.append(push_ref['name'])
426 branches.append(push_ref['name'])
378
427
379 # Fix up head revision if needed
428 # Fix up head revision if needed
380 cmd = ['git', 'show', 'HEAD']
429 cmd = ['git', 'show', 'HEAD']
381 try:
430 try:
382 _run_command(cmd)
431 _run_command(cmd)
383 except Exception:
432 except Exception:
384 cmd = ['git', 'symbolic-ref', 'HEAD',
433 cmd = ['git', 'symbolic-ref', 'HEAD',
385 'refs/heads/%s' % push_ref['name']]
434 'refs/heads/%s' % push_ref['name']]
386 print("Setting default branch to %s" % push_ref['name'])
435 print("Setting default branch to %s" % push_ref['name'])
387 _run_command(cmd)
436 _run_command(cmd)
388
437
389 cmd = ['git', 'for-each-ref', '--format=%(refname)',
438 cmd = ['git', 'for-each-ref', '--format=%(refname)',
390 'refs/heads/*']
439 'refs/heads/*']
391 heads = _run_command(cmd)
440 heads = _run_command(cmd)
392 heads = heads.replace(push_ref['ref'], '')
441 heads = heads.replace(push_ref['ref'], '')
393 heads = ' '.join(head for head in heads.splitlines() if head)
442 heads = ' '.join(head for head in heads.splitlines() if head)
394 cmd = ['git', 'log', '--reverse', '--pretty=format:%H',
443 cmd = ['git', 'log', '--reverse', '--pretty=format:%H',
395 '--', push_ref['new_rev'], '--not', heads]
444 '--', push_ref['new_rev'], '--not', heads]
396 git_revs.extend(_run_command(cmd).splitlines())
445 git_revs.extend(_run_command(cmd).splitlines())
397 elif push_ref['new_rev'] == empty_commit_id:
446 elif push_ref['new_rev'] == empty_commit_id:
398 # delete branch case
447 # delete branch case
399 git_revs.append('delete_branch=>%s' % push_ref['name'])
448 git_revs.append('delete_branch=>%s' % push_ref['name'])
400 else:
449 else:
401 if push_ref['name'] not in branches:
450 if push_ref['name'] not in branches:
402 branches.append(push_ref['name'])
451 branches.append(push_ref['name'])
403
452
404 cmd = ['git', 'log',
453 cmd = ['git', 'log',
405 '{old_rev}..{new_rev}'.format(**push_ref),
454 '{old_rev}..{new_rev}'.format(**push_ref),
406 '--reverse', '--pretty=format:%H']
455 '--reverse', '--pretty=format:%H']
407 git_revs.extend(_run_command(cmd).splitlines())
456 git_revs.extend(_run_command(cmd).splitlines())
408 elif type_ == 'tags':
457 elif type_ == 'tags':
409 if push_ref['name'] not in tags:
458 if push_ref['name'] not in tags:
410 tags.append(push_ref['name'])
459 tags.append(push_ref['name'])
411 git_revs.append('tag=>%s' % push_ref['name'])
460 git_revs.append('tag=>%s' % push_ref['name'])
412
461
413 extras['commit_ids'] = git_revs
462 extras['commit_ids'] = git_revs
414 extras['new_refs'] = {
463 extras['new_refs'] = {
415 'branches': branches,
464 'branches': branches,
416 'bookmarks': [],
465 'bookmarks': [],
417 'tags': tags,
466 'tags': tags,
418 }
467 }
419
468
420 if 'repo_size' in extras['hooks']:
469 if 'repo_size' in extras['hooks']:
421 try:
470 try:
422 _call_hook('repo_size', extras, GitMessageWriter())
471 _call_hook('repo_size', extras, GitMessageWriter())
423 except:
472 except:
424 pass
473 pass
425
474
426 return _call_hook('post_push', extras, GitMessageWriter())
475 return _call_hook('post_push', extras, GitMessageWriter())
General Comments 0
You need to be logged in to leave comments. Login now