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