##// END OF EJS Templates
mercurial: move imports from top-level to prevent from loading mercurial code on hook execution for svn/git
marcink -
r802:4f496d5f default
parent child Browse files
Show More
@@ -1,720 +1,722 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # RhodeCode VCSServer provides access to different vcs backends via network.
4 4 # Copyright (C) 2014-2019 RhodeCode GmbH
5 5 #
6 6 # This program is free software; you can redistribute it and/or modify
7 7 # it under the terms of the GNU General Public License as published by
8 8 # the Free Software Foundation; either version 3 of the License, or
9 9 # (at your option) any later version.
10 10 #
11 11 # This program is distributed in the hope that it will be useful,
12 12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 14 # GNU General Public License for more details.
15 15 #
16 16 # You should have received a copy of the GNU General Public License
17 17 # along with this program; if not, write to the Free Software Foundation,
18 18 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 19
20 20 import io
21 21 import os
22 22 import sys
23 23 import logging
24 24 import collections
25 25 import importlib
26 26 import base64
27 27
28 28 from httplib import HTTPConnection
29 29
30 30
31 31 import mercurial.scmutil
32 32 import mercurial.node
33 33 import simplejson as json
34 34
35 35 from vcsserver import exceptions, subprocessio, settings
36 from vcsserver.hgcompat import get_ctx
37 36
38 37 log = logging.getLogger(__name__)
39 38
40 39
41 40 class HooksHttpClient(object):
42 41 connection = None
43 42
44 43 def __init__(self, hooks_uri):
45 44 self.hooks_uri = hooks_uri
46 45
47 46 def __call__(self, method, extras):
48 47 connection = HTTPConnection(self.hooks_uri)
49 48 body = self._serialize(method, extras)
50 49 try:
51 50 connection.request('POST', '/', body)
52 51 except Exception:
53 52 log.error('Connection failed on %s', connection)
54 53 raise
55 54 response = connection.getresponse()
56 55
57 56 response_data = response.read()
58 57
59 58 try:
60 59 return json.loads(response_data)
61 60 except Exception:
62 61 log.exception('Failed to decode hook response json data. '
63 62 'response_code:%s, raw_data:%s',
64 63 response.status, response_data)
65 64 raise
66 65
67 66 def _serialize(self, hook_name, extras):
68 67 data = {
69 68 'method': hook_name,
70 69 'extras': extras
71 70 }
72 71 return json.dumps(data)
73 72
74 73
75 74 class HooksDummyClient(object):
76 75 def __init__(self, hooks_module):
77 76 self._hooks_module = importlib.import_module(hooks_module)
78 77
79 78 def __call__(self, hook_name, extras):
80 79 with self._hooks_module.Hooks() as hooks:
81 80 return getattr(hooks, hook_name)(extras)
82 81
83 82
84 83 class HooksShadowRepoClient(object):
85 84
86 85 def __call__(self, hook_name, extras):
87 86 return {'output': '', 'status': 0}
88 87
89 88
90 89 class RemoteMessageWriter(object):
91 90 """Writer base class."""
92 91 def write(self, message):
93 92 raise NotImplementedError()
94 93
95 94
96 95 class HgMessageWriter(RemoteMessageWriter):
97 96 """Writer that knows how to send messages to mercurial clients."""
98 97
99 98 def __init__(self, ui):
100 99 self.ui = ui
101 100
102 101 def write(self, message):
103 102 # TODO: Check why the quiet flag is set by default.
104 103 old = self.ui.quiet
105 104 self.ui.quiet = False
106 105 self.ui.status(message.encode('utf-8'))
107 106 self.ui.quiet = old
108 107
109 108
110 109 class GitMessageWriter(RemoteMessageWriter):
111 110 """Writer that knows how to send messages to git clients."""
112 111
113 112 def __init__(self, stdout=None):
114 113 self.stdout = stdout or sys.stdout
115 114
116 115 def write(self, message):
117 116 self.stdout.write(message.encode('utf-8'))
118 117
119 118
120 119 class SvnMessageWriter(RemoteMessageWriter):
121 120 """Writer that knows how to send messages to svn clients."""
122 121
123 122 def __init__(self, stderr=None):
124 123 # SVN needs data sent to stderr for back-to-client messaging
125 124 self.stderr = stderr or sys.stderr
126 125
127 126 def write(self, message):
128 127 self.stderr.write(message.encode('utf-8'))
129 128
130 129
131 130 def _handle_exception(result):
132 131 exception_class = result.get('exception')
133 132 exception_traceback = result.get('exception_traceback')
134 133
135 134 if exception_traceback:
136 135 log.error('Got traceback from remote call:%s', exception_traceback)
137 136
138 137 if exception_class == 'HTTPLockedRC':
139 138 raise exceptions.RepositoryLockedException()(*result['exception_args'])
140 139 elif exception_class == 'HTTPBranchProtected':
141 140 raise exceptions.RepositoryBranchProtectedException()(*result['exception_args'])
142 141 elif exception_class == 'RepositoryError':
143 142 raise exceptions.VcsException()(*result['exception_args'])
144 143 elif exception_class:
145 144 raise Exception('Got remote exception "%s" with args "%s"' %
146 145 (exception_class, result['exception_args']))
147 146
148 147
149 148 def _get_hooks_client(extras):
150 149 hooks_uri = extras.get('hooks_uri')
151 150 is_shadow_repo = extras.get('is_shadow_repo')
152 151 if hooks_uri:
153 152 return HooksHttpClient(extras['hooks_uri'])
154 153 elif is_shadow_repo:
155 154 return HooksShadowRepoClient()
156 155 else:
157 156 return HooksDummyClient(extras['hooks_module'])
158 157
159 158
160 159 def _call_hook(hook_name, extras, writer):
161 160 hooks_client = _get_hooks_client(extras)
162 161 log.debug('Hooks, using client:%s', hooks_client)
163 162 result = hooks_client(hook_name, extras)
164 163 log.debug('Hooks got result: %s', result)
165 164
166 165 _handle_exception(result)
167 166 writer.write(result['output'])
168 167
169 168 return result['status']
170 169
171 170
172 171 def _extras_from_ui(ui):
173 172 hook_data = ui.config('rhodecode', 'RC_SCM_DATA')
174 173 if not hook_data:
175 174 # maybe it's inside environ ?
176 175 env_hook_data = os.environ.get('RC_SCM_DATA')
177 176 if env_hook_data:
178 177 hook_data = env_hook_data
179 178
180 179 extras = {}
181 180 if hook_data:
182 181 extras = json.loads(hook_data)
183 182 return extras
184 183
185 184
186 185 def _rev_range_hash(repo, node, check_heads=False):
186 from vcsserver.hgcompat import get_ctx
187 187
188 188 commits = []
189 189 revs = []
190 190 start = get_ctx(repo, node).rev()
191 191 end = len(repo)
192 192 for rev in range(start, end):
193 193 revs.append(rev)
194 194 ctx = get_ctx(repo, rev)
195 195 commit_id = mercurial.node.hex(ctx.node())
196 196 branch = ctx.branch()
197 197 commits.append((commit_id, branch))
198 198
199 199 parent_heads = []
200 200 if check_heads:
201 201 parent_heads = _check_heads(repo, start, end, revs)
202 202 return commits, parent_heads
203 203
204 204
205 205 def _check_heads(repo, start, end, commits):
206 from vcsserver.hgcompat import get_ctx
206 207 changelog = repo.changelog
207 208 parents = set()
208 209
209 210 for new_rev in commits:
210 211 for p in changelog.parentrevs(new_rev):
211 212 if p == mercurial.node.nullrev:
212 213 continue
213 214 if p < start:
214 215 parents.add(p)
215 216
216 217 for p in parents:
217 218 branch = get_ctx(repo, p).branch()
218 219 # The heads descending from that parent, on the same branch
219 220 parent_heads = set([p])
220 221 reachable = set([p])
221 222 for x in xrange(p + 1, end):
222 223 if get_ctx(repo, x).branch() != branch:
223 224 continue
224 225 for pp in changelog.parentrevs(x):
225 226 if pp in reachable:
226 227 reachable.add(x)
227 228 parent_heads.discard(pp)
228 229 parent_heads.add(x)
229 230 # More than one head? Suggest merging
230 231 if len(parent_heads) > 1:
231 232 return list(parent_heads)
232 233
233 234 return []
234 235
235 236
236 237 def _get_git_env():
237 238 env = {}
238 239 for k, v in os.environ.items():
239 240 if k.startswith('GIT'):
240 241 env[k] = v
241 242
242 243 # serialized version
243 244 return [(k, v) for k, v in env.items()]
244 245
245 246
246 247 def _get_hg_env(old_rev, new_rev, txnid, repo_path):
247 248 env = {}
248 249 for k, v in os.environ.items():
249 250 if k.startswith('HG'):
250 251 env[k] = v
251 252
252 253 env['HG_NODE'] = old_rev
253 254 env['HG_NODE_LAST'] = new_rev
254 255 env['HG_TXNID'] = txnid
255 256 env['HG_PENDING'] = repo_path
256 257
257 258 return [(k, v) for k, v in env.items()]
258 259
259 260
260 261 def repo_size(ui, repo, **kwargs):
261 262 extras = _extras_from_ui(ui)
262 263 return _call_hook('repo_size', extras, HgMessageWriter(ui))
263 264
264 265
265 266 def pre_pull(ui, repo, **kwargs):
266 267 extras = _extras_from_ui(ui)
267 268 return _call_hook('pre_pull', extras, HgMessageWriter(ui))
268 269
269 270
270 271 def pre_pull_ssh(ui, repo, **kwargs):
271 272 extras = _extras_from_ui(ui)
272 273 if extras and extras.get('SSH'):
273 274 return pre_pull(ui, repo, **kwargs)
274 275 return 0
275 276
276 277
277 278 def post_pull(ui, repo, **kwargs):
278 279 extras = _extras_from_ui(ui)
279 280 return _call_hook('post_pull', extras, HgMessageWriter(ui))
280 281
281 282
282 283 def post_pull_ssh(ui, repo, **kwargs):
283 284 extras = _extras_from_ui(ui)
284 285 if extras and extras.get('SSH'):
285 286 return post_pull(ui, repo, **kwargs)
286 287 return 0
287 288
288 289
289 290 def pre_push(ui, repo, node=None, **kwargs):
290 291 """
291 292 Mercurial pre_push hook
292 293 """
293 294 extras = _extras_from_ui(ui)
294 295 detect_force_push = extras.get('detect_force_push')
295 296
296 297 rev_data = []
297 298 if node and kwargs.get('hooktype') == 'pretxnchangegroup':
298 299 branches = collections.defaultdict(list)
299 300 commits, _heads = _rev_range_hash(repo, node, check_heads=detect_force_push)
300 301 for commit_id, branch in commits:
301 302 branches[branch].append(commit_id)
302 303
303 304 for branch, commits in branches.items():
304 305 old_rev = kwargs.get('node_last') or commits[0]
305 306 rev_data.append({
306 307 'total_commits': len(commits),
307 308 'old_rev': old_rev,
308 309 'new_rev': commits[-1],
309 310 'ref': '',
310 311 'type': 'branch',
311 312 'name': branch,
312 313 })
313 314
314 315 for push_ref in rev_data:
315 316 push_ref['multiple_heads'] = _heads
316 317
317 318 repo_path = os.path.join(
318 319 extras.get('repo_store', ''), extras.get('repository', ''))
319 320 push_ref['hg_env'] = _get_hg_env(
320 321 old_rev=push_ref['old_rev'],
321 322 new_rev=push_ref['new_rev'], txnid=kwargs.get('txnid'),
322 323 repo_path=repo_path)
323 324
324 325 extras['hook_type'] = kwargs.get('hooktype', 'pre_push')
325 326 extras['commit_ids'] = rev_data
326 327
327 328 return _call_hook('pre_push', extras, HgMessageWriter(ui))
328 329
329 330
330 331 def pre_push_ssh(ui, repo, node=None, **kwargs):
331 332 extras = _extras_from_ui(ui)
332 333 if extras.get('SSH'):
333 334 return pre_push(ui, repo, node, **kwargs)
334 335
335 336 return 0
336 337
337 338
338 339 def pre_push_ssh_auth(ui, repo, node=None, **kwargs):
339 340 """
340 341 Mercurial pre_push hook for SSH
341 342 """
342 343 extras = _extras_from_ui(ui)
343 344 if extras.get('SSH'):
344 345 permission = extras['SSH_PERMISSIONS']
345 346
346 347 if 'repository.write' == permission or 'repository.admin' == permission:
347 348 return 0
348 349
349 350 # non-zero ret code
350 351 return 1
351 352
352 353 return 0
353 354
354 355
355 356 def post_push(ui, repo, node, **kwargs):
356 357 """
357 358 Mercurial post_push hook
358 359 """
359 360 extras = _extras_from_ui(ui)
360 361
361 362 commit_ids = []
362 363 branches = []
363 364 bookmarks = []
364 365 tags = []
365 366
366 367 commits, _heads = _rev_range_hash(repo, node)
367 368 for commit_id, branch in commits:
368 369 commit_ids.append(commit_id)
369 370 if branch not in branches:
370 371 branches.append(branch)
371 372
372 373 if hasattr(ui, '_rc_pushkey_branches'):
373 374 bookmarks = ui._rc_pushkey_branches
374 375
375 376 extras['hook_type'] = kwargs.get('hooktype', 'post_push')
376 377 extras['commit_ids'] = commit_ids
377 378 extras['new_refs'] = {
378 379 'branches': branches,
379 380 'bookmarks': bookmarks,
380 381 'tags': tags
381 382 }
382 383
383 384 return _call_hook('post_push', extras, HgMessageWriter(ui))
384 385
385 386
386 387 def post_push_ssh(ui, repo, node, **kwargs):
387 388 """
388 389 Mercurial post_push hook for SSH
389 390 """
390 391 if _extras_from_ui(ui).get('SSH'):
391 392 return post_push(ui, repo, node, **kwargs)
392 393 return 0
393 394
394 395
395 396 def key_push(ui, repo, **kwargs):
397 from vcsserver.hgcompat import get_ctx
396 398 if kwargs['new'] != '0' and kwargs['namespace'] == 'bookmarks':
397 399 # store new bookmarks in our UI object propagated later to post_push
398 400 ui._rc_pushkey_branches = get_ctx(repo, kwargs['key']).bookmarks()
399 401 return
400 402
401 403
402 404 # backward compat
403 405 log_pull_action = post_pull
404 406
405 407 # backward compat
406 408 log_push_action = post_push
407 409
408 410
409 411 def handle_git_pre_receive(unused_repo_path, unused_revs, unused_env):
410 412 """
411 413 Old hook name: keep here for backward compatibility.
412 414
413 415 This is only required when the installed git hooks are not upgraded.
414 416 """
415 417 pass
416 418
417 419
418 420 def handle_git_post_receive(unused_repo_path, unused_revs, unused_env):
419 421 """
420 422 Old hook name: keep here for backward compatibility.
421 423
422 424 This is only required when the installed git hooks are not upgraded.
423 425 """
424 426 pass
425 427
426 428
427 429 HookResponse = collections.namedtuple('HookResponse', ('status', 'output'))
428 430
429 431
430 432 def git_pre_pull(extras):
431 433 """
432 434 Pre pull hook.
433 435
434 436 :param extras: dictionary containing the keys defined in simplevcs
435 437 :type extras: dict
436 438
437 439 :return: status code of the hook. 0 for success.
438 440 :rtype: int
439 441 """
440 442 if 'pull' not in extras['hooks']:
441 443 return HookResponse(0, '')
442 444
443 445 stdout = io.BytesIO()
444 446 try:
445 447 status = _call_hook('pre_pull', extras, GitMessageWriter(stdout))
446 448 except Exception as error:
447 449 status = 128
448 450 stdout.write('ERROR: %s\n' % str(error))
449 451
450 452 return HookResponse(status, stdout.getvalue())
451 453
452 454
453 455 def git_post_pull(extras):
454 456 """
455 457 Post pull hook.
456 458
457 459 :param extras: dictionary containing the keys defined in simplevcs
458 460 :type extras: dict
459 461
460 462 :return: status code of the hook. 0 for success.
461 463 :rtype: int
462 464 """
463 465 if 'pull' not in extras['hooks']:
464 466 return HookResponse(0, '')
465 467
466 468 stdout = io.BytesIO()
467 469 try:
468 470 status = _call_hook('post_pull', extras, GitMessageWriter(stdout))
469 471 except Exception as error:
470 472 status = 128
471 473 stdout.write('ERROR: %s\n' % error)
472 474
473 475 return HookResponse(status, stdout.getvalue())
474 476
475 477
476 478 def _parse_git_ref_lines(revision_lines):
477 479 rev_data = []
478 480 for revision_line in revision_lines or []:
479 481 old_rev, new_rev, ref = revision_line.strip().split(' ')
480 482 ref_data = ref.split('/', 2)
481 483 if ref_data[1] in ('tags', 'heads'):
482 484 rev_data.append({
483 485 # NOTE(marcink):
484 486 # we're unable to tell total_commits for git at this point
485 487 # but we set the variable for consistency with GIT
486 488 'total_commits': -1,
487 489 'old_rev': old_rev,
488 490 'new_rev': new_rev,
489 491 'ref': ref,
490 492 'type': ref_data[1],
491 493 'name': ref_data[2],
492 494 })
493 495 return rev_data
494 496
495 497
496 498 def git_pre_receive(unused_repo_path, revision_lines, env):
497 499 """
498 500 Pre push hook.
499 501
500 502 :param extras: dictionary containing the keys defined in simplevcs
501 503 :type extras: dict
502 504
503 505 :return: status code of the hook. 0 for success.
504 506 :rtype: int
505 507 """
506 508 extras = json.loads(env['RC_SCM_DATA'])
507 509 rev_data = _parse_git_ref_lines(revision_lines)
508 510 if 'push' not in extras['hooks']:
509 511 return 0
510 512 empty_commit_id = '0' * 40
511 513
512 514 detect_force_push = extras.get('detect_force_push')
513 515
514 516 for push_ref in rev_data:
515 517 # store our git-env which holds the temp store
516 518 push_ref['git_env'] = _get_git_env()
517 519 push_ref['pruned_sha'] = ''
518 520 if not detect_force_push:
519 521 # don't check for forced-push when we don't need to
520 522 continue
521 523
522 524 type_ = push_ref['type']
523 525 new_branch = push_ref['old_rev'] == empty_commit_id
524 526 delete_branch = push_ref['new_rev'] == empty_commit_id
525 527 if type_ == 'heads' and not (new_branch or delete_branch):
526 528 old_rev = push_ref['old_rev']
527 529 new_rev = push_ref['new_rev']
528 530 cmd = [settings.GIT_EXECUTABLE, 'rev-list', old_rev, '^{}'.format(new_rev)]
529 531 stdout, stderr = subprocessio.run_command(
530 532 cmd, env=os.environ.copy())
531 533 # means we're having some non-reachable objects, this forced push was used
532 534 if stdout:
533 535 push_ref['pruned_sha'] = stdout.splitlines()
534 536
535 537 extras['hook_type'] = 'pre_receive'
536 538 extras['commit_ids'] = rev_data
537 539 return _call_hook('pre_push', extras, GitMessageWriter())
538 540
539 541
540 542 def git_post_receive(unused_repo_path, revision_lines, env):
541 543 """
542 544 Post push hook.
543 545
544 546 :param extras: dictionary containing the keys defined in simplevcs
545 547 :type extras: dict
546 548
547 549 :return: status code of the hook. 0 for success.
548 550 :rtype: int
549 551 """
550 552 extras = json.loads(env['RC_SCM_DATA'])
551 553 if 'push' not in extras['hooks']:
552 554 return 0
553 555
554 556 rev_data = _parse_git_ref_lines(revision_lines)
555 557
556 558 git_revs = []
557 559
558 560 # N.B.(skreft): it is ok to just call git, as git before calling a
559 561 # subcommand sets the PATH environment variable so that it point to the
560 562 # correct version of the git executable.
561 563 empty_commit_id = '0' * 40
562 564 branches = []
563 565 tags = []
564 566 for push_ref in rev_data:
565 567 type_ = push_ref['type']
566 568
567 569 if type_ == 'heads':
568 570 if push_ref['old_rev'] == empty_commit_id:
569 571 # starting new branch case
570 572 if push_ref['name'] not in branches:
571 573 branches.append(push_ref['name'])
572 574
573 575 # Fix up head revision if needed
574 576 cmd = [settings.GIT_EXECUTABLE, 'show', 'HEAD']
575 577 try:
576 578 subprocessio.run_command(cmd, env=os.environ.copy())
577 579 except Exception:
578 580 cmd = [settings.GIT_EXECUTABLE, 'symbolic-ref', 'HEAD',
579 581 'refs/heads/%s' % push_ref['name']]
580 582 print("Setting default branch to %s" % push_ref['name'])
581 583 subprocessio.run_command(cmd, env=os.environ.copy())
582 584
583 585 cmd = [settings.GIT_EXECUTABLE, 'for-each-ref',
584 586 '--format=%(refname)', 'refs/heads/*']
585 587 stdout, stderr = subprocessio.run_command(
586 588 cmd, env=os.environ.copy())
587 589 heads = stdout
588 590 heads = heads.replace(push_ref['ref'], '')
589 591 heads = ' '.join(head for head
590 592 in heads.splitlines() if head) or '.'
591 593 cmd = [settings.GIT_EXECUTABLE, 'log', '--reverse',
592 594 '--pretty=format:%H', '--', push_ref['new_rev'],
593 595 '--not', heads]
594 596 stdout, stderr = subprocessio.run_command(
595 597 cmd, env=os.environ.copy())
596 598 git_revs.extend(stdout.splitlines())
597 599 elif push_ref['new_rev'] == empty_commit_id:
598 600 # delete branch case
599 601 git_revs.append('delete_branch=>%s' % push_ref['name'])
600 602 else:
601 603 if push_ref['name'] not in branches:
602 604 branches.append(push_ref['name'])
603 605
604 606 cmd = [settings.GIT_EXECUTABLE, 'log',
605 607 '{old_rev}..{new_rev}'.format(**push_ref),
606 608 '--reverse', '--pretty=format:%H']
607 609 stdout, stderr = subprocessio.run_command(
608 610 cmd, env=os.environ.copy())
609 611 git_revs.extend(stdout.splitlines())
610 612 elif type_ == 'tags':
611 613 if push_ref['name'] not in tags:
612 614 tags.append(push_ref['name'])
613 615 git_revs.append('tag=>%s' % push_ref['name'])
614 616
615 617 extras['hook_type'] = 'post_receive'
616 618 extras['commit_ids'] = git_revs
617 619 extras['new_refs'] = {
618 620 'branches': branches,
619 621 'bookmarks': [],
620 622 'tags': tags,
621 623 }
622 624
623 625 if 'repo_size' in extras['hooks']:
624 626 try:
625 627 _call_hook('repo_size', extras, GitMessageWriter())
626 628 except:
627 629 pass
628 630
629 631 return _call_hook('post_push', extras, GitMessageWriter())
630 632
631 633
632 634 def _get_extras_from_txn_id(path, txn_id):
633 635 extras = {}
634 636 try:
635 637 cmd = [settings.SVNLOOK_EXECUTABLE, 'pget',
636 638 '-t', txn_id,
637 639 '--revprop', path, 'rc-scm-extras']
638 640 stdout, stderr = subprocessio.run_command(
639 641 cmd, env=os.environ.copy())
640 642 extras = json.loads(base64.urlsafe_b64decode(stdout))
641 643 except Exception:
642 644 log.exception('Failed to extract extras info from txn_id')
643 645
644 646 return extras
645 647
646 648
647 649 def _get_extras_from_commit_id(commit_id, path):
648 650 extras = {}
649 651 try:
650 652 cmd = [settings.SVNLOOK_EXECUTABLE, 'pget',
651 653 '-r', commit_id,
652 654 '--revprop', path, 'rc-scm-extras']
653 655 stdout, stderr = subprocessio.run_command(
654 656 cmd, env=os.environ.copy())
655 657 extras = json.loads(base64.urlsafe_b64decode(stdout))
656 658 except Exception:
657 659 log.exception('Failed to extract extras info from commit_id')
658 660
659 661 return extras
660 662
661 663
662 664 def svn_pre_commit(repo_path, commit_data, env):
663 665 path, txn_id = commit_data
664 666 branches = []
665 667 tags = []
666 668
667 669 if env.get('RC_SCM_DATA'):
668 670 extras = json.loads(env['RC_SCM_DATA'])
669 671 else:
670 672 # fallback method to read from TXN-ID stored data
671 673 extras = _get_extras_from_txn_id(path, txn_id)
672 674 if not extras:
673 675 return 0
674 676
675 677 extras['hook_type'] = 'pre_commit'
676 678 extras['commit_ids'] = [txn_id]
677 679 extras['txn_id'] = txn_id
678 680 extras['new_refs'] = {
679 681 'total_commits': 1,
680 682 'branches': branches,
681 683 'bookmarks': [],
682 684 'tags': tags,
683 685 }
684 686
685 687 return _call_hook('pre_push', extras, SvnMessageWriter())
686 688
687 689
688 690 def svn_post_commit(repo_path, commit_data, env):
689 691 """
690 692 commit_data is path, rev, txn_id
691 693 """
692 694 path, commit_id, txn_id = commit_data
693 695 branches = []
694 696 tags = []
695 697
696 698 if env.get('RC_SCM_DATA'):
697 699 extras = json.loads(env['RC_SCM_DATA'])
698 700 else:
699 701 # fallback method to read from TXN-ID stored data
700 702 extras = _get_extras_from_commit_id(commit_id, path)
701 703 if not extras:
702 704 return 0
703 705
704 706 extras['hook_type'] = 'post_commit'
705 707 extras['commit_ids'] = [commit_id]
706 708 extras['txn_id'] = txn_id
707 709 extras['new_refs'] = {
708 710 'branches': branches,
709 711 'bookmarks': [],
710 712 'tags': tags,
711 713 'total_commits': 1,
712 714 }
713 715
714 716 if 'repo_size' in extras['hooks']:
715 717 try:
716 718 _call_hook('repo_size', extras, SvnMessageWriter())
717 719 except Exception:
718 720 pass
719 721
720 722 return _call_hook('post_push', extras, SvnMessageWriter())
General Comments 0
You need to be logged in to leave comments. Login now