xaizek / rocketgit (License: AGPLv3+) (since 2018-12-09)
Light and fast Git hosting solution suitable to serve both as a hub or as a personal code storage with its tickets, pull requests, API and much more.
Commit fa2a07bd822b496e65cee7c748429e9b69e91707

Hooks fixes
Author: Catalin(ux) M. BOIE
Author date (UTC): 2016-01-17 19:26
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2016-01-17 19:26
Parent(s): 85a7d584e031f9b3ce94e2520f998ec6698ca46a
Signing key:
Tree: 1209c3ed588f131b916e08ad680658a430403db9
File Lines added Lines deleted
TODO 12 12
inc/git.inc.php 2 0
inc/repo.inc.php 8 11
inc/struct.inc.php 7 1
inc/wh/cloud.inc.php 18 18
inc/wh/core.inc.php 31 12
inc/wh/http.inc.php 46 51
inc/wh/lambda.inc.php 26 16
root/themes/default/user/settings/wh/add_edit.html 10 0
root/themes/default/user/settings/wh/hints_tags.html 1 2
root/themes/default/user/settings/wh/lambda/form.html 1 1
root/themes/default/user/settings/wh/list/header.html 2 0
root/themes/default/user/settings/wh/list/line.html 2 0
tests/repo.php 20 0
tests/wh_cloud.php 6 2
tests/wh_http.php 10 1
File TODO changed (mode: 100644) (index ae20e25..a6656d1)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] wh: where do I specify the repo_id?!
3 [ ] wh: repo/branch/tag regex
4 [ ] wh: Add a regex filter for branches!
5 [ ] wh: unit test: events
6 [ ] wh: id of the hook appears as root-id, but also as root-info-id!
7 2 [ ] [ ]
8 3
9 4 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
5 [ ] wh: 2 members in a team, both must push to S3 - it is possible
6 with only one hook? If the other user can push, why not let her/him
7 execute the hook? The problem is that I have no link between the repo.
8 Maybe go to the repo and link the hooks? what about 'repo create'?
9 [ ] docker: document somewhere that is available and how to use it.
10 [ ] wh: Add a link to a "movie" explaining how with one hook you can cover both
11 production and evaluation deployments.
12 [ ] wh: notify user when a hook fails.
10 13 [ ] wh: trigger on assigning a tag? For example, trigger on [ ] wh: trigger on assigning a tag? For example, trigger on
11 14 adding a tag (regex match) to a ref (regex match). adding a tag (regex match) to a ref (regex match).
12 15 I do have two matches here! I do have two matches here!
 
34 37 [ ] I do not have rights to del_undel bugs, but I am still getting the [ ] I do not have rights to del_undel bugs, but I am still getting the
35 38 token (token_get). Not good. token (token_get). Not good.
36 39 [ ] Plan for webhooks: [ ] Plan for webhooks:
37 If we do 'include', take care of type to be aonly a-bA-B0-9_!
40 If we do 'include', take care of type to be only a-bA-B0-9_!
38 41 [ ] Do not show 'webhooks' menu if the login user has no rights. [ ] Do not show 'webhooks' menu if the login user has no rights.
39 This is for when we will allow webhooks per repo.
42 This is for when we will allow webhooks per repo. If.
40 43 [ ] Add labels for users and for repos/comments/etc.? [Also] private ones? [ ] Add labels for users and for repos/comments/etc.? [Also] private ones?
41 44 [ ] last events: gravatar [ ] last events: gravatar
42 45 [ ] last events: 2015-12-27 09:42 n/a Reference refs/heads/master created (290e4f7a70640d79836b3298c47b913484da24de) [ ] last events: 2015-12-27 09:42 n/a Reference refs/heads/master created (290e4f7a70640d79836b3298c47b913484da24de)
 
44 47 Should we just say so? Should we just say so?
45 48 [ ] rights: store '*' as equivalent for "all rights". Else, when we will add [ ] rights: store '*' as equivalent for "all rights". Else, when we will add
46 49 more rights, they will not be automatically added to the list. more rights, they will not be automatically added to the list.
47 [ ] http://r1i:9000/op/settings/wh looks wrong!
48 50 [ ] "Please login first"/"Login form" are now justified. [ ] "Please login first"/"Login form" are now justified.
49 51 [ ] Use rg_repo_has_rights. [ ] Use rg_repo_has_rights.
50 52 [ ] Do we stop event processing when we change the structure? [ ] Do we stop event processing when we change the structure?
 
73 75 http://thread.gmane.org/gmane.linux.network/390690 http://thread.gmane.org/gmane.linux.network/390690
74 76 [ ] si inca o chestie foarte utila ar fi sa pot accesa fisierul raw, fara line [ ] si inca o chestie foarte utila ar fi sa pot accesa fisierul raw, fara line
75 77 number, pentru a putea da copy la mai multe linii deodata (Gabi B) number, pentru a putea da copy la mai multe linii deodata (Gabi B)
78 Asta plus "Download".
76 79 [ ] o sugestie ar mai fi ca atunci cand sunt deja pe un fisier sa pot accesa [ ] o sugestie ar mai fi ca atunci cand sunt deja pe un fisier sa pot accesa
77 80 istoricul lui (Gabi) istoricul lui (Gabi)
78 81 [ ] tree: I have no "UP" folder or the list of dirs with links behind. [ ] tree: I have no "UP" folder or the list of dirs with links behind.
79 [ ] If a repo changes from public to private or the other way around,
80 I must invalidate the rights cache.
81 82 [ ] rights: if a user has 'admin/give_rights' rights, allow push? [ ] rights: if a user has 'admin/give_rights' rights, allow push?
82 83 [ ] wh: add prios - we may want to have a hook for storing in s3 and a hook for [ ] wh: add prios - we may want to have a hook for storing in s3 and a hook for
83 84 deployment. Hm. deployment. Hm.
 
87 88 [ ] amazon: allow deploy to multiple regions [ ] amazon: allow deploy to multiple regions
88 89 [ ] amazon: is clear that i have to use a role and a custom bucket [ ] amazon: is clear that i have to use a role and a custom bucket
89 90 Still investigating how to trigger a CodeDeploy task that will fetch Still investigating how to trigger a CodeDeploy task that will fetch
90 from repo and do the deploy. Not use if is possible.
91 from repo and do the deploy. Not use if is possible.
91 92 [ ] 2fa: m.google.com/authenticator - also for BlackBerry/iPhone/iPad [ ] 2fa: m.google.com/authenticator - also for BlackBerry/iPhone/iPad
92 [ ] At least refs rights are not reorder by priority! Bad!
93 93 [ ] When editing rights, it is not clear that we are in edit mode! [ ] When editing rights, it is not clear that we are in edit mode!
94 94 [ ] Markdown (Gabi B) [ ] Markdown (Gabi B)
95 95 [ ] Editarea bug-urilor pare ca nu merge [ ] Editarea bug-urilor pare ca nu merge
File inc/git.inc.php changed (mode: 100644) (index 66ff96f..06b0b81)
... ... function rg_git_update_branch($db, $a)
1363 1363 $ev['category'] = 3007; $ev['category'] = 3007;
1364 1364 $ev['prio'] = 50; $ev['prio'] = 50;
1365 1365 $ev['ui'] = array('uid' => $a['login_uid']); $ev['ui'] = array('uid' => $a['login_uid']);
1366 $ev['ri'] = array('repo_id' => $a['repo_id'], 'name' => $a['repo_name']);
1367 unset($ev['repo_id']); unset($ev['repo_name']);
1366 1368 $r = rg_event_add($db, $ev); $r = rg_event_add($db, $ev);
1367 1369 if ($r !== TRUE) if ($r !== TRUE)
1368 1370 rg_git_fatal($a['refname'] . ": " . rg_event_error()); rg_git_fatal($a['refname'] . ": " . rg_event_error());
File inc/repo.inc.php changed (mode: 100644) (index 8197ddf..3af6f36)
... ... function rg_repo_compare_refs($misc, $ref)
271 271 { {
272 272 rg_prof_start("repo_compare_refs"); rg_prof_start("repo_compare_refs");
273 273
274 if (empty($misc))
275 return TRUE;
276
274 277 $misc = rg_repo_ref_canon($misc); $misc = rg_repo_ref_canon($misc);
275 278 $ref = rg_repo_ref_canon($ref); $ref = rg_repo_ref_canon($ref);
276 279
277 $qmisc = preg_quote($misc, '/');
280 // seems that by diong escape, nothing will match!
281 //$qmisc = preg_quote($misc, '/');
282 $qmisc = str_replace('|', '', $misc);
278 283
279 $ret = preg_match('/^' . $qmisc . '/uD', $ref);
280 rg_log("repo_compare_refs: misc=$misc ref=$ref => "
284 $ret = preg_match('|^' . $qmisc . '|uD', $ref);
285 rg_log("repo_compare_refs: ret=$ret misc=$misc ref=$ref [qmisc=$qmisc] => "
281 286 . ($ret === 1 ? "match" : "no match")); . ($ret === 1 ? "match" : "no match"));
282 287
283 288 rg_prof_end("repo_compare_refs"); rg_prof_end("repo_compare_refs");
 
... ... function rg_repo_event_new($db, $event)
398 403 $x['category'] = 30000; $x['category'] = 30000;
399 404 $x['prio'] = 50; $x['prio'] = 50;
400 405 $x['wh_event'] = 'C'; // see rg_wh_events array $x['wh_event'] = 'C'; // see rg_wh_events array
401 $ri = &$event['ri'];
402 $x['wh_data'] = array(
403 'name' => $ri['name'],
404 'public' => $ri['public'],
405 'description' => $ri['description'],
406 'itime' => $ri['itime'],
407 'license' => $ri['license']
408 );
409 406 $ret[] = $x; $ret[] = $x;
410 407
411 408 // add a history entry // add a history entry
File inc/struct.inc.php changed (mode: 100644) (index ffe5018..4f0ca7c)
... ... $rg_sql_struct[36]['other'] = array(
508 508
509 509 $rg_sql_struct[37]['other'] = array( $rg_sql_struct[37]['other'] = array(
510 510 'webhooks - flags is back' => 'webhooks - flags is back' =>
511 "ALTER TABLE webhooks ADD flags TEXT NOT NULL DEFAULT ''"
511 "ALTER TABLE webhooks ADD flags TEXT NOT NULL DEFAULT ''",
512 'webhooks - add refname match' =>
513 "ALTER TABLE webhooks ADD refname TEXT NOT NULL DEFAULT ''",
514 'webhooks - repo_id not needed' =>
515 "ALTER TABLE webhooks DROP repo_id",
516 'webhooks - repo' =>
517 "ALTER TABLE webhooks ADD repo TEXT NOT NULL DEFAULT '';"
512 518 ); );
513 519
514 520 // This must be the last line // This must be the last line
File inc/wh/cloud.inc.php changed (mode: 100644) (index 5c43e4b..1b11661)
... ... function rg_wh_cloud_send_one($db, $event)
25 25 $ret = FALSE; $ret = FALSE;
26 26
27 27 $wh = &$event['wh']; $wh = &$event['wh'];
28 $info = &$wh['info'];
29 28
30 29 $xid = rg_id(8); $xid = rg_id(8);
31 30 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip'; $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip';
 
... ... function rg_wh_cloud_send_one($db, $event)
48 47 rg_wh_replace_tags($event); rg_wh_replace_tags($event);
49 48
50 49 // store to s3 // store to s3
51 $info['idata']['content_type'] = 'application/zip';
50 $wh['idata']['content_type'] = 'application/zip';
52 51 // we need to copy 'flags' because we pass idata // we need to copy 'flags' because we pass idata
53 $info['idata']['flags'] = $info['flags'];
52 $wh['idata']['flags'] = $wh['flags'];
54 53 $c = @file_get_contents($path); $c = @file_get_contents($path);
55 54 if ($c === FALSE) { if ($c === FALSE) {
56 55 $last_output .= 'missing archive; very strange!'; $last_output .= 'missing archive; very strange!';
57 56 break; break;
58 57 } }
59 $r = rg_amazon_s3_put_object($info['idata'], $c);
58 $r = rg_amazon_s3_put_object($wh['idata'], $c);
60 59 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
61 60 $last_output .= $r['error']; $last_output .= $r['error'];
62 61 break; break;
 
... ... function rg_wh_cloud_send_one($db, $event)
64 63 $last_output .= 'S3: ' . $r['answer']; $last_output .= 'S3: ' . $r['answer'];
65 64
66 65 // c = skip the CodeDeploy step // c = skip the CodeDeploy step
67 if (!strchr($info['flags'], 'c')) {
66 if (!strchr($wh['flags'], 'c')) {
68 67 // Do the code deploy // Do the code deploy
69 $r = rg_amazon_codedeploy_create($info['idata']);
68 $r = rg_amazon_codedeploy_create($wh['idata']);
70 69 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
71 70 $last_output .= $r['error']; $last_output .= $r['error'];
72 71 break; break;
 
... ... function rg_wh_cloud_send_one($db, $event)
83 82 rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'], rg_wh_set_last_output($db, $event['ui']['uid'], $wh['id'],
84 83 substr($last_output, 0, 4096)); substr($last_output, 0, 4096));
85 84
86 if ($info['idata']['debug'] == 1)
85 if ($wh['idata']['debug'] == 1)
87 86 rg_cache_set('DEBUG::' . $event['ui']['uid'] rg_cache_set('DEBUG::' . $event['ui']['uid']
88 87 . '::webhooks::' . $wh['id'], $last_output, . '::webhooks::' . $wh['id'], $last_output,
89 88 RG_SOCKET_NO_WAIT); RG_SOCKET_NO_WAIT);
 
... ... function rg_wh_cloud_send($db, $event)
107 106 if ($r['ok'] != 1) if ($r['ok'] != 1)
108 107 return FALSE; return FALSE;
109 108
110 // Filter them by repo_id
111 foreach ($r['list'] as $id => $info) {
112 if (($info['repo_id'] > 0)
113 && ($event['repo_id'] != $info['repo_id'])) {
114 rg_log('hook is not for this repo');
109 // Filter
110 foreach ($r['list'] as $id => $wh) {
111 if (!rg_repo_compare_refs($wh['repo'], $event['ri']['name'])) {
112 rg_log('hook is not for this ref');
115 113 continue; continue;
116 114 } }
117 115
118 if (strcmp($info['htype'], 'cloud') != 0)
116 if (!rg_repo_compare_refs($wh['refname'], $event['refname'])) {
117 rg_log('hook is not for this ref');
119 118 continue; continue;
119 }
120 120
121 // Diabled?
122 if (strchr($info['flags'], 'D'))
121 if (strcmp($wh['htype'], 'cloud') != 0)
123 122 continue; continue;
124 123
125 $wh = array();
126 $wh['id'] = $id;
127 $wh['info'] = $info;
124 // Diabled?
125 if (strchr($wh['flags'], 'D'))
126 continue;
128 127
129 128 $x = $event; $x = $event;
130 129 $x['category'] = 20001; $x['category'] = 20001;
131 130 $x['wh'] = $wh; $x['wh'] = $wh;
131 $x['debug'] = $wh['idata']['debug'];
132 132 $ret[] = $x; $ret[] = $x;
133 133 } }
134 134
File inc/wh/core.inc.php changed (mode: 100644) (index 1b6ec6b..6c7102a)
... ... function rg_wh_sort_helper($a, $b)
218 218
219 219 /* /*
220 220 * Returns a list of webhooks associated with a user * Returns a list of webhooks associated with a user
221 * @repo_id may be 0 => hooks installed on user account
222 221 */ */
223 222 function rg_wh_list($db, $uid) function rg_wh_list($db, $uid)
224 223 { {
 
... ... function rg_wh_add($db, $uid, $data)
292 291
293 292 if ($data['id'] == 0) { if ($data['id'] == 0) {
294 293 $data['last_output'] = ''; $data['last_output'] = '';
295 $sql = 'INSERT INTO webhooks (uid, repo_id, itime'
296 . ', htype, flags'
294 $sql = 'INSERT INTO webhooks (uid, itime'
295 . ', htype, flags, repo, refname'
297 296 . ', add_ip, description, idata)' . ', add_ip, description, idata)'
298 . ' VALUES (@@uid@@, @@repo_id@@, @@itime@@'
299 . ', @@htype@@, @@flags@@, @@add_ip@@'
297 . ' VALUES (@@uid@@, @@itime@@'
298 . ', @@htype@@, @@flags@@, @@repo@@'
299 . ', @@refname@@'
300 . ', @@add_ip@@'
300 301 . ', @@description@@, @@idata@@)' . ', @@description@@, @@idata@@)'
301 302 . ' RETURNING id'; . ' RETURNING id';
302 303 } else { } else {
303 304 $sql = 'UPDATE webhooks' $sql = 'UPDATE webhooks'
304 305 . ' SET description = @@description@@' . ' SET description = @@description@@'
305 306 . ', flags = @@flags@@' . ', flags = @@flags@@'
307 . ', repo = @@repo@@'
308 . ', refname = @@refname@@'
306 309 . ', idata = @@idata@@' . ', idata = @@idata@@'
307 310 . ' WHERE uid = @@uid@@' . ' WHERE uid = @@uid@@'
308 311 . ' AND id = @@id@@'; . ' AND id = @@id@@';
 
... ... function rg_wh_fill_vars(&$rg)
390 393 while (1) { while (1) {
391 394 $t = $rg['wh']['htype']; $t = $rg['wh']['htype'];
392 395
396 $rg['wh']['repo'] = rg_var_str('wh::repo');
393 397 $rg['wh']['flags'] = rg_var_a2s('wh::flags'); $rg['wh']['flags'] = rg_var_a2s('wh::flags');
394 $rg['wh']['repo_id'] = rg_var_uint('wh::repo_id');
398 $rg['wh']['refname'] = rg_var_str('wh::refname');
395 399 $rg['wh']['itime'] = time(); $rg['wh']['itime'] = time();
396 400 $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : ''; $rg['wh']['add_ip'] = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
397 401 $rg['wh']['description'] = trim(rg_var_str('wh::description')); $rg['wh']['description'] = trim(rg_var_str('wh::description'));
 
... ... function rg_wh_default_paras(&$rg)
516 520 $rg['wh']['id'] = 0; $rg['wh']['id'] = 0;
517 521 $rg['wh']['description'] = ''; $rg['wh']['description'] = '';
518 522 $rg['wh']['flags'] = ''; $rg['wh']['flags'] = '';
523 $rg['wh']['repo'] = '';
524 $rg['wh']['refname'] = '';
519 525
520 526 $rg['wh']['idata'] = array(); $rg['wh']['idata'] = array();
521 527 $rg['wh']['idata']['events'] = ''; $rg['wh']['idata']['events'] = '';
 
... ... function rg_wh_replace_tags(&$ev)
589 595 rg_log_ml('wh_replace_tags: ev=' . print_r($ev, TRUE)); rg_log_ml('wh_replace_tags: ev=' . print_r($ev, TRUE));
590 596
591 597 $wh = &$ev['wh']; $wh = &$ev['wh'];
592 $info = &$wh['info'];
593 $idata = &$info['idata'];
598 $idata = &$wh['idata'];
594 599
595 $branch = rg_repo_ref_nice($ev['refname']);
600 $branch = isset($ev['refname']) ? rg_repo_ref_nice($ev['refname']) : '';
601 $repo_name = isset($ev['ri']['name']) ? $ev['ri']['name'] : '';
602 $new_rev = isset($ev['new_rev']) ? $ev['new_rev'] : '';
596 603
597 $keys = array('##branch##', '##repo##', '##who##',
604 $keys = array('##branch##', '##repo##',
598 605 '##hook_id##', '##commit##', '##hook_id##', '##commit##',
599 606 '##date##', '##time##', '##date##', '##time##',
600 607 '##ip##', '##timestamp##'); '##ip##', '##timestamp##');
601 608
602 $values = array($branch, $ev['repo_name'], $ev['login_username'],
603 $info['id'], $ev['new_rev'],
609 $values = array($branch, $repo_name,
610 $wh['id'], $new_rev,
604 611 gmdate('Y-m-d', $ev['itime']), gmdate('Y-m-d', $ev['itime']),
605 612 gmdate('H:i:s', $ev['itime']), gmdate('H:i:s', $ev['itime']),
606 613 $ev['ip'], $ev['itime']); $ev['ip'], $ev['itime']);
 
... ... function rg_wh_replace_tags(&$ev)
611 618 rg_log_ml('after: ' . print_r($idata, TRUE)); rg_log_ml('after: ' . print_r($idata, TRUE));
612 619 } }
613 620
621 /*
622 * Used to filter hooks by repo name
623 */
624 function rg_wh_repo_match($pattern, $repo_name)
625 {
626 rg_log('wh_repo_match pattern=[' . $pattern . ']'
627 . ' repo_name=[' . $repo_name . ']');
628
629 $pattern = str_replace('|', '', $pattern);
630 return preg_match('|' . $pattern . '|uD', $repo_name) === 1;
631 }
632
614 633 ?> ?>
File inc/wh/http.inc.php changed (mode: 100644) (index 77eebea..5566680)
... ... function rg_wh_http_send_one($db, $event)
20 20 rg_prof_start('wh_http_send_helper'); rg_prof_start('wh_http_send_helper');
21 21
22 22 $wh = &$event['wh']; $wh = &$event['wh'];
23 $info = &$wh['info'];
24 23
25 24 rg_log_ml('wh_http_send_one: event: ' . print_r($event, TRUE)); rg_log_ml('wh_http_send_one: event: ' . print_r($event, TRUE));
26 if ($info['idata']['debug'] == 1)
27 rg_log_ml('XXX DEBUG: wh[data]=' . print_r($wh['data'], TRUE));
25 if ($wh['idata']['debug'] == 1)
26 rg_log_ml('DEBUG: wh[data]=' . print_r($wh['data'], TRUE));
28 27
29 28 $headers = array(); $headers = array();
30
31 while (!empty($info['idata']['key'])) {
32 if ($info['idata']['itype'] == 0)
29 while (!empty($wh['idata']['key'])) {
30 if ($wh['idata']['itype'] == 0)
33 31 break; break;
34 32
35 33 $headers[] = 'X-RocketGit-Signature: ' $headers[] = 'X-RocketGit-Signature: '
36 . hash_hmac('sha512', $wh['data'], $info['idata']['key']);
34 . hash_hmac('sha512', $wh['data'], $wh['idata']['key']);
37 35 break; break;
38 36 } }
39 37
40 $c = curl_init($info['idata']['url']);
38 $c = curl_init($wh['idata']['url']);
41 39 curl_setopt($c, CURLOPT_POST, 1); curl_setopt($c, CURLOPT_POST, 1);
42 40 curl_setopt($c, CURLOPT_POSTFIELDS, $wh['data']); curl_setopt($c, CURLOPT_POSTFIELDS, $wh['data']);
43 41 curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE);
 
... ... function rg_wh_http_send_one($db, $event)
57 55 if ($err !== FALSE) if ($err !== FALSE)
58 56 curl_setopt($c, CURLOPT_STDERR, $err); curl_setopt($c, CURLOPT_STDERR, $err);
59 57
60 if (strchr($info['flags'], 'I'))
58 if (strchr($wh['flags'], 'I'))
61 59 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($c, CURLOPT_SSL_VERIFYPEER, FALSE);
62 60
63 if (strchr($info['flags'], 'H'))
61 if (strchr($wh['flags'], 'H'))
64 62 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0); // TODO verify 0 is a good value (default 2) curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0); // TODO verify 0 is a good value (default 2)
65 63
66 64 $ret = FALSE; $ret = FALSE;
 
... ... function rg_wh_http_send_one($db, $event)
72 70 // replace ##tags## // replace ##tags##
73 71 rg_wh_replace_tags($event); rg_wh_replace_tags($event);
74 72
75 if (!empty($info['idata']['client_cert'])) {
73 if (!empty($wh['idata']['client_cert'])) {
76 74 rg_log('DEBUG: will provide client cert...'); rg_log('DEBUG: will provide client cert...');
77 75 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-client-' . $xid; $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-client-' . $xid;
78 $cert_file = rg_tmp_file($f, $info['idata']['client_cert']);
76 $cert_file = rg_tmp_file($f, $wh['idata']['client_cert']);
79 77 if ($cert_file === FALSE) if ($cert_file === FALSE)
80 78 break; break;
81 79
 
... ... function rg_wh_http_send_one($db, $event)
86 84 curl_setopt($c, CURLOPT_SSLCERT, FALSE); curl_setopt($c, CURLOPT_SSLCERT, FALSE);
87 85 } }
88 86
89 if (!empty($info['idata']['client_ca_cert'])) {
87 if (!empty($wh['idata']['client_ca_cert'])) {
90 88 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-ca-' . $xid; $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-ca-' . $xid;
91 $ca_file = rg_tmp_file($f, $info['idata']['client_ca_cert']);
89 $ca_file = rg_tmp_file($f, $wh['idata']['client_ca_cert']);
92 90 if ($ca_file === FALSE) if ($ca_file === FALSE)
93 91 break; break;
94 92
 
... ... function rg_wh_http_send_one($db, $event)
111 109 $_info = curl_getinfo($c); $_info = curl_getinfo($c);
112 110 rg_log_ml('Debug: ' . print_r($_info, TRUE)); rg_log_ml('Debug: ' . print_r($_info, TRUE));
113 111
114 if ($info['idata']['debug'] == 1)
112 if ($wh['idata']['debug'] == 1)
115 113 rg_cache_set('DEBUG::' . $event['ui']['uid'] rg_cache_set('DEBUG::' . $event['ui']['uid']
116 . '::webhooks::' . $info['idata']['opaque']
114 . '::webhooks::' . $wh['idata']['opaque']
117 115 . '::' . $wh['id'], . '::' . $wh['id'],
118 116 'BAD', RG_SOCKET_NO_WAIT); 'BAD', RG_SOCKET_NO_WAIT);
119 117 break; break;
 
... ... function rg_wh_http_send_one($db, $event)
123 121 rg_log_ml('Answer: ' . print_r($r, TRUE)); rg_log_ml('Answer: ' . print_r($r, TRUE));
124 122 $xerr .= $r; $xerr .= $r;
125 123
126 if ($info['idata']['debug'] == 1)
124 if ($wh['idata']['debug'] == 1)
127 125 rg_cache_set('DEBUG::' . $event['ui']['uid'] rg_cache_set('DEBUG::' . $event['ui']['uid']
128 . '::webhooks::' . $info['idata']['opaque']
126 . '::webhooks::' . $wh['idata']['opaque']
129 127 . '::' . $wh['id'], . '::' . $wh['id'],
130 128 'OK', RG_SOCKET_NO_WAIT); 'OK', RG_SOCKET_NO_WAIT);
131 129
 
... ... function rg_wh_http_send($db, $event)
161 159 if ($r['ok'] != 1) if ($r['ok'] != 1)
162 160 return FALSE; return FALSE;
163 161
164 // Filter them by repo_id
165 $real_list = array();
166 foreach ($r['list'] as $id => $info) {
167 if (($info['repo_id'] > 0)
168 && ($event['ri']['repo_id'] != $info['repo_id'])) {
162 $cache = array();
163 $ret = array();
164
165 // Filter
166 foreach ($r['list'] as $id => $wh) {
167 if (isset($event['ri']['name'])
168 && !rg_wh_repo_match($wh['repo'], $event['ri']['name'])) {
169 169 rg_log('hook is not for this repo'); rg_log('hook is not for this repo');
170 170 continue; continue;
171 171 } }
172 172
173 if (strcmp($info['htype'], 'http') != 0)
173 if (isset($event['refname'])
174 && !rg_repo_compare_refs($wh['refname'], $event['refname'])) {
175 rg_log('hook is not for this ref');
176 continue;
177 }
178
179 if (strcmp($wh['htype'], 'http') != 0)
174 180 continue; continue;
175 181
176 182 // Diabled? // Diabled?
177 if (strchr($info['flags'], 'D'))
183 if (strchr($wh['flags'], 'D'))
178 184 continue; continue;
179 185
180 186 // If the web hook does not contain our type, skip it // If the web hook does not contain our type, skip it
181 if (!strchr($info['idata']['events'], $event['wh_event'])) {
187 if (!strchr($wh['idata']['events'], $event['wh_event'])) {
182 188 rg_log($event['wh_event'] . ' is not present in ' rg_log($event['wh_event'] . ' is not present in '
183 . $info['idata']['events']);
189 . $wh['idata']['events']);
184 190 continue; continue;
185 191 } }
186 192
187 $real_list[] = $id;
188 }
189
190 // Something to do?
191 if (empty($real_list))
192 return array();
193
194 $cache = array();
195 $wh = array();
196 $ret = array();
197 foreach ($real_list as $id) {
198 $wh['info'] = $r['list'][$id];
199 $wh['id'] = $id;
200
201 if (!isset($wh['info']['idata']['itype'])) {
202 rg_log_ml('wh[info]: ' . print_r($wh['info'], TRUE));
193 if (!isset($wh['idata']['itype'])) {
194 rg_log_ml('wh: ' . print_r($wh, TRUE));
203 195 rg_internal_error('DEBUG: itype is not present'); rg_internal_error('DEBUG: itype is not present');
196 continue;
204 197 } }
205 $type = $wh['info']['idata']['itype'];
206 if (!isset($cache[$type])) {
207 switch ($type) {
198
199 $itype = $wh['idata']['itype'];
200 if (!isset($cache[$itype])) {
201 switch ($itype) {
208 202 case 0: // http post case 0: // http post
209 $cache[$type] = &$event['wh_data'];
203 $cache[$itype] = &$event['ri'];
210 204 break; break;
211 205
212 206 case 1: // php serialize case 1: // php serialize
213 $cache[$type] = serialize($event['wh_data']);
207 $cache[$itype] = serialize($event['ri']);
214 208 break; break;
215 209
216 210 default: default:
217 rg_log('Unknown type ' . $type . '!');
218 $cache[$type] = '';
211 rg_log('Unknown type ' . $itype . '!');
212 $cache[$itype] = '';
219 213 break; break;
220 214 } }
221 215 } }
222 $wh['data'] = $cache[$type];
216 $wh['data'] = $cache[$itype];
223 217
224 218 $x = $event; $x = $event;
225 219 $x['category'] = 10001; $x['category'] = 10001;
226 220 $x['wh'] = $wh; $x['wh'] = $wh;
221 $x['debug'] = $wh['idata']['debug'];
227 222 $ret[] = $x; $ret[] = $x;
228 223 } }
229 224
File inc/wh/lambda.inc.php changed (mode: 100644) (index 93fcabf..fe0b9f2)
... ... function rg_wh_lambda_send_one($db, $event)
25 25 $ret = FALSE; $ret = FALSE;
26 26
27 27 $wh = &$event['wh']; $wh = &$event['wh'];
28 $info = &$wh['info'];
29 28
30 29 $last_output = ''; $last_output = '';
31 30 while (1) { while (1) {
 
... ... function rg_wh_lambda_send_one($db, $event)
33 32 rg_wh_replace_tags($event); rg_wh_replace_tags($event);
34 33
35 34 // we need to copy 'flags' because we pass idata // we need to copy 'flags' because we pass idata
36 $info['idata']['flags'] = $info['flags'];
35 $wh['idata']['flags'] = $wh['flags'];
37 36
38 37 // Call the function // Call the function
39 $r = rg_amazon_lambda_invoke($info['idata']);
38 $r = rg_amazon_lambda_invoke($wh['idata']);
40 39 if ($r['ok'] != 1) { if ($r['ok'] != 1) {
41 40 $last_output .= $r['error']; $last_output .= $r['error'];
42 41 break; break;
 
... ... function rg_wh_lambda_send($db, $event)
69 68 if ($r['ok'] != 1) if ($r['ok'] != 1)
70 69 return FALSE; return FALSE;
71 70
72 // Filter them by repo_id
73 foreach ($r['list'] as $id => $info) {
74 if (($info['repo_id'] > 0)
75 && ($event['repo_id'] != $info['repo_id'])) {
71 // Filter
72 foreach ($r['list'] as $id => $wh) {
73 if (isset($event['ri']['name'])
74 && !rg_repo_compare_refs($wh['repo'], $event['ri']['name'])) {
76 75 rg_log('hook is not for this repo'); rg_log('hook is not for this repo');
77 76 continue; continue;
78 77 } }
79 78
80 if (strcmp($info['htype'], 'lambda') != 0)
79 if (isset($event['refname'])
80 && !rg_repo_compare_refs($wh['refname'], $event['refname'])) {
81 rg_log('hook is not for this ref');
81 82 continue; continue;
83 }
82 84
83 // Diabled?
84 if (strchr($info['flags'], 'D'))
85 if (strcmp($wh['htype'], 'lambda') != 0)
85 86 continue; continue;
86 87
87 $wh = array();
88 $wh['id'] = $id;
89 $wh['info'] = $info;
88 // Diabled?
89 if (strchr($wh['flags'], 'D'))
90 continue;
90 91
91 92 $x = $event; $x = $event;
92 93 $x['category'] = 30001; $x['category'] = 30001;
93 94 $x['wh'] = $wh; $x['wh'] = $wh;
95 $x['debug'] = $wh['idata']['debug'];
94 96 $ret[] = $x; $ret[] = $x;
95 97 } }
96 98
 
... ... function rg_wh_lambda_fill_hints($rg, &$hints)
165 167 { {
166 168 $hints[]['HTML:hint'] = rg_template('user/settings/wh/amazon/hints.html', $hints[]['HTML:hint'] = rg_template('user/settings/wh/amazon/hints.html',
167 169 $rg, TRUE /*xss*/); $rg, TRUE /*xss*/);
168 $hints[]['HTML:hint'] = rg_template('user/settings/wh/hints_tags.html',
169 $rg, TRUE /*xss*/);
170 170 } }
171 171
172 172 /* /*
173 173 * Loads default paras for a form * Loads default paras for a form
174 * TODO: escape json when replacing
174 175 */ */
175 176 function rg_wh_lambda_default_paras(&$rg) function rg_wh_lambda_default_paras(&$rg)
176 177 { {
177 178 $a = &$rg['wh']['idata']; $a = &$rg['wh']['idata'];
178 179 rg_wh_amazon_default_paras($a); rg_wh_amazon_default_paras($a);
179 180 $a['function'] = ''; $a['function'] = '';
180 $a['payload'] = '';
181 $a['payload'] = '{' . "\n"
182 . '"repo": "##repo##",' . "\n"
183 . '"branch": "##branch##",' . "\n"
184 . '"hook_id": "##hook_id##",' . "\n"
185 . '"commit": "##commit##",' . "\n"
186 . '"date": "##date##",' . "\n"
187 . '"time": "##time##",' . "\n"
188 . '"timestamp": "##timestamp##",' . "\n"
189 . '"ip": "##ip##"' . "\n"
190 . '}';
181 191 } }
182 192
183 193
File root/themes/default/user/settings/wh/add_edit.html changed (mode: 100644) (index 65f1a96..07d0f80)
9 9 <input type="hidden" name="wh::htype" value="@@wh::htype@@" /> <input type="hidden" name="wh::htype" value="@@wh::htype@@" />
10 10 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
11 11
12 <p>
13 <label for="repo">Repository filter (regex; leave empty for any)</label><br />
14 <input type="text" name="wh::repo" id="repo" size="80" value="@@wh::repo@@" />
15 </p>
16
17 <p>
18 <label for="refname">Reference filter (branch or tag; regex; leave empty for any)</label><br />
19 <input type="text" name="wh::refname" id="refname" size="80" value="@@wh::refname@@" />
20 </p>
21
12 22 <fieldset> <fieldset>
13 23 <legend>Flags</legend> <legend>Flags</legend>
14 24 @@check_flags@@ @@check_flags@@
File root/themes/default/user/settings/wh/hints_tags.html changed (mode: 100644) (index 2e82d17..79af097)
... ... be replaced at hook execution. It is a feature that allows you to minimize
4 4 the number of hooks you must maintain.<br /> the number of hooks you must maintain.<br />
5 5 The complete list of tags: The complete list of tags:
6 6 <ul> <ul>
7 <li>##branch## - the branch name just created or pushed to</li>
8 7 <li>##repo## - the repository name</li> <li>##repo## - the repository name</li>
9 <li>##who## - the user who triggered the hook</li>
8 <li>##branch## - the branch name just created or pushed to</li>
10 9 <li>##hook_id## - the id of the hook</li> <li>##hook_id## - the id of the hook</li>
11 10 <li>##commit## - the git's SHA-1 commit id</li> <li>##commit## - the git's SHA-1 commit id</li>
12 11 <li>##date## - the UTC date (example: 2016-01-15)</li> <li>##date## - the UTC date (example: 2016-01-15)</li>
File root/themes/default/user/settings/wh/lambda/form.html changed (mode: 100644) (index 2bee253..73c5d25)
29 29
30 30 <p> <p>
31 31 <label for="payload">JSON payload</label><br /> <label for="payload">JSON payload</label><br />
32 <textarea name="wh::idata::payload" id="payload" rows="5" cols="80">@@wh::idata::payload@@</textarea>
32 <textarea name="wh::idata::payload" id="payload" rows="10" cols="80">@@wh::idata::payload@@</textarea>
33 33 </p> </p>
34 34 </fieldset> </fieldset>
File root/themes/default/user/settings/wh/list/header.html changed (mode: 100644) (index 94ca0ee..68f325b)
12 12 <th>Edit</th> <th>Edit</th>
13 13 <th>Date (UTC) / Add IP</th> <th>Date (UTC) / Add IP</th>
14 14 <th>Description</th> <th>Description</th>
15 <th>Repo name filter</th>
16 <th>Reference filter</th>
15 17 <th>Flags</th> <th>Flags</th>
16 18 <th>Private info</th> <th>Private info</th>
17 19 <th>Last output</th> <th>Last output</th>
File root/themes/default/user/settings/wh/list/line.html changed (mode: 100644) (index 4bcfe10..f879487)
5 5 <td><a href="/op/settings/wh/edit/@@id@@">Edit</a></td> <td><a href="/op/settings/wh/edit/@@id@@">Edit</a></td>
6 6 <td>@@itime_nice@@<br />@@add_ip@@</td> <td>@@itime_nice@@<br />@@add_ip@@</td>
7 7 <td class="small">@@description_nice@@</td> <td class="small">@@description_nice@@</td>
8 <td>@@repo@@</td>
9 <td>@@refname@@</td>
8 10 <td>@@flags_text@@</td> <td>@@flags_text@@</td>
9 11 <td>@@idata::private@@</td> <td>@@idata::private@@</td>
10 12 <td class="small">@@last_output_nice@@</td> <td class="small">@@last_output_nice@@</td>
File tests/repo.php changed (mode: 100644) (index 037efa3..8e8134b)
... ... $res = rg_sql_query($db, $sql);
37 37 rg_sql_free_result($res); rg_sql_free_result($res);
38 38
39 39
40 rg_log('');
41 rg_log_enter('rg_repo_compare_refs');
42 $patterns = array(
43 '' => 'any',
44 'a' => 'a',
45 '.*' => 'aaaa',
46 'v.*' => 'v3.3',
47 'v[0-9]*' => 'v3333',
48 'prod|.*' => 'production' // because | is removed
49 );
50 foreach ($patterns as $pattern => $data) {
51 $r = rg_repo_compare_refs($pattern, $data);
52 if ($r !== TRUE) {
53 rg_log('Ref [' . $data . '] should match pattern [' . $pattern . ']');
54 exit(1);
55 }
56 }
57 rg_log_exit();
58
59
40 60 rg_log(''); rg_log('');
41 61 rg_log_enter("rg_repo_path 1"); rg_log_enter("rg_repo_path 1");
42 62 $e = $rg_repos . "/by_id/11/22/33/44/11223344/repos/by_id/55.git"; $e = $rg_repos . "/by_id/11/22/33/44/11223344/repos/by_id/55.git";
File tests/wh_cloud.php changed (mode: 100644) (index 90a5cdf..568da7a)
... ... rg_log_enter('Registering webhook1...');
50 50 $extra = array( $extra = array(
51 51 'wh::htype' => 'cloud', 'wh::htype' => 'cloud',
52 52 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
53 'wh::repo' => '',
54 'wh::refname' => '',
53 55 'wh::idata::access_key_id' => $a['access_key_id'], 'wh::idata::access_key_id' => $a['access_key_id'],
54 56 'wh::idata::secret_access_key' => $a['secret_access_key'], 'wh::idata::secret_access_key' => $a['secret_access_key'],
55 57 'wh::idata::region' => 'eu-central-1', 'wh::idata::region' => 'eu-central-1',
 
... ... $extra = array(
58 60 'wh::idata::deployment_config_name' => '', 'wh::idata::deployment_config_name' => '',
59 61 'wh::idata::bucket' => 'test-deploy-500-##repo##-##branch##', 'wh::idata::bucket' => 'test-deploy-500-##repo##-##branch##',
60 62 'wh::idata::file' => 'wh::idata::file' =>
61 '##repo##-##branch##-##who##-##hook_id##'
63 '##repo##-##branch##-##hook_id##'
62 64 . '-##commit##-##date##-##time##-##ip##-##timestamp##.zip', . '-##commit##-##date##-##time##-##ip##-##timestamp##.zip',
63 65 ); );
64 66 rg_test_wh_add_edit($db, $rg_ui, $good_sid, 'cloud', $extra); rg_test_wh_add_edit($db, $rg_ui, $good_sid, 'cloud', $extra);
 
... ... rg_log_enter('Testing the edit of webhook...');
136 138 $extra = array( $extra = array(
137 139 'wh::id' => $wh_id, 'wh::id' => $wh_id,
138 140 'wh::htype' => 'cloud', 'wh::htype' => 'cloud',
141 'wh::repo' => '.*',
142 'wh::refname' => '..*',
139 143 'wh::description' => 'desc2 <xss>', 'wh::description' => 'desc2 <xss>',
140 144 'wh::flags' => 'D', 'wh::flags' => 'D',
141 145 'wh::idata::access_key_id' => 'aaa', 'wh::idata::access_key_id' => 'aaa',
 
... ... $row['idata'] = unserialize($row['idata']);
157 161 $key = 'wh' . '::' . $rg_ui['uid'] . '::' . 'list' . '::' . $wh_id; $key = 'wh' . '::' . $rg_ui['uid'] . '::' . 'list' . '::' . $wh_id;
158 162 rg_cache_core_unset($key); // else we will get previous copy! rg_cache_core_unset($key); // else we will get previous copy!
159 163 $c = rg_cache_get($key); $c = rg_cache_get($key);
160 $list = array('htype' => 'cloud',
164 $list = array('htype' => 'cloud', 'repo' => '.*', 'refname' => '..*',
161 165 'description' => 'desc2 <xss>', 'flags' => 'D', 'description' => 'desc2 <xss>', 'flags' => 'D',
162 166 'access_key_id' => 'aaa', 'access_key_id' => 'aaa',
163 167 'secret_access_key' => 'bbb', 'region' => 'ccc', 'secret_access_key' => 'bbb', 'region' => 'ccc',
File tests/wh_http.php changed (mode: 100644) (index e301f49..c9517bb)
... ... rg_log('Registering webhook1...');
136 136 $extra = array( $extra = array(
137 137 'wh::htype' => 'http', 'wh::htype' => 'http',
138 138 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
139 'wh::repo' => '',
140 'wh::refname' => '',
139 141 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html', 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html',
140 142 'wh::idata::events[C]' => 'on', 'wh::idata::events[C]' => 'on',
141 143 'wh::idata::events[P]' => 'on', 'wh::idata::events[P]' => 'on',
 
... ... rg_log('Registering webhook2...');
154 156 $extra = array( $extra = array(
155 157 'wh::htype' => 'http', 'wh::htype' => 'http',
156 158 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
159 'wh::repo' => '',
160 'wh::refname' => '',
157 161 'wh::idata::url' => 'https://localhost:' . $port2 . '/wh.html', 'wh::idata::url' => 'https://localhost:' . $port2 . '/wh.html',
158 162 'wh::idata::events[C]' => 'on', 'wh::idata::events[C]' => 'on',
159 163 'wh::idata::events[P]' => 'on', 'wh::idata::events[P]' => 'on',
 
... ... rg_log('Registering webhook3...');
173 177 $extra = array( $extra = array(
174 178 'wh::htype' => 'http', 'wh::htype' => 'http',
175 179 'wh::description' => 'description1 <xss>', 'wh::description' => 'description1 <xss>',
180 'wh::repo' => '',
181 'wh::refname' => '',
176 182 'wh::idata::url' => 'https://localhost:' . $port3 . '/wh.html', 'wh::idata::url' => 'https://localhost:' . $port3 . '/wh.html',
177 183 'wh::idata::events[C]' => 'on', 'wh::idata::events[C]' => 'on',
178 184 'wh::idata::events[P]' => 'on', 'wh::idata::events[P]' => 'on',
 
... ... $extra = array(
275 281 'wh::id' => $wh_id1, 'wh::id' => $wh_id1,
276 282 'wh::htype' => 'http', 'wh::htype' => 'http',
277 283 'wh::description' => 'desc2 <xss>', 'wh::description' => 'desc2 <xss>',
284 'wh::repo' => '.*',
285 'wh::refname' => '..*',
278 286 'wh::flags[D]' => 'on', 'wh::flags[D]' => 'on',
279 287 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html', 'wh::idata::url' => 'https://localhost:' . $port1 . '/wh.html',
280 288 'wh::idata::events[C]' => 'on', 'wh::idata::events[C]' => 'on',
 
... ... $row['idata'] = unserialize($row['idata']);
295 303 $key = 'wh' . '::' . $rg_ui['uid'] . '::' . 'list' . '::' . $wh_id1; $key = 'wh' . '::' . $rg_ui['uid'] . '::' . 'list' . '::' . $wh_id1;
296 304 rg_cache_core_unset($key); // else we will get previous copy! rg_cache_core_unset($key); // else we will get previous copy!
297 305 $c = rg_cache_get($key); $c = rg_cache_get($key);
298 $list = array('htype' => 'http', 'events' => 'CB',
306 $list = array('htype' => 'http', 'events' => 'CB', 'repo' => '.*',
307 'refname' => '..*',
299 308 'description' => 'desc2 <xss>', 'key' => 'another key <xss>', 'description' => 'desc2 <xss>', 'key' => 'another key <xss>',
300 309 'opaque' => 'xxx', 'itype' => '1', 'flags' => 'D', 'opaque' => 'xxx', 'itype' => '1', 'flags' => 'D',
301 310 'client_cert' => 'abc <xss>', 'client_ca_cert' => 'zzz <xss>'); 'client_cert' => 'abc <xss>', 'client_ca_cert' => 'zzz <xss>');
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/rocketgit

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master