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