List of commits:
Subject Hash Author Date (UTC)
Lots of fixes for pull requests 54c410d144ae9ebdcc17ad8d11865a378e89f576 Catalin(ux) M. BOIE 2016-03-06 20:07:06
Replaced rg_bug_next_id with the more generic rg_repo_next_id 7c3131ac2bff3afb08983a2ebd23736ced070fb1 Catalin(ux) M. BOIE 2016-02-17 16:07:12
text correction: Amazon user must also have S3 rights 6a97f6ef92bb455b02434f35218224a3cae4cf02 Catalin(ux) M. BOIE 2016-02-14 12:11:29
for git:// access, organization field was missing 6c4479d982ea36941dc10db6d1b74012d1a75649 Catalin(ux) M. BOIE 2016-02-14 12:10:16
TODO changes bc6bf53c22bf2918e0fca8684406a753e4a335a3 Catalin(ux) M. BOIE 2016-02-14 12:09:47
Added login hints: about rg_change_pass ed1c5226b5e9e44859f76ad058aed76423855e0c Catalin(ux) M. BOIE 2016-02-14 12:09:23
css: fixed admins pages 3a8e93564ee53176ae510e131e55fa4bbef98908 Catalin(ux) M. BOIE 2016-02-14 12:09:00
Added rg_change_pass tool cfc9e214ef3bb978e831a68ab6395c74b6604b41 Catalin(ux) M. BOIE 2016-02-14 11:56:10
CSS fixes to make the spaces the same all over the place 6abddc6fc655a8b67537f46106467229ed687dcc Catalin(ux) M. BOIE 2016-02-14 11:19:07
minor: reorder functions 4c02703e69e56289670e96952b49c55fadcab671 Catalin(ux) M. BOIE 2016-02-14 09:40:44
Show ssh key type before number of bits 980da7f8b9c3380c169547c2b1f522e7d52f0398 Catalin(ux) M. BOIE 2016-02-12 05:20:21
Improved a little the error message received by git:// bb2ed8554a00ae532e93bab17285a4a1eb24ec12 Catalin(ux) M. BOIE 2016-02-11 21:13:14
Show the key size in bits when listing ssh keys 31583c21cf178475e546ad47a47e56c6982dff09 Catalin(ux) M. BOIE 2016-02-08 06:23:43
Improved a little the admin report 1f348f2c163ba1320dce223774b2f677f18d6461 Catalin(ux) M. BOIE 2016-02-08 06:23:05
Improved a little how a tree is shown 753af0ef4a6d9fc2f2ddb993335f3c50a3fff2ab Catalin(ux) M. BOIE 2016-02-07 06:46:02
In admin's report, add in the subject the total number of yesterday's changes 02a3b4131626b7023ba87a59b188256a601cd13a Catalin(ux) M. BOIE 2016-02-07 05:52:47
More detailed and correct description for hooks d3045a11eed05c897381ae2cfcbbf91ede1d4910 Catalin(ux) M. BOIE 2016-02-07 05:42:53
docker: fixes and improvements for image generation 37bd416d1664e8d9fcdf4554646618e5dd226e35 Catalin(ux) M. BOIE 2016-02-07 05:42:28
Added bug template and prefill the bug form assigned to field to the owner of the repo 682e787ceb92d770e1a268a9f635e4336102cf3b Catalin(ux) M. BOIE 2016-02-07 05:38:58
Change download location for rocketgit.xml 41bf40104994391fd5d9938ac891157625872c0d Catalin(ux) M. BOIE 2016-02-02 23:04:53
Commit 54c410d144ae9ebdcc17ad8d11865a378e89f576 - Lots of fixes for pull requests
Author: Catalin(ux) M. BOIE
Author date (UTC): 2016-03-06 20:07
Committer name: Catalin(ux) M. BOIE
Committer date (UTC): 2016-03-06 20:07
Parent(s): 7c3131ac2bff3afb08983a2ebd23736ced070fb1
Signing key:
Tree: 593f4c6bff3bc3c104c4a0ddb5691040b005348f
File Lines added Lines deleted
History.txt 2 0
TODO 83 4
hooks/pre-commit 3 3
inc/admin.inc.php 1 0
inc/git.inc.php 415 79
inc/mr.inc.php 290 19
inc/sql.inc.php 16 10
inc/struct.inc.php 3 1
inc/user/repo-page.php 14 57
inc/user/repo/bug/main.php 3 0
inc/util.inc.php 3 3
inc/wh/cloud.inc.php 1 1
root/index.php 0 1
root/themes/default/hints/repo/git_setup.html 1 1
root/themes/default/hints/repo/merge.html 5 4
root/themes/default/main.css 41 7
root/themes/default/repo/bug/main.html 0 10
root/themes/default/repo/bug/menu.html 0 2
root/themes/default/repo/log/header.html 1 2
root/themes/default/repo/log/line.html 1 1
root/themes/default/repo/mail/merge_failed.body.txt 8 0
root/themes/default/repo/mail/merge_failed.head.txt 0 0
root/themes/default/repo/mail/merge_failed.subj.txt 0 0
root/themes/default/repo/mr/conflicts.html 4 0
root/themes/default/repo/mr/list/header.html 4 2
root/themes/default/repo/mr/list/line.html 5 3
root/themes/default/repo/mr/menu.html 7 0
root/themes/default/repo/mr/merge_in_progress.html 3 0
root/themes/default/repo/mr/page.html 47 6
root/themes/default/repo/mr/req-pull.txt 14 0
root/themes/default/user/keys/add.html 1 1
root/themes/default/user/settings/wh/http/show.html 4 4
tests/.gitignore 1 0
tests/Makefile 2 2
tests/git_log1.expected 10 10
tests/git_log1.final 0 78
tests/git_log1.php 2 1
tests/helpers.inc.php 38 2
tests/http.inc.php 5 4
tests/http_totp.php 1 1
tests/pr_anon.php 134 47
File History.txt changed (mode: 100644) (index 0a7a539..cb77f12)
5 5 2015-03-13 - Google Code closing the gates. 2015-03-13 - Google Code closing the gates.
6 6 2015-11-18 - rocketgit 0.42 installed on rocketgit.com 2015-11-18 - rocketgit 0.42 installed on rocketgit.com
7 7 2015-12-02 - RocketGit is announced to 40 people (friends) (time: 20:56:00) 2015-12-02 - RocketGit is announced to 40 people (friends) (time: 20:56:00)
8 2016-02-23 - First merge of a pull request on the deve machine.
9 2016-02-24 - First unknown (to me) user created an account on rocketgit.com.
File TODO changed (mode: 100644) (index 15db99d..0fbb7e3)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] Protect emails from commits?!
3 [ ] Stop logging passwords!
2 4 [ ] /user/catalinux/test1/source/tree/blob/"xx/"yy" pe rocketgit.com [ ] /user/catalinux/test1/source/tree/blob/"xx/"yy" pe rocketgit.com
3 5 generates errors. something regargin ls-tree that outputs nothing. generates errors. something regargin ls-tree that outputs nothing.
4 6 This is another problem. If is empty, we should not enter foreach! This is another problem. If is empty, we should not enter foreach!
7 [ ] Seems that after I create a repo and pushed something anonymous, some files
8 were not readable by others. :(
9 [ ] mr: where is the uid of the user that did the push?!
10 Is the anon push by a user supported?!
11 added merge_requests.who (default 0)
12 [ ] mr: when pushing, also show the link to the mr?
13 We do not have it because we add an event.
14 [ ] mr: after a push is done, add an event to generate the status if a mr can
15 be merged. Or be lazy till first access? Maybe when we are idle.
16 [ ] mr: we need token in merge form! Done, check.
17 [ ] repo stats must not be generated in web. It may take a lot of time.
18 We must do them incrementally, from cron, and only max N commits
19 per repo in one run.
20 [ ] --work-dir must be created in some temporary folder.
21 [ ] mr: After merging, shoul we delete the namespace?
22 [ ] mr: do I test if the user "pressing" merge has the right to do the merge?
23 [ ] mr: seems I do not store the merge requests into mr/<id>!
5 24 [ ] [ ]
6 25
7 26 == BEFORE NEXT RELEASE == == BEFORE NEXT RELEASE ==
27 [ ] LOW: do we clean temporary files automatically?
28 [ ] LOW: when pushing, in history add a link to the pull request (if anon).
29 [ ] LOW: commit on web: enforce subject (50 chars), do wrap (72),
30 enforce signoffs or other headers. Add a marker to force no wrap.
31 A pull must have name, e-mail, why, shorlog, diffstat.
32 [ ] LOW: mr: notify the owner of the pull request (if not anonymous)?
33 [ ] LOW: when destroying a repo, destroy the cache by path (git caches by path)
34 [ ] LOW: /usr/share/rocketgit/root/themes/default//usr/share/rocketgit/root/themes/default/hints/list/header.html
35 [ ] LOW: mr: private pull requests?
36 [ ] LOW: mr: get rid of namespaces?
37 [ ] LOW: mr: add possibility to reject a pull request.
38 [ ] LOW: mr: add the right to reject pull requests.
39 [ ] LOW: mr: allow adding comments for pull requests.
40 [ ] LOW: mr: Add after "Against ref" the sha/subject of the commit.
41 [ ] LOW: mr: allow the anonymous users to delete a pull request by providing
42 a link.
43 [ ] LOW: mr: allow the owner to remove a pull request.
44 [ ] LOW: mr: Use rg_git_request_pull to generate a pull request from a onw repo.
45 Example: git request-pull master~4 git://localhost/user/catab/testpull
46 We must present a list of commits, so the user can choose 'start' and
47 'end'.
48 [ ] LOW: do not make the e-mail mandatory.
49 [ ] LOW: mr: add PGP signature in the pull request.
50 [ ] LOW: mr: "git diff ...otherbranch" - should I also use this to show
51 what a merge will do? This is different from git log old..new
52 when branch tip was updated.
53 [ ] LOW: optimization for merge_base: if 'against' == HEAD, just return 'against'
54 [ ] LOW: signal when a pull request from rocketgit was fetched?
55 [ ] LOW: pull rquests: subject and body must be in another div.
56 [ ] LOW: rebase: add rebase on a branch (test for conflicts first).
57 [ ] LOW: mr: add another type of merge: merge a branch into another.
58 [ ] LOW: mr: add to history when a merge is done.
59 [ ] MED: mr: a push/merge must destroy the cache git::sha1($repo_path)
60 [ ] LOW: mr: add caching for mergeability status.
61 [ ] LOW: "mode:" must be also shown nice
62 [ ] LOW: mr: commits must be isolated in div islands with some background
63 [ ] LOW: mr: maybe files should be listen on the right of the commit info?
64 [ ] LOW: mr: Commits must be indented somehow.
65 [ ] LOW: mr: between diff and "Commit xxx" the is no space!
66 [ ] LOW: In log/line.html, subject should also be a link to the commit
67 [ ] LOW: mr: allow user to resolve conflicts online?
68 [ ] LOW: mr: error messages must still show the merge information.
69 [ ] mr: what if a user pushes agains a tag instead of a branch?!
70 rg_git_short will not work correctly!
71 [ ] mr: test if a merge was already merged.
72 [ ] Do we call rg_git_reference when a push takes place?
73 [ ] Add rewind/rebase rights?
74 [ ] for any tree sha, add a link to show the tree.
75 [ ] mr: add possibility to reject a pull request (and move it to the inactive
76 queue).
77 [ ] mr: when a push is taking place, all mrs must invalidate merge_cleanly flag
78 but only if are affected by the branch!
79 Also, revalidate if the merge is ok and if not, maybe notify the owner
80 to give her/him the chance to redo it? Maybe sent her/him an access
81 code to be able to close it?
82 [ ] notes: Error: Unknown refname type provided [refs/notes/commits]
83 [ ] notes: Right ro allow notes pushing?
84 [ ] repo: delete 'mr's when deleting a repo.
85 [ ] bug: allow deleting
86 [ ] final-form: add a flag to the repo that is not maintained anymore.
87 [ ] Scellow: dark theme (https://userstyles.org/styles/37035/github-dark)
8 88 [ ] Add some hints on how to recover the password for admin user! [ ] Add some hints on how to recover the password for admin user!
9 89 Make the script to allow to change pass for any user? Make the script to allow to change pass for any user?
10 90 Think about multiple admins. Think about multiple admins.
 
256 336 [ ] unit test: check if the log is correctly generated after a push. [ ] unit test: check if the log is correctly generated after a push.
257 337 I suspect some rights problems. I suspect some rights problems.
258 338 [ ] pr: I should add also the user who made the pull request [ ] pr: I should add also the user who made the pull request
259 or anonymous. Also, IP must be shown also to the owner.
339 or anonymous.
260 340 [ ] After some releases, remove any trace of q_merge_requests! [ ] After some releases, remove any trace of q_merge_requests!
261 341 [ ] pr: seems now I go through /var/lib/rocketgit/q_merge_requests [ ] pr: seems now I go through /var/lib/rocketgit/q_merge_requests
262 342 We should use events! And then get rid of this dir. We should use events! And then get rid of this dir.
263 343 What happends now? What happends now?
264 344 Seems I need to replace rg_mr_queue_add with rg_mr_create. Seems I need to replace rg_mr_queue_add with rg_mr_create.
265 345 Cron loads merge requests from files and calls mr_queue_add. Cron loads merge requests from files and calls mr_queue_add.
266 [ ] Add avatars for notes and bugs.
346 [ ] Add avatars for bugs.
267 347 [ ] Allow an admin to run extra hooks by adding _them_ info [ ] Allow an admin to run extra hooks by adding _them_ info
268 348 /var/lib/rocketgit/extra_hooks/{update,post-receive,...}/ folder. /var/lib/rocketgit/extra_hooks/{update,post-receive,...}/ folder.
269 349 [ ] check 'man git-receive-pack' for gpg (about signed pushes). [ ] check 'man git-receive-pack' for gpg (about signed pushes).
 
307 387 - Select "Review" - optional - Select "Review" - optional
308 388 - If selected, show the diff - If selected, show the diff
309 389 - Add a commit message - Add a commit message
310 - Notify commiters?
390 - Notify committers?
311 391 Where should the "Pull requests" menu be? Where should the "Pull requests" menu be?
312 392 Show some info about the merge request: authors, files, diffstat etc. Show some info about the merge request: authors, files, diffstat etc.
313 393 4 pieces of information: src/dst repo/branch. 4 pieces of information: src/dst repo/branch.
 
... ... But, we have a problem with the expiration time!
1024 1104 lists without pagination? lists without pagination?
1025 1105 [ ] pg_fetch_assoc returns FALSE if error or no more rows. [ ] pg_fetch_assoc returns FALSE if error or no more rows.
1026 1106 We must know the difference! We must know the difference!
1027 [ ] Finish high level sql function.
1028 1107 [ ] No caching for keys.php? If we add one, update first_use only if needed. [ ] No caching for keys.php? If we add one, update first_use only if needed.
1029 1108 [ ] Rate limit at least login operations to prevent brute force passwords. [ ] Rate limit at least login operations to prevent brute force passwords.
1030 1109 Because the attack may come from several IPs, it is tempting to Because the attack may come from several IPs, it is tempting to
File hooks/pre-commit changed (mode: 100755) (index 1abab33..00184a9)
... ... rg_log("_SERVER: " . rg_array2string($_SERVER));
31 31 umask(0022); umask(0022);
32 32
33 33
34 if (rg_git_rev_ok("HEAD"))
35 $against = "HEAD";
36 else
34 if (rg_git_rev_ok("HEAD") !== FALSE)
37 35 $against = $rg_git_empty; $against = $rg_git_empty;
36 else
37 $against = "HEAD";
38 38
39 39 // TODO: Here we can deny non ascii file names // TODO: Here we can deny non ascii file names
40 40 // git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0') // git diff --cached --name-only --diff-filter=A -z $against | LC_ALL=C tr -d '[ -~]\0')
File inc/admin.inc.php changed (mode: 100644) (index 5dd3a5f..a923ebc)
... ... function rg_admin_report1($db, $rg)
334 334 'repos' => 'repositories', 'repos' => 'repositories',
335 335 'bugs' => 'bugs', 'bugs' => 'bugs',
336 336 'bug_notes' => 'bug notes', 'bug_notes' => 'bug notes',
337 'repo_history' => 'repo history',
337 338 'keys' => 'keys', 'keys' => 'keys',
338 339 'login_tokens' => 'login tokens', 'login_tokens' => 'login tokens',
339 340 'scratch_codes' => 'scratch codes', 'scratch_codes' => 'scratch codes',
File inc/git.inc.php changed (mode: 100644) (index 4d31466..528eaae)
... ... function rg_git_fatal($msg)
34 34 exit(1); exit(1);
35 35 } }
36 36
37 /*
38 * Returns the short version for a reference
39 */
40 function rg_git_short($ref)
41 {
42 if (strncmp($ref, 'refs/heads/', 11) == 0)
43 return substr($ref, 11);
44
45 if (strncmp($ref, '/refs/heads/', 12) == 0)
46 return substr($ref, 12);
47
48 return $ref;
49 }
50
37 51 function rg_git_info($msg) function rg_git_info($msg)
38 52 { {
39 53 $x = explode("\n", trim($msg)); $x = explode("\n", trim($msg));
 
... ... function rg_git_rev($rev)
263 277 function rg_git_reference($refname) function rg_git_reference($refname)
264 278 { {
265 279 // We do not accept '..' chars // We do not accept '..' chars
266 if (preg_match('/\.\./', $refname) !== 0) {
280 if (strstr($refname, '..')) {
267 281 rg_git_set_error('we do not accept \'..\' inside the ref name'); rg_git_set_error('we do not accept \'..\' inside the ref name');
268 282 return FALSE; return FALSE;
269 283 } }
270 284
271 // We do not accept '/.' chars
272 if (preg_match('/\/\./', $refname) !== 0) {
285 if (strstr($refname, '/.')) {
273 286 rg_git_set_error('we do not accept \'/.\' inside the ref name'); rg_git_set_error('we do not accept \'/.\' inside the ref name');
274 287 return FALSE; return FALSE;
275 288 } }
276 289
277 // We do not accept '\\' chars
278 if (preg_match('/\\\\/', $refname) !== 0) {
290 if (strstr($refname, '\\\\')) {
279 291 rg_git_set_error('we do not accept \'\\\\\' inside the ref name'); rg_git_set_error('we do not accept \'\\\\\' inside the ref name');
280 292 return FALSE; return FALSE;
281 293 } }
 
... ... function rg_git_rev_ok($rev)
312 324
313 325 $ret = FALSE; $ret = FALSE;
314 326 while (1) { while (1) {
315 $cmd = "git rev-parse --verify '" . $rev . "'";
327 $cmd = 'git rev-parse --verify ' . escapeshellarg($rev);
316 328 $a = rg_exec($cmd); $a = rg_exec($cmd);
317 329 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
318 330 rg_git_set_error("error on rev-parse (" . $a['errmsg'] . ")"); rg_git_set_error("error on rev-parse (" . $a['errmsg'] . ")");
319 331 break; break;
320 332 } }
321 333
322 $ret = TRUE;
334 $ret = trim($a['data']);
323 335 break; break;
324 336 } }
325 337
 
... ... function rg_git_whitespace_ok($old, $new)
364 376 return $ret; return $ret;
365 377 } }
366 378
367 // TODO: Unit testing
368 function rg_git_merge_base($old, $new)
379 /*
380 * Loads refs/heads/BRANCH
381 */
382 function rg_git_load_ref($repo_path, $ref)
369 383 { {
370 rg_prof_start("git_merge_base");
371 rg_log_enter("git_merge_base: old=$old new=$new");
384 global $rg_git_empty;
385
386 $b = rg_git_reference($ref);
387 if ($b === FALSE)
388 return FALSE;
389
390 $b = rg_git_short($b);
391 $path = $repo_path . '/refs/heads/' . $b;
392 $r = @file_get_contents($path);
393 if ($r === FALSE) {
394 // probably is a sha1
395 $r = $ref;
396 }
397
398 $ret = trim($r);
399 rg_log('DEBUG: git_load_ref[' . $ref . ']=' . $ret);
400 return $ret;
401 }
402
403 /*
404 * Returns a common ancestor between two commits
405 * TODO: Unit testing
406 */
407 function rg_git_merge_base($repo_path, $a, $b)
408 {
409 global $rg_git_zero;
410 global $rg_git_empty;
411
412 rg_prof_start('git_merge_base');
413 rg_log_enter('git_merge_base' . ' a=' . $a . ' b=' . $b);
372 414
373 415 $ret = FALSE; $ret = FALSE;
374 416 while (1) { while (1) {
375 $cmd = "git merge-base " . $old . " " . $new;
417 if (empty($repo_path))
418 $add = '';
419 else
420 $add = ' --git-dir=' . escapeshellarg($repo_path);
421
422 if (!empty($repo_path)) {
423 $head = rg_git_load_ref($repo_path, $a);
424 if ($head === FALSE)
425 break;
426
427 $key = 'git'
428 . '::' . sha1($repo_path)
429 . '::' . 'merge-base'
430 . '::' . $head . '::' . $b;
431 $r = rg_cache_get($key);
432 if ($r !== FALSE) {
433 $ret = $r;
434 break;
435 }
436 }
437
438 $cmd = 'git'
439 . $add
440 . ' merge-base'
441 . ' ' . escapeshellarg($a)
442 . ' ' . escapeshellarg($b);
376 443 $a = rg_exec($cmd); $a = rg_exec($cmd);
377 444 if ($a['ok'] != 1) { if ($a['ok'] != 1) {
378 rg_git_set_error("error on merge-base (" . $a['errmsg'] . ")");
445 rg_git_set_error('error on git merge_base ('
446 . $a['errmsg'] . ')');
379 447 break; break;
380 448 } }
381 449
382 450 $ret = trim($a['data']); $ret = trim($a['data']);
451
452 if (!empty($repo_path))
453 rg_cache_set($key, $ret, RG_SOCKET_NO_WAIT);
454
383 455 break; break;
384 456 } }
385 457
386 458 rg_log_exit(); rg_log_exit();
387 rg_prof_end("git_merge_base");
459 rg_prof_end('git_merge_base');
388 460 return $ret; return $ret;
389 461 } }
390 462
 
... ... function rg_git_merge_base($old, $new)
393 465 * If @new is empty, we assume a delete * If @new is empty, we assume a delete
394 466 * TODO: Unit testing * TODO: Unit testing
395 467 */ */
396 function rg_git_update_ref($ref, $old, $new, $reason)
468 function rg_git_update_ref($repo_path, $ref, $old, $new, $reason)
397 469 { {
398 470 rg_prof_start("git_update_ref"); rg_prof_start("git_update_ref");
399 471 rg_log_enter("git_update_ref: ref=$ref old=$old new=$new reason=$reason"); rg_log_enter("git_update_ref: ref=$ref old=$old new=$new reason=$reason");
400 472
401 473 $ret = FALSE; $ret = FALSE;
402 474 while (1) { while (1) {
403 $cmd = "git update-ref";
475 $cmd = 'git --git-dir=' . escapeshellarg($repo_path);
476 $cmd .= ' update-ref';
477
404 478 if (!empty($reason)) if (!empty($reason))
405 479 $cmd .= " -m " . escapeshellarg($reason); $cmd .= " -m " . escapeshellarg($reason);
406 480
 
... ... function rg_git_update_ref($ref, $old, $new, $reason)
427 501 return $ret; return $ret;
428 502 } }
429 503
504 /*
505 * git shortlog command
506 */
507 function rg_git_shortlog($repo_path, $a, $b)
508 {
509 rg_prof_start('git_shortlog');
510 rg_log_enter('git_shortlog: a=' . $a . ' b=' . $b);
511
512 $ret = FALSE;
513 while (1) {
514 $cmd = 'git shortlog'
515 . ' --git-dir=' . escapeshellarg($repo_path)
516 . ' ' . escapeshellarg($a) . '..' . escapeshellarg($b);
517 $r = rg_exec($cmd);
518 if ($r['ok'] != 1) {
519 rg_git_set_error('error on shortlog (' . $r['errmsg'] . ')');
520 break;
521 }
522
523 $ret = trim($r['data']);
524 break;
525 }
526
527 rg_log_exit();
528 rg_prof_end("git_shortlog");
529 return $ret;
530 }
531
430 532 /* /*
431 533 * Returns a tree (git ls-tree) * Returns a tree (git ls-tree)
432 534 */ */
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
698 800
699 801 $ret = FALSE; $ret = FALSE;
700 802 while (1) { while (1) {
701 if (!file_exists($path . "/refs/heads/master")) {
702 if (!file_exists($path . "/.git/refs/heads/master")) {
703 rg_log("Repo is empty.");
704 $ret = array();
705 break;
706 }
707 }
708
709 $max_count = ($max == 0) ? "" : " --max-count=$max";
710 $patches = $also_patch ? " --patch" : " --shortstat";
803 $test_for_master = TRUE;
711 804
712 805 if (empty($from) && empty($to)) { if (empty($from) && empty($to)) {
806 rg_log('from/to empty');
713 807 $from_to = ''; $from_to = '';
808 } else if (empty($from)) {
809 rg_log('from empty');
810 $from_to = ' ' . $to;
811 } else if (strcmp($from, $rg_git_zero) == 0) {
812 rg_log('from zero');
813 $from_to = ' ' . $rg_git_empty . '..' . $to;
814 $test_for_master = FALSE;
714 815 } else { } else {
715 if (empty($from))
716 $from_to = ' ' . $to;
717 else if (strcmp($from, $rg_git_zero) == 0)
718 $from_to = ' ' . $rg_git_empty . '..' . $to;
719 else
720 $from_to = ' ' . $from . '..' . $to;
816 $from_to = ' ' . $from . '..' . $to;
817 }
818
819 if ($test_for_master) {
820 if (!file_exists($path . "/refs/heads/master")) {
821 if (!file_exists($path . "/.git/refs/heads/master")) {
822 rg_log("Repo is empty.");
823 $ret = array();
824 break;
825 }
826 }
721 827 } }
722 828
829 $max_count = ($max == 0) ? "" : " --max-count=$max";
830 $patches = $also_patch ? " --patch" : " --shortstat";
831
723 832 $cmd = "git --no-pager" $cmd = "git --no-pager"
724 833 . " --git-dir=" . escapeshellarg($path) . " --git-dir=" . escapeshellarg($path)
725 834 . " log" . " log"
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
730 839 . $patches . $patches
731 840 . " --pretty=\"format:" . " --pretty=\"format:"
732 841 . "%x00-=ROCKETGIT=-%x00" . "%x00-=ROCKETGIT=-%x00"
842 . "sha1:%H%x00\"\""
733 843 . "sha1_short:%h%x00\"\"" . "sha1_short:%h%x00\"\""
734 . "sha1_long:%H%x00\"\""
735 . "tree:%t%x00\"\""
844 . "tree:%T%x00\"\""
845 . "tree_short:%t%x00\"\""
846 . "parents:%P%x00\"\""
736 847 . "parents_short:%p%x00\"\"" . "parents_short:%p%x00\"\""
737 . "parents_long:%P%x00\"\""
738 848 . "author name:%aN%x00\"\"" . "author name:%aN%x00\"\""
739 849 . "author email:%aE%x00\"\"" . "author email:%aE%x00\"\""
740 850 . "author date:%at%x00\"\"" . "author date:%at%x00\"\""
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
742 852 . "committer email:%ce%x00\"\"" . "committer email:%ce%x00\"\""
743 853 . "committer date:%ct%x00\"\"" . "committer date:%ct%x00\"\""
744 854 . "encoding:%e%x00\"\"" . "encoding:%e%x00\"\""
855 . "ref_names:%d%x00\"\""
856 . "sign_key:%GK%x00\"\""
745 857 . "subject:%s%x00\"\"" . "subject:%s%x00\"\""
746 858 . "body:%b%x00\"\"" . "body:%b%x00\"\""
747 859 . "notes:%N%x00\"\"" . "notes:%N%x00\"\""
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
773 885 // vars // vars
774 886 $y['vars']['lines_add'] = 0; $y['vars']['lines_add'] = 0;
775 887 $y['vars']['lines_del'] = 0; $y['vars']['lines_del'] = 0;
776 $y['vars']['files_cahnged'] = 0;
777 888 $x = explode ("\0", trim($parts[0])); $x = explode ("\0", trim($parts[0]));
778 889 $count = count($x); $count = count($x);
779 890 for ($i = 0; $i < $count - 1; $i++) { for ($i = 0; $i < $count - 1; $i++) {
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
795 906
796 907 $y['vars']['lines_add'] = $_extra['lines_add']; $y['vars']['lines_add'] = $_extra['lines_add'];
797 908 $y['vars']['lines_del'] = $_extra['lines_del']; $y['vars']['lines_del'] = $_extra['lines_del'];
798 // TODO: add files_cahnged field!
799 909 } else { } else {
800 910 // stortstat // stortstat
801 911 rg_log('DEBUG parts[1]: ' . print_r($parts[1], TRUE)); rg_log('DEBUG parts[1]: ' . print_r($parts[1], TRUE));
802 912 $t = explode(',', $parts[1]); $t = explode(',', $parts[1]);
803 $y['vars']['files_changed'] = intval($t[0]);
804 913
805 914 for ($i = 1; $i < 3; $i++) { for ($i = 1; $i < 3; $i++) {
806 915 if (!isset($t[$i])) if (!isset($t[$i]))
 
... ... function rg_git_files($old, $new)
944 1053 /* /*
945 1054 * Nice diff per file * Nice diff per file
946 1055 * Outputs the result of replacing variables in a template with real variables * Outputs the result of replacing variables in a template with real variables
1056 * @id - uniq id, most of the time the commit sha1; used to differentiate
1057 * between same files in different commits.
947 1058 * @a - output of rg_git_diff2array[index]['files'] * @a - output of rg_git_diff2array[index]['files']
948 1059 * TODO: Switch to rg_template_table? * TODO: Switch to rg_template_table?
949 1060 */ */
950 function rg_git_diff($a, $template_file)
1061 function rg_git_diff($id, $a, $template_file)
951 1062 { {
952 1063 rg_prof_start("git_diff"); rg_prof_start("git_diff");
953 1064 //rg_log_enter("DEBUG: git_diff: a: " . rg_array2string($a)); //rg_log_enter("DEBUG: git_diff: a: " . rg_array2string($a));
954 1065
1066 $id = rg_xss_safe($id);
1067
955 1068 $ret = "<div class=\"diff\">\n"; $ret = "<div class=\"diff\">\n";
956 1069
957 1070 $x = array(); $x = array();
 
... ... function rg_git_diff($a, $template_file)
964 1077 $ret .= "<br />\n"; $ret .= "<br />\n";
965 1078
966 1079 $f = rg_xss_safe($finfo['file']); $f = rg_xss_safe($finfo['file']);
967 $ret .= "<a name=\"file-$f\"></a>\n";
1080 $ret .= '<a name="file-' . $id . '-' . $f . '"></a>' . "\n";
968 1081
969 1082 $ret .= "<table class=\"chunk\" summary=\"chunk\">\n"; $ret .= "<table class=\"chunk\" summary=\"chunk\">\n";
970 1083 $ret .= "<tr style=\"border: 1px; background: #dddddd\"><td colspan=\"4\">"; $ret .= "<tr style=\"border: 1px; background: #dddddd\"><td colspan=\"4\">";
 
... ... function rg_git_diff($a, $template_file)
998 1111 $ret .= " (index " . rg_xss_safe($finfo['index']) . ")"; $ret .= " (index " . rg_xss_safe($finfo['index']) . ")";
999 1112
1000 1113 // TODO: Before stats we must show commit hash, author etc. (source/log/commit/xxxxxx) // TODO: Before stats we must show commit hash, author etc. (source/log/commit/xxxxxx)
1001 // TODO: what about commiter and time and rest?
1114 // TODO: what about committer and time and rest?
1002 1115
1003 1116 $ret .= ":"; $ret .= ":";
1004 1117 $ret .= "</td></tr>\n"; $ret .= "</td></tr>\n";
 
... ... function rg_git_update_tag($db, $a)
1177 1290 if (!empty($a['namespace'])) { if (!empty($a['namespace'])) {
1178 1291 // Update the main ref (not a namespace) // Update the main ref (not a namespace)
1179 1292 $reason = $a['login_username'] . ' pushed tag ' . $a['refname']; $reason = $a['login_username'] . ' pushed tag ' . $a['refname'];
1180 $r = rg_git_update_ref($a['refname'], $a['old_rev'],
1181 $a['new_rev'], $reason);
1293 $r = rg_git_update_ref($a['repo_path'], $a['refname'],
1294 $a['old_rev'], $a['new_rev'], $reason);
1182 1295 if ($r !== TRUE) { if ($r !== TRUE) {
1183 1296 rg_git_fatal($a['refname'] . "\nCannot update ref (" rg_git_fatal($a['refname'] . "\nCannot update ref ("
1184 1297 . rg_git_error() . ")"); . rg_git_error() . ")");
 
... ... function rg_git_update_tag($db, $a)
1192 1305 } }
1193 1306
1194 1307 /* /*
1195 *
1308 * Called from hooks
1196 1309 */ */
1197 1310 function rg_git_update_branch($db, $a) function rg_git_update_branch($db, $a)
1198 1311 { {
 
... ... function rg_git_update_branch($db, $a)
1245 1358 $x = $_x; $x = $_x;
1246 1359 $x['needed_rights'] = 'O'; $x['needed_rights'] = 'O';
1247 1360 if ((rg_rights_allow($db, $x) !== TRUE) && ($check_fast_forward == 1)) { if ((rg_rights_allow($db, $x) !== TRUE) && ($check_fast_forward == 1)) {
1248 $merge_base = rg_git_merge_base($a['old_rev'], $a['new_rev']);
1361 $merge_base = rg_git_merge_base($a['repo_path'], $a['old_rev'],
1362 $a['new_rev']);
1249 1363 if ($merge_base === FALSE) { if ($merge_base === FALSE) {
1250 1364 rg_log("Error in merge_base: " . rg_git_error()); rg_log("Error in merge_base: " . rg_git_error());
1251 1365 rg_git_fatal($a['refname'] . "\nInternal error." rg_git_fatal($a['refname'] . "\nInternal error."
 
... ... function rg_git_update_branch($db, $a)
1262 1376 $x = $_x; $x = $_x;
1263 1377 $x['needed_rights'] = 'M'; $x['needed_rights'] = 'M';
1264 1378 if (rg_rights_allow($db, $x) !== TRUE) { if (rg_rights_allow($db, $x) !== TRUE) {
1265 if (rg_git_rev_ok($a['new_rev'] . "^2"))
1379 if (rg_git_rev_ok($a['new_rev'] . "^2") !== FALSE)
1266 1380 rg_git_fatal($a['refname'] rg_git_fatal($a['refname']
1267 1381 . "\nYou have no rights to push merges."); . "\nYou have no rights to push merges.");
1268 1382 } }
 
... ... function rg_git_update_branch($db, $a)
1319 1433 } }
1320 1434
1321 1435 // anonymous push - create a merge request // anonymous push - create a merge request
1322 // TODO: git may fail to update the reference after this hook;
1323 // the mr code should check if the update was done.
1324 $mr = "refs/mr/"
1325 . str_replace('refs/heads/', '', $a['refname'])
1326 . "_" . str_replace('rg_', '', $a['namespace']);
1327 $reason = $a['login_username'] . ' pushed a merge request'
1328 . ' for ref ' . $a['refname']
1329 . ' into namespace ' . $mr;
1330 $r = rg_git_update_ref($mr, "", $a['new_rev'], $reason);
1331 if ($r !== TRUE) {
1332 rg_log("Cannot update-ref: " . rg_git_error());
1333 rg_git_fatal($a['refname'] . ": Cannot set refs/mr/."
1334 . " Try again later.");
1335 }
1336 1436 $ev = $a; $ev = $a;
1337 $ev['category'] = 7000;
1437 $ev['category'] = 'rg_mr_event_new';
1338 1438 $ev['prio'] = 100; $ev['prio'] = 100;
1339 1439 $ev['ui'] = array('uid' => $a['login_uid']); $ev['ui'] = array('uid' => $a['login_uid']);
1340 1440 $r = rg_event_add($db, $ev); $r = rg_event_add($db, $ev);
 
... ... function rg_git_update_branch($db, $a)
1348 1448
1349 1449 $history['history_category'] = REPO_CAT_GIT_BRANCH_ANON_PUSH; $history['history_category'] = REPO_CAT_GIT_BRANCH_ANON_PUSH;
1350 1450 $history['history_message'] = 'Anonymous push to ref ' $history['history_message'] = 'Anonymous push to ref '
1351 . $a['refname'] . ' into namespace ' . $mr;
1451 . $a['refname'] . ' into namespace ' . $a['namespace'];
1352 1452 } else { } else {
1353 1453 rg_log("DEBUG: We are allowed to push."); rg_log("DEBUG: We are allowed to push.");
1354 1454
 
... ... function rg_git_update_branch($db, $a)
1358 1458 // Updating main ref (not a namespace) // Updating main ref (not a namespace)
1359 1459 $reason = $a['login_username'] $reason = $a['login_username']
1360 1460 . ' pushed ref ' . $a['refname']; . ' pushed ref ' . $a['refname'];
1361 $r = rg_git_update_ref($a['refname'], $a['old_rev'],
1362 $a['new_rev'], $reason);
1461 $r = rg_git_update_ref($a['repo_path'], $a['refname'],
1462 $a['old_rev'], $a['new_rev'], $reason);
1363 1463 if ($r !== TRUE) { if ($r !== TRUE) {
1364 1464 rg_git_fatal($a['refname'] rg_git_fatal($a['refname']
1365 1465 . "\nCannot update ref (" . "\nCannot update ref ("
 
... ... function rg_git_content_by_file($treeish, $file)
1586 1686 function rg_git_log2listing($log, $rg, $commit_table) function rg_git_log2listing($log, $rg, $commit_table)
1587 1687 { {
1588 1688 if ($log === FALSE) if ($log === FALSE)
1589 return rg_template('repo/not_init.html', $rg, TRUE /* xss */);
1689 return rg_template('repo/not_init.html', $rg, TRUE/*xss*/);
1590 1690
1591 1691 $ret = ''; $ret = '';
1592 1692
 
... ... function rg_git_log2listing($log, $rg, $commit_table)
1595 1695 // Set 'url' // Set 'url'
1596 1696 foreach ($log as $index => $i) foreach ($log as $index => $i)
1597 1697 $log[$index]['vars']['commit_url'] = $log[$index]['vars']['commit_url'] =
1598 rg_xss_safe($rg['mr'])
1599 . "#sha1-" . rg_xss_safe($i['vars']['sha1_short']);
1698 rg_xss_safe($rg['mr']['id'])
1699 . "#sha1-" . rg_xss_safe($i['vars']['sha1']);
1600 1700 $ret .= rg_git_log_template($log, 'repo/log', $rg); $ret .= rg_git_log_template($log, 'repo/log', $rg);
1601 1701 } }
1602 1702
1603 1703 // TODO: move this into a template! // TODO: move this into a template!
1704 $ret .= '<div style="margin-top: 8pt; margin-left: 8pt">' . "\n";
1604 1705 foreach ($log as $junk => $i) { foreach ($log as $junk => $i) {
1706 //rg_log_ml('DEBUG: i=' . print_r($i, TRUE));
1707
1605 1708 // Some info about commit // Some info about commit
1606 $ret .= "<br /><b>"
1607 . "<a name=\"sha1-" . rg_xss_safe($i['vars']['sha1_short']) . "\">"
1608 . "Commit " . rg_xss_safe($i['vars']['sha1_short'])
1709 $ret .= "<b>"
1710 . "<a name=\"sha1-" . rg_xss_safe($i['vars']['sha1']) . "\">"
1711 . "Commit " . rg_xss_safe($i['vars']['sha1'])
1609 1712 . "</a></b> - " . rg_xss_safe($i['vars']['subject']) . "\n"; . "</a></b> - " . rg_xss_safe($i['vars']['subject']) . "\n";
1610 1713
1611 1714 if (!empty($i['vars']['body'])) if (!empty($i['vars']['body']))
1612 1715 $ret .= "<br />\n" $ret .= "<br />\n"
1613 1716 . nl2br(rg_xss_safe($i['vars']['body'])); . nl2br(rg_xss_safe($i['vars']['body']));
1614 1717
1615 $ret .= "<br />\n"
1616 . "<b>Author</b>: " . rg_xss_safe($i['vars']['author name']);
1718 $ret .= "<br /><b>Author</b>: " . rg_xss_safe($i['vars']['author name']);
1617 1719
1618 if (!empty($i['vars']['commiter name']))
1619 $ret .= "<br />\n"
1620 . "<b>Commiter</b>: " . rg_xss_safe($i['vars']['commiter name']);
1720 $ret .= "<br /><b>Author date (UTC)</b>: "
1721 . gmdate("Y-m-d H:i", $i['vars']['author date']);
1621 1722
1622 $ret .= "<br />\n"
1623 . "<b>Date (UTC)</b>: " . gmdate("Y-m-d H:i", $i['vars']['author date']);
1624 $ret .= "<br />\n";
1723 if (!empty($i['vars']['committer name']))
1724 $ret .= "<br /><b>Committer</b>: "
1725 . rg_xss_safe($i['vars']['committer name']);
1726
1727 $ret .= '<br /><b>Commit date (UTC)</b>: '
1728 . gmdate("Y-m-d H:i", $i['vars']['committer date']);
1729
1730 $ret .= '<br /><b>Tree</b>: ' . $i['vars']['tree'];
1731
1732 if (!empty($i['vars']['parents']))
1733 $ret .= '<br /><b>Parents</b>: '
1734 . $i['vars']['parents'];
1735
1736 if (!empty($i['vars']['sign_key']))
1737 $ret .= '<br /><b>Signing key</b>: '
1738 . $i['vars']['sign_key'];
1625 1739
1626 1740 // stats // stats
1627 1741 $r = rg_git_files_stats($i['files'], 'repo/fstat'); $r = rg_git_files_stats($i['files'], 'repo/fstat');
 
... ... function rg_git_log2listing($log, $rg, $commit_table)
1631 1745
1632 1746 // diff // diff
1633 1747 //rg_log_ml("DEBUG: i[files]=" . print_r($i['files'], TRUE)); //rg_log_ml("DEBUG: i[files]=" . print_r($i['files'], TRUE));
1634 $r = rg_git_diff($i['files'], 'repo/diff.html');
1748 $r = rg_git_diff($i['vars']['sha1'], $i['files'],
1749 'repo/diff.html');
1635 1750 if ($r === FALSE) if ($r === FALSE)
1636 1751 return "Internal error"; return "Internal error";
1637 1752 $ret .= $r; $ret .= $r;
1638 1753 } }
1754 $ret .= '</div>' . "\n";
1639 1755
1640 1756 return $ret; return $ret;
1641 1757 } }
 
... ... function rg_git_archive($repo_path, $treeish, $archive_name, $format)
1673 1789 return $ret; return $ret;
1674 1790 } }
1675 1791
1792 /*
1793 * Tests if a merge will result in conflicts
1794 ****************** Example for conflict:
1795 * changed in both
1796 * base 100644 72943a16fb2c8f38f9dde202b7a70ccc19c52f34 a
1797 * our 100644 959479a9d0d05bf843067e5f9fb4b2abef354f70 a
1798 * their 100644 dbee0265d31298531773537e6e37e4fd1ee71d62 a
1799 * @@ -1,2 +1,6 @@
1800 * aaa
1801 * +<<<<<<< .our
1802 * ccc
1803 * +=======
1804 * +bbb
1805 * +>>>>>>> .their
1806 *
1807 ****************** Example for a merge without conflicts:
1808 * merged
1809 * result 100644 3c5556ce5ed90f293dd05e5942ccdbff43a71556 a
1810 * our 100644 959479a9d0d05bf843067e5f9fb4b2abef354f70 a
1811 * @@ -1,2 +1,2 @@
1812 * aaa
1813 * -ccc
1814 * +ddd
1815 */
1816 function rg_git_merge_tree($repo_path, $base, $a, $b)
1817 {
1818 global $rg_git_zero;
1819 global $rg_git_empty;
1820
1821 rg_prof_start('git_merge_tree');
1822 rg_log_enter('rg_git_merge_tree base='
1823 . $base . ' a=' . $a . ' b=' . $b);
1824
1825 $ret = FALSE;
1826 while (1) {
1827 $head = rg_git_load_ref($repo_path, $a);
1828 if ($head === FALSE)
1829 break;
1830 $key = 'git'
1831 . '::' . sha1($repo_path)
1832 . '::' . 'merge-tree'
1833 . '::' . $head . '::' . $b;
1834 $r = rg_cache_get($key);
1835 if ($r !== FALSE) {
1836 $ret = $r;
1837 break;
1838 }
1839
1840 $cmd = 'git --git-dir=' . escapeshellarg($repo_path)
1841 . ' merge-tree'
1842 . ' ' . escapeshellarg($base)
1843 . ' ' . escapeshellarg($a)
1844 . ' ' . escapeshellarg($b);
1845 $a = rg_exec($cmd);
1846 if ($a['ok'] != 1) {
1847 rg_git_set_error('error on git merge-tree ('
1848 . $a['errmsg'] . ')');
1849 break;
1850 }
1851
1852 $ret = trim($a['data']);
1853 rg_cache_set($key, $ret, RG_SOCKET_NO_WAIT);
1854 rg_log_ml('DEBUG: merge-tree: ' . $ret);
1855 break;
1856 }
1857
1858 rg_log_exit();
1859 rg_prof_end('git_merge_tree');
1860 return $ret;
1861 }
1862
1863 function rg_git_merge_tree_html($repo_path, $base, $a, $b)
1864 {
1865 $r = rg_git_merge_tree($repo_path, $base, $a, $b);
1866 if ($r === FALSE)
1867 return rg_git_error();
1868
1869 return nl2br(rg_xss_safe($r));
1870 }
1871
1872 /*
1873 * Returns the status of a pull request
1874 * Returns FALSE on error, 1 if merge is without conflict, else 0
1875 */
1876 function rg_git_merge_without_conflict($repo_path, $a, $b)
1877 {
1878 rg_log_enter('git_merge_without_conflict a=' . $a . ' b=' . $b);
1879
1880 $ret = FALSE;
1881 while (1) {
1882 $base = rg_git_merge_base($repo_path, $a, $b);
1883 if ($base === FALSE)
1884 break;
1885
1886 $out = rg_git_merge_tree($repo_path, $base, $a, $b);
1887 if($out === FALSE)
1888 break;
1889
1890 $r = strstr($out, "\n+<<<<<<<");
1891 if ($r === FALSE) {
1892 $ret = 1;
1893 break;
1894 }
1895
1896 $ret = 0;
1897 break;
1898 }
1899
1900 rg_log_exit();
1901 return $ret;
1902 }
1903
1904 /*
1905 * Do a merge
1906 * @ff - 0 = no fast-forward, 1 = fast-forward allowed
1907 * @msg - merge message
1908 * Returns the output of the command or FALSE
1909 */
1910 function rg_git_merge($repo_path, $a, $b, $ff, $msg)
1911 {
1912 global $rg_git_zero;
1913 global $rg_git_empty;
1914
1915 rg_prof_start('git_merge');
1916 rg_log_enter('git_merge' . ' a=' . $a . ' b=' . $b . ' ff=' . $ff
1917 . ' msg=' . $msg);
1918
1919 $ret = FALSE;
1920 while (1) {
1921 if (empty($repo_path))
1922 $add = '';
1923 else
1924 $add = ' --git-dir=' . escapeshellarg($repo_path);
1925
1926 $work_tree = rg_tmp_path('git_merge_' . rg_id(10));
1927 $r = @mkdir($work_tree, 0700, TRUE);
1928 if ($r !== TRUE) {
1929 rg_git_set_error('cannot create temporary dir for merge');
1930 break;
1931 }
1932 $add .= ' --work-tree ' . escapeshellarg($work_tree);
1933
1934 if ($ff == 1)
1935 $add_ff = ' --ff';
1936 else
1937 $add_ff = ' --no-ff';
1938
1939 $cmd = 'git'
1940 . $add
1941 . ' merge'
1942 . $add_ff
1943 . ' --stat'
1944 . ' -m ' . escapeshellarg($msg)
1945 . ' ' . escapeshellarg($a)
1946 . ' ' . escapeshellarg($b);
1947 $a = rg_exec($cmd);
1948 rg_rmdir($work_tree);
1949 if ($a['ok'] != 1) {
1950 rg_git_set_error('error on git merge ('
1951 . $a['errmsg'] . ')');
1952 break;
1953 }
1954
1955 $ret = trim($a['data']);
1956 break;
1957 }
1958
1959 rg_log_exit();
1960 rg_prof_end('git_merge');
1961 return $ret;
1962 }
1963
1964 /*
1965 * Creates a pull request against a user repo to be sent by e-mail
1966 */
1967 function rg_git_request_pull($repo_path, $start, $url, $end, $patch)
1968 {
1969 global $rg_git_zero;
1970 global $rg_git_empty;
1971
1972 rg_prof_start('git_request_pull');
1973 rg_log_enter('git_request_pull' . ' start=' . $start
1974 . ' url=' . $url . ' end=' . $end
1975 . ' patch=' . ($patch ? 'yes' : 'no'));
1976
1977 $text = '';
1978 $ret = FALSE;
1979 while (1) {
1980 $rg['req'] = array();
1981 $rg['req']['start'] = $start;
1982 $rg['req']['url'] = $url;
1983 $rg['req']['end'] = $end;
1984
1985 $text .= rg_template('repo/mr/req-pull.txt', $rg, TRUE/*xss*/);
1986
1987 $r = rg_git_shortlog($repo_path, $baserev, $headrev);
1988 if ($r === FALSE)
1989 break;
1990 $text .= $r;
1991
1992 $cmd = 'git diff -M --stat --summary';
1993 if ($patch)
1994 $cmd .= ' --patch';
1995 $cmd .= escapeshellarg($start) . '..' . escapeshellarg($end);
1996 $r = rg_exec($cmd);
1997 if ($a['ok'] != 1) {
1998 rg_git_set_error('error on git diff: ' . $a['errmsg']);
1999 break;
2000 }
2001 $text .= $r['data'];
2002
2003 $ret = $text;
2004 break;
2005 }
2006
2007 rg_log_exit();
2008 rg_prof_end('git_pull_request');
2009 return $ret;
2010 }
2011
1676 2012 ?> ?>
File inc/mr.inc.php changed (mode: 100644) (index 399e80a..3c8ed10)
3 3
4 4 require_once($INC . "/util.inc.php"); require_once($INC . "/util.inc.php");
5 5 require_once($INC . "/sql.inc.php"); require_once($INC . "/sql.inc.php");
6 require_once($INC . '/user.inc.php');
6 7 require_once($INC . "/events.inc.php"); require_once($INC . "/events.inc.php");
7 8
8 9 $rg_mr_env_q = getenv("ROCKETGIT_MR_QUEUE"); $rg_mr_env_q = getenv("ROCKETGIT_MR_QUEUE");
 
... ... function rg_mr_error()
26 27 return $rg_mr_error; return $rg_mr_error;
27 28 } }
28 29
30
29 31 /* /*
30 * Events functions
32 * Event functions
31 33 */ */
32 34 $rg_mr_functions = array( $rg_mr_functions = array(
33 7000 => 'rg_mr_event_new',
34 7001 => 'rg_mr_event_add_to_db'
35 'rg_mr_event_new' => 'rg_mr_event_new',
36 'rg_mr_event_add_to_db' => 'rg_mr_event_add_to_db',
37 'mr_merge' => 'rg_mr_event_merge'
35 38 ); );
36 39 rg_event_register_functions($rg_mr_functions); rg_event_register_functions($rg_mr_functions);
37 40
41 /*
42 * This is called when the user press "Merge" button
43 */
44 function rg_mr_event_merge($db, $ev)
45 {
46 $ret = array();
47
48 // TODO: we should send the error messages only at last try! Anywhere! Really?!
49 // TODO: care! we should not send the mail before doing the merge!
50 // TODO: check also all the other events.
51 // do the merge
52
53 $r = rg_git_merge($ev['repo_path'], $ev['merge_against'],
54 $ev['mri']['new_rev'], $ev['merge_ff'], $ev['merge_msg']);
55 if ($r === FALSE) {
56 rg_log('Merge failed: ' . rg_git_error());
57 // TODO: notify ui['uid'] that the merge failed
58 rg_mail_template('repo/mail/merge_failed', $ev);
59 return $ret;
60 }
61
62 $r = rg_mr_merge_set_status($db, $ev['ri']['repo_id'],
63 $ev['mri']['id'], time());
64 if ($r === FALSE)
65 return FALSE;
66
67 // notify the requester (if not anonymous)
68 // TODO: notify the watchers?
69 // TODO: notify the users who commented on the pull request?
70 // TODO: notify users who watch the pull request?
71
72 return $ret;
73 }
74
38 75 /* /*
39 76 * This is called when a new pull request is done * This is called when a new pull request is done
40 77 */ */
 
... ... function rg_mr_event_new($db, $ev)
44 81
45 82 // Insert it into database // Insert it into database
46 83 $ret[] = array_merge($ev, $ret[] = array_merge($ev,
47 array('category' => 7001, 'prio' => 100));
84 array('category' => 'rg_mr_event_add_to_db', 'prio' => 100));
48 85
49 86 // TODO: Notify admins of the repo // TODO: Notify admins of the repo
50 87
 
... ... function rg_mr_event_new($db, $ev)
59 96 function rg_mr_event_add_to_db($db, $a) function rg_mr_event_add_to_db($db, $a)
60 97 { {
61 98 rg_prof_start('mr_event_add_to_db'); rg_prof_start('mr_event_add_to_db');
62 rg_log_start('mr_add_to_db: a: ' . rg_array2string($a));
99 rg_log_enter('mr_add_to_db: a: ' . rg_array2string($a));
63 100
64 101 $now = time(); $now = time();
65 102
 
... ... function rg_mr_event_add_to_db($db, $a)
67 104 $rollback = 0; $rollback = 0;
68 105 while (1) { while (1) {
69 106 if (rg_sql_begin($db) !== TRUE) { if (rg_sql_begin($db) !== TRUE) {
70 rg_mr_set_error('start tranzaction failed');
107 rg_mr_set_error('start transaction failed');
71 108 break; break;
72 109 } }
73 110
 
... ... function rg_mr_event_add_to_db($db, $a)
79 116 break; break;
80 117 } }
81 118
119 // TODO: git may fail to update the reference after this hook;
120 // the mr code should check if the update was done.
121 $mr = 'refs/mr/' . $id;
122 $reason = $a['login_username'] . ' pushed a merge request'
123 . ' for ref ' . $a['refname']
124 . ' into ' . $mr;
125 $r = rg_git_update_ref($a['repo_path'], $mr, '', $a['new_rev'], $reason);
126 if ($r !== TRUE) {
127 rg_mr_set_error('cannot update-ref: ' . rg_git_error());
128 break;
129 }
130
82 131 $a['id'] = $id; $a['id'] = $id;
132 $a['who'] = $a['ui']['uid'];
83 133 $sql = 'INSERT INTO merge_requests (repo_id, id, itime' $sql = 'INSERT INTO merge_requests (repo_id, id, itime'
84 . ', namespace, refname, old_rev, new_rev, done, ip)'
134 . ', namespace, refname, old_rev, new_rev, done, ip'
135 . ', who)'
85 136 . ' VALUES (@@repo_id@@, @@id@@, @@itime@@' . ' VALUES (@@repo_id@@, @@id@@, @@itime@@'
86 137 . ', @@namespace@@, @@refname@@, @@old_rev@@' . ', @@namespace@@, @@refname@@, @@old_rev@@'
87 . ', @@new_rev@@, 0, @@ip@@)';
138 . ', @@new_rev@@, 0, @@ip@@, @@who@@)';
88 139 $res = rg_sql_query_params($db, $sql, $a); $res = rg_sql_query_params($db, $sql, $a);
89 140 if ($res === FALSE) { if ($res === FALSE) {
90 141 rg_mr_set_error('cannot insert merge request'); rg_mr_set_error('cannot insert merge request');
 
... ... function rg_mr_queue_process($db)
185 236 /* /*
186 237 * Helper to cosmetic mr data * Helper to cosmetic mr data
187 238 */ */
188 function rg_mr_cosmetic(&$row)
239 function rg_mr_cosmetic($db, &$row)
189 240 { {
190 241 $row['date_utc'] = gmdate("Y-m-d H:i", $row['itime']); $row['date_utc'] = gmdate("Y-m-d H:i", $row['itime']);
191 242 $row['old_rev_short'] = substr($row['old_rev'], 0, 7); $row['old_rev_short'] = substr($row['old_rev'], 0, 7);
192 243 $row['new_rev_short'] = substr($row['new_rev'], 0, 7); $row['new_rev_short'] = substr($row['new_rev'], 0, 7);
244
245 if (!isset($row['who_nice'])) {
246 if ($row['who'] == 0) {
247 $row['who_nice'] = 'anonymous';
248 } else {
249 $ui = rg_user_info($db, $row['who'], '', '');
250 if ($ui['exists'] == 1)
251 $row['who_nice'] = $ui['username'];
252 else
253 $row['who_nice'] = 'n/a';
254 }
255 }
256 $row['done_nice'] = gmdate("Y-m-d H:i", $row['done']);
193 257 } }
194 258
195 259 /* /*
196 260 * Loads merge requests * Loads merge requests
261 * @type - 'pending' or 'closed'
197 262 * @limit = 0 => no limit * @limit = 0 => no limit
198 263 */ */
199 function rg_mr_load($db, $repo_id, $limit)
264 function rg_mr_load($db, $repo_id, $type, $limit)
200 265 { {
201 rg_log("mr_load: repo_id=$repo_id limit=$limit");
266 rg_log("mr_load: repo_id=$repo_id type=$type limit=$limit");
267
268 if (strcmp($type, 'pending') == 0)
269 $add = ' AND done = 0';
270 else
271 $add = ' AND done > 1000'; // first values are for different status
202 272
203 $params = array("repo_id" => $repo_id);
204 $sql = "SELECT * FROM merge_requests"
205 . " WHERE repo_id = @@repo_id@@"
206 . " AND done = 0"
207 . " ORDER BY itime";
273 $params = array('repo_id' => $repo_id);
274 $sql = 'SELECT * FROM merge_requests'
275 . ' WHERE repo_id = @@repo_id@@'
276 . $add
277 . ' ORDER BY itime';
208 278 if ($limit > 0) if ($limit > 0)
209 $sql .= " LIMIT " . $limit;
279 $sql .= ' LIMIT ' . $limit;
210 280 $res = rg_sql_query_params($db, $sql, $params); $res = rg_sql_query_params($db, $sql, $params);
211 281 if ($res === FALSE) { if ($res === FALSE) {
212 282 rg_mr_set_error("Cannot load merge requests (" . rg_sql_error() . ")"); rg_mr_set_error("Cannot load merge requests (" . rg_sql_error() . ")");
 
... ... function rg_mr_load($db, $repo_id, $limit)
215 285
216 286 $ret = array(); $ret = array();
217 287 while (($row = rg_sql_fetch_array($res))) { while (($row = rg_sql_fetch_array($res))) {
218 rg_mr_cosmetic($row);
288 rg_mr_cosmetic($db, $row);
219 289 $ret[] = $row; $ret[] = $row;
220 290 } }
221 291 rg_sql_free_result($res); rg_sql_free_result($res);
 
... ... function rg_mr_load_one($db, $repo_id, $id)
242 312 } }
243 313
244 314 $row = rg_sql_fetch_array($res); $row = rg_sql_fetch_array($res);
245 rg_mr_cosmetic($row);
315 rg_mr_cosmetic($db, $row);
246 316
247 317 rg_sql_free_result($res); rg_sql_free_result($res);
248 318
 
... ... function rg_mr_load_one($db, $repo_id, $id)
250 320 return $row; return $row;
251 321 } }
252 322
323 /*
324 * Sets the status ('done' filed of a merge request
325 * @status - 0 - not merged, > 10 = timestamp when the merge took place
326 */
327 function rg_mr_merge_set_status($db, $repo_id, $id, $status)
328 {
329 $ret = FALSE;
330 while (1) {
331 $params = array('repo_id' => $repo_id,
332 'id' => $id,
333 'status' => $status
334 );
335 $sql = 'UPDATE merge_requests'
336 . ' SET done = @@status@@'
337 . ' WHERE repo_id = @@repo_id@@'
338 . ' AND id = @@id@@';
339 $res = rg_sql_query_params($db, $sql, $params);
340 if ($res === FALSE) {
341 rg_mr_set_error('cannot update status (' . rg_sql_error());
342 break;
343 }
344 rg_sql_free_result($res);
345
346 $ret = TRUE;
347 break;
348 }
349
350 return $ret;
351 }
352
353 /*
354 * High level merge request function
355 */
356 function rg_mr_high_level($db, &$rg, $paras)
357 {
358 rg_prof_start('mr_high_level');
359 rg_log_enter('mr_high_level');
360
361 $ret = '';
362 while (1) {
363 if ($rg['ri']['git_dir_done'] == 0) {
364 $ret .= rg_template('repo/no_git_dir.html',
365 $rg, TRUE /*xss*/);
366 break;
367 }
368
369 // TODO: mrs.html is empty!
370 $ret .= rg_template('repo/mrs.html', $rg, TRUE /*xss*/);
371
372 $op = array_shift($paras);
373 if (empty($op)) {
374 $op = 'pending';
375 } else {
376 $mr = sprintf('%u', $op);
377 if ($mr > 0)
378 $op = '';
379 }
380
381 rg_log('DEBUG: op=' . $op);
382 $rg['menu']['mr'][$op] = 1;
383 $rg['HTML:menu_repo_level2'] =
384 rg_template('repo/mr/menu.html', $rg, TRUE /*xss*/);
385
386 if ((strcmp($op, 'pending') == 0) || (strcmp($op, 'closed') == 0)) {
387 $rg['mr']['op'] = $op;
388 $r = rg_mr_load($db, $rg['ri']['repo_id'], $op,
389 0 /*no limit*/);
390 if ($r === FALSE) {
391 $ret .= 'error getting merge request list ('
392 . rg_mr_error() . ')';
393 } else {
394 $ret .= rg_template_table('repo/mr/list', $r, $rg);
395 }
396 break;
397 } else if (strcmp($op, 'create') == 0) {
398 $ret .= rg_warning('not yet implemented');
399 break;
400 }
401
402 $mri = rg_mr_load_one($db, $rg['ri']['repo_id'], $mr);
403 if ($mri === FALSE) {
404 $ret .= 'error loading merge request'
405 . ' (' . rg_mr_error() . ')';
406 break;
407 }
408
409 $mri['merge_in_progress'] = 0;
410 $mri['already_merged'] = 0;
411 $against = rg_git_short($mri['refname']);
412
413 $mr_op = array_shift($paras);
414 rg_log('DEBUG: mr_op=' . $mr_op);
415 if (strcmp($mr_op, 'merge') == 0) {
416 if ($rg['can_admin'] !== 1) {
417 $ret .= rg_warning('Not allowed!');
418 break;
419 }
420
421 if (!rg_valid_referer()) {
422 $ret .= rg_warning('Invalid referer; try again.');
423 break;
424 }
425
426 if (!rg_token_valid($db, $rg, 'mr_merge', FALSE)) {
427 $ret .= rg_warning('Invalid token; try again.');
428 break;
429 }
430
431 $event = array(
432 'category' => 'mr_merge',
433 'prio' => 30,
434 'ri' => $rg['ri'],
435 'ui' => $rg['login_ui'],
436 'repo_path' => $rg['repo_path'],
437 'mri' => $mri,
438 'merge_against' => $against,
439 'merge_ff' => rg_var_uint('merge_ff'),
440 'merge_msg' => rg_var_str('merge_msg')
441 );
442 $r = rg_event_add($db, $event);
443 if ($r !== TRUE) {
444 $ret .= rg_warning('Cannot add event; try again later.');
445 break;
446 }
447 rg_event_signal_daemon('', 0);
448
449 $mri['merge_in_progress'] = 1;
450 $mri['HTML:body'] = rg_template(
451 'repo/mr/merge_in_progress.html',
452 $rg, TRUE /*xss*/);
453 } else {
454 $mri['HTML:body'] = '';
455
456 if ($mri['done'] > 10) { // already merged
457 $mri['merge_in_progress'] = 1;
458 $mri['already_merged'] = 1;
459 $mri['done_nice'] =
460 gmdate('Y-m-d H:i', $mri['done']) . ' UTC';
461 $mri['can_merge_without_conflicts'] = 0;
462 } else {
463 $r = rg_git_merge_without_conflict($rg['repo_path'],
464 $against, $mri['new_rev']);
465 if ($r === FALSE) {
466 $ret .= rg_warning('Error testing if merge will work'
467 . ' (' . rg_git_error() . ').');
468 break;
469 }
470 rg_log('DEBUG: cmwc=' . $r);
471 $mri['can_merge_without_conflicts'] = $r;
472
473 if ($mri['can_merge_without_conflicts'] == 0) {
474 $base = rg_git_merge_base($rg['repo_path'],
475 $against, $mri['new_rev']);
476 if ($base === FALSE) {
477 $ret .= rg_warning('Error: finding base: '
478 . rg_git_error() . '.');
479 break;
480 }
481
482 $mri['HTML:status'] = rg_git_merge_tree_html(
483 $rg['repo_path'], $base, $against,
484 $mri['new_rev']);
485 rg_log_ml('DEBUG: status: ' . print_r($mri['HTML:status'], TRUE));
486 $mri['HTML:body'] .= rg_template(
487 'repo/mr/conflicts.html', $mri, TRUE /*xss*/);
488 }
489 }
490
491 $_log = rg_git_log($rg['repo_path'], 0, $mri['old_rev'],
492 $mri['new_rev'], TRUE);
493 if ($_log === FALSE) {
494 $ret .= rg_warning('Error generating patch.');
495 break;
496 }
497
498 $mri['HTML:body'] .=
499 rg_git_log2listing($_log, $rg, TRUE);
500
501 if ($mri['can_merge_without_conflicts'] == 1)
502 $rg['rg_form_token'] = rg_token_get($db, $rg, 'mr_merge');
503 }
504
505 //rg_log_ml('DEBUG: mri: ' . print_r($mri, TRUE));
506 $rg['mr'] = $mri;
507
508 $hints = array();
509 $hints[]['HTML:hint'] = rg_template('hints/repo/merge.html',
510 $rg, TRUE /*xss*/);
511 $rg['mr']['HTML:hints'] = rg_template_table('hints/list',
512 $hints, $rg);
513
514 $ret .= rg_template('repo/mr/page.html', $rg,
515 TRUE/*xss*/);
516 break;
517 }
518
519 rg_log_exit();
520 rg_prof_end('mr_high_level');
521 return $ret;
522 }
523
253 524 ?> ?>
File inc/sql.inc.php changed (mode: 100644) (index 669fcd8..26f6685)
... ... function rg_sql_open_nodelay($h)
68 68
69 69 $_s = microtime(TRUE); $_s = microtime(TRUE);
70 70
71 $tries = 30;
72 while ($tries > 0) {
71 $tries = 0;
72 while (1) {
73 73 $db = @pg_pconnect($str); $db = @pg_pconnect($str);
74 if ($db === FALSE) {
75 rg_log("Cannot connect to db. Sleep 1 second and try again.");
76 sleep(1);
77 $tries--;
78 continue;
74 if ($db !== FALSE) {
75 $x = pg_ping($db);
76 if ($x === TRUE)
77 break;
78 }
79
80 if ($tries == 0)
81 rg_log('Cannot connect to db. Keep trying...');
82
83 $tries++;
84 if ($tries > 30) {
85 $db = FALSE;
86 break;
79 87 } }
80 break;
81 88 } }
82 $diff = sprintf("%u", (microtime(TRUE) - $_s) * 1000);
89 $diff = intval((microtime(TRUE) - $_s) * 1000);
83 90 rg_prof_set(array("db_c_ms" => $diff)); rg_prof_set(array("db_c_ms" => $diff));
84 91 if ($db === FALSE) { if ($db === FALSE) {
85 92 rg_sql_set_error('cannot connect to database'); rg_sql_set_error('cannot connect to database');
 
... ... function rg_sql_open_nodelay($h)
87 94 break; break;
88 95 } }
89 96
90 rg_log("Connect OK to database.");
91 97 $rg_sql_conn[$h]['db'] = $db; $rg_sql_conn[$h]['db'] = $db;
92 98 $ret = $db; $ret = $db;
93 99 break; break;
File inc/struct.inc.php changed (mode: 100644) (index f2f4470..cd313f7)
... ... $rg_sql_struct[38]['other'] = array(
521 521 'repo - pr id' => 'repo - pr id' =>
522 522 "ALTER TABLE repos ADD last_mr_id INT NOT NULL DEFAULT 0", "ALTER TABLE repos ADD last_mr_id INT NOT NULL DEFAULT 0",
523 523 'merge_requests - id' => 'merge_requests - id' =>
524 "ALTER TABLE merge_requests ADD id INT NOT NULL DEFAULT 0"
524 "ALTER TABLE merge_requests ADD id INT NOT NULL DEFAULT 0",
525 'merge_requests - who' =>
526 "ALTER TABLE merge_requests ADD who INT NOT NULL DEFAULT 0"
525 527 ); );
526 528
527 529
File inc/user/repo-page.php changed (mode: 100644) (index 6a37182..9e191ae)
... ... $rg['ssh'] = rg_re_repo_ssh($organization, $user, $repo);
64 64 $rg['git'] = rg_re_repo_git($organization, $user, $repo); $rg['git'] = rg_re_repo_git($organization, $user, $repo);
65 65 $rg['can_admin'] = $can_admin; $rg['can_admin'] = $can_admin;
66 66 $rg['HTML:hints'] = ''; $rg['HTML:hints'] = '';
67 $rg['mr'] = array('id' => '');
67 68
68 $repo_path = rg_repo_path_by_id($rg['ri']['uid'], $rg['ri']['repo_id']);
69 rg_log("repo_path=$repo_path");
70 putenv("GIT_DIR=$repo_path"); // TODO: this will be removed after all functios will got a path para
69 $rg['repo_path'] = rg_repo_path_by_id($rg['ri']['uid'], $rg['ri']['repo_id']);
70 rg_log('repo_path=' . $rg['repo_path']);
71 putenv('GIT_DIR=' . $rg['repo_path']); // TODO: this will be removed after all functios will got a path para
71 72
72 73 $rg['HTML:menu_repo_level2'] = ''; $rg['HTML:menu_repo_level2'] = '';
73 74 $rg['HTML:branches_and_tags'] = ''; $rg['HTML:branches_and_tags'] = '';
 
... ... if (strcmp($_subop, "history") == 0) {
141 142 $ref = $type_ref['ref_path']; $ref = $type_ref['ref_path'];
142 143 $rg = array_merge($rg, $type_ref); $rg = array_merge($rg, $type_ref);
143 144
144 $bt = rg_git_branches_and_tags($repo_path, $rg['ri']['url_repo'],
145 $bt = rg_git_branches_and_tags($rg['repo_path'], $rg['ri']['url_repo'],
145 146 $type_ref['ref_url']); $type_ref['ref_url']);
146 147 $rg = array_merge($rg, $bt); $rg = array_merge($rg, $bt);
147 148
 
... ... if (strcmp($_subop, "history") == 0) {
159 160 // find hash of blob // find hash of blob
160 161 $_path = implode("/", $paras); $_path = implode("/", $paras);
161 162 $rg['path'] = "/" . $_path; $rg['path'] = "/" . $_path;
162 $_tree = rg_git_ls_tree($repo_path, $ref, $_path);
163 $_tree = rg_git_ls_tree($rg['repo_path'], $ref, $_path);
163 164 if ($_tree === FALSE) { if ($_tree === FALSE) {
164 165 $_repo_body .= rg_warning('Error: ' . rg_git_error()); $_repo_body .= rg_warning('Error: ' . rg_git_error());
165 166 } else { } else {
 
... ... if (strcmp($_subop, "history") == 0) {
179 180 // find treeish of dir // find treeish of dir
180 181 $_path = implode("/", $paras); $_path = implode("/", $paras);
181 182 $rg['path'] = "/" . $_path; $rg['path'] = "/" . $_path;
182 $_tree = rg_git_ls_tree($repo_path, $ref, $_path);
183 $_tree = rg_git_ls_tree($rg['repo_path'], $ref, $_path);
183 184 if ($_tree === FALSE) { if ($_tree === FALSE) {
184 185 $_repo_body .= rg_warning('Error: ' . rg_git_error()); $_repo_body .= rg_warning('Error: ' . rg_git_error());
185 186 } else { } else {
186 187 $_hash = $_tree[0]['ref']; $_hash = $_tree[0]['ref'];
187 $_tree = rg_git_ls_tree($repo_path, $_hash, "");
188 $_tree = rg_git_ls_tree($rg['repo_path'],
189 $_hash, '');
188 190 if ($_tree === FALSE) if ($_tree === FALSE)
189 191 $_repo_body .= rg_warning('Error: ' . rg_git_error()); $_repo_body .= rg_warning('Error: ' . rg_git_error());
190 192 else else
 
... ... if (strcmp($_subop, "history") == 0) {
193 195 } }
194 196 } else { // default is to show root tree } else { // default is to show root tree
195 197 $rg['path'] = ""; $rg['path'] = "";
196 $_tree = rg_git_ls_tree($repo_path, $ref, "");
198 $_tree = rg_git_ls_tree($rg['repo_path'], $ref, '');
197 199 if ($_tree === FALSE) if ($_tree === FALSE)
198 200 $_repo_body .= rg_warning('Error: ' . rg_git_error()); $_repo_body .= rg_warning('Error: ' . rg_git_error());
199 201 else else
 
... ... if (strcmp($_subop, "history") == 0) {
202 204 } }
203 205 } else { // show the log } else { // show the log
204 206 // TODO: improve the error report (error or empty?) // TODO: improve the error report (error or empty?)
205 $log = rg_git_log($repo_path, 10, "", $ref, FALSE);
207 $log = rg_git_log($rg['repo_path'], 10, '', $ref, FALSE);
206 208 if ($log === FALSE) { if ($log === FALSE) {
207 209 $_repo_body .= rg_template("repo/not_init.html", $rg, $_repo_body .= rg_template("repo/not_init.html", $rg,
208 210 TRUE /*xss*/); TRUE /*xss*/);
 
... ... if (strcmp($_subop, "history") == 0) {
236 238 $second = $commit; $second = $commit;
237 239 } }
238 240
239 $log = rg_git_log($repo_path, 1, $first, $second, TRUE);
241 $log = rg_git_log($rg['repo_path'], 1, $first, $second,
242 TRUE);
240 243 $_repo_body .= rg_git_log2listing($log, $rg, FALSE); $_repo_body .= rg_git_log2listing($log, $rg, FALSE);
241 244 } }
242 245 } }
 
... ... if (strcmp($_subop, "history") == 0) {
246 249 } else if (strcmp($_subop, "stats") == 0) { } else if (strcmp($_subop, "stats") == 0) {
247 250 $_repo_body .= rg_repo_stats($rg); $_repo_body .= rg_repo_stats($rg);
248 251 } else if (strcmp($_subop, "mr") == 0) { } else if (strcmp($_subop, "mr") == 0) {
249 if ($rg['ri']['git_dir_done'] == 0) {
250 $_repo_body .= rg_template("repo/no_git_dir.html",
251 $rg, TRUE /*xss*/);
252 } else {
253 $_repo_body .= rg_template("repo/mrs.html", $rg, TRUE /*xss*/);
254
255 while (1) {
256 if (empty($paras)) {
257 $r = rg_mr_load($db, $rg['ri']['repo_id'], 0 /*no limit*/);
258 if ($r === FALSE) {
259 $_repo_body .= "Error getting merge request list ("
260 . rg_mr_error() . ").";
261 } else {
262 $_repo_body .= rg_template_table("repo/mr/list",
263 $r, $rg);
264 }
265 break;
266 }
267
268 $mr = sprintf('%u', array_shift($paras));
269 $rg['mr'] = $mr;
270 $mri = rg_mr_load_one($db, $rg['ri']['repo_id'], $mr);
271 if ($mri === FALSE) {
272 $_repo_body .= "Error getting merge request"
273 . " (" . rg_mr_error() . ").";
274 break;
275 }
276
277 $_log = rg_git_log($repo_path, 0, $mri['old_rev'],
278 $mri['new_rev'], TRUE);
279 if ($_log === FALSE) {
280 $_repo_body .= rg_warning("Error generating patch.");
281 break;
282 }
283
284 $mri['HTML:diff'] = rg_git_log2listing($_log, $rg, TRUE);
285 $_repo_body .= rg_template("repo/mr/page.html", $mri,
286 TRUE /*xss*/);
287 break;
288 }
289
290 $hints = array();
291 $hints[]['HTML:hint'] = rg_template("hints/repo/merge.html",
292 $rg, TRUE /*xss*/);
293 $rg['HTML:hints'] = rg_template_table("hints/list",
294 $hints, $rg);
295 }
252 $_repo_body .= rg_mr_high_level($db, $rg, $paras);
296 253 } }
297 254
298 255 rg_watch_hl_process($db, $rg, 'repo', $rg['ri']['repo_id'], 0 /*obj_id2*/, rg_watch_hl_process($db, $rg, 'repo', $rg['ri']['repo_id'], 0 /*obj_id2*/,
File inc/user/repo/bug/main.php changed (mode: 100644) (index d203662..385aa4a)
... ... $rg['can_save'] = $rg['login_ui']['uid'] > 0 ? 1 : 0;
8 8 $_op = empty($paras) ? "list" : array_shift($paras); $_op = empty($paras) ? "list" : array_shift($paras);
9 9 $rg['menu']['sub2'][$_op] = 1; $rg['menu']['sub2'][$_op] = 1;
10 10
11 $rg['HTML:menu_repo_level2'] =
12 rg_template('repo/bug/menu.html', $rg, TRUE /*xss*/);
13
11 14 $rg['allow_bug_add'] = 0; $rg['allow_bug_add'] = 0;
12 15 $x = array(); $x = array();
13 16 $x['obj_id'] = $rg['ri']['repo_id']; $x['obj_id'] = $rg['ri']['repo_id'];
File inc/util.inc.php changed (mode: 100644) (index 6c288f7..eff4a4f)
... ... function rg_age($ts)
1573 1573 } }
1574 1574
1575 1575 /* /*
1576 * Creates a temporary file name and returns it
1576 * Returns the path into the temporary area
1577 1577 */ */
1578 function rg_tmp_file_name($file)
1578 function rg_tmp_path($file)
1579 1579 { {
1580 1580 global $rg_state_dir; global $rg_state_dir;
1581 1581
 
... ... function rg_tmp_file_name($file)
1583 1583 } }
1584 1584
1585 1585 /* /*
1586 * Creates a temporary file
1586 * Creates and stores content into a temporary file
1587 1587 */ */
1588 1588 function rg_tmp_file($file, $content) function rg_tmp_file($file, $content)
1589 1589 { {
File inc/wh/cloud.inc.php changed (mode: 100644) (index 8d98bfd..1f5712d)
... ... function rg_wh_cloud_send_one($db, $event)
28 28
29 29 $xid = rg_id(8); $xid = rg_id(8);
30 30 $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip'; $f = 'wh-' . $event['ui']['uid'] . '-' . $wh['id'] . '-' . $xid . '.zip';
31 $path = rg_tmp_file_name($f);
31 $path = rg_tmp_path($f);
32 32
33 33 $last_output = ''; $last_output = '';
34 34 while (1) { while (1) {
File root/index.php changed (mode: 100644) (index 1ce867d..74901ad)
... ... if (strcmp($proto, 'HTTP/1.1') == 0) {
182 182
183 183 rg_prof_end("MAIN"); rg_prof_end("MAIN");
184 184 rg_prof_log(); rg_prof_log();
185 rg_log("DONE!");
186 185 ?> ?>
File root/themes/default/hints/repo/git_setup.html changed (mode: 100644) (index 4124678..9e0c280)
1 1 <br /> <br />
2 2 Before first commit, do not forget to setup your git environment:<br /> Before first commit, do not forget to setup your git environment:<br />
3 3 <div class="xcode"> <div class="xcode">
4 git config --global user.name "your name here"<br />
4 git config --global user.name "your_name_here"<br />
5 5 git config --global user.email "your@email_here" git config --global user.email "your@email_here"
6 6 </div> </div>
File root/themes/default/hints/repo/merge.html changed (mode: 100644) (index d8374fc..60a6304)
2 2 How to merge on your machine?<br /> How to merge on your machine?<br />
3 3
4 4 <div class="xcode"> <div class="xcode">
5 git fetch origin refs/mr/@@mr@@:mr-@@mr@@<br />
5 git fetch origin refs/mr/@@if("@@mr::id@@" == ""){{ID}}{{@@mr::id@@}}:mr-@@if("@@mr::id@@" == ""){{ID}}{{@@mr::id@@}}<br />
6 6 git checkout master<br /> git checkout master<br />
7 git merge mr-@@mr@@<br />
7 git merge mr-@@if("@@mr::id@@" == ""){{ID}}{{@@mr::id@@}}<br />
8 8 </div> </div>
9 9 <br /> <br />
10 10
11 11 To "see" all the pull requests as branches,<br /> To "see" all the pull requests as branches,<br />
12 add, in config file (.git/config), under the remote you want, a line like this:<br />
12 add, in the config file (.git/config), under the remote you want,
13 a line like this:<br />
13 14 <div class="xcode"> <div class="xcode">
14 15 fetch = +refs/mr/*:refs/remotes/your_remote_name_for_example_origin/mr/*<br /> fetch = +refs/mr/*:refs/remotes/your_remote_name_for_example_origin/mr/*<br />
15 16 </div> </div>
 
... ... After you run a git fetch, you will have all the pull requests locally.<br />
17 18 For example, you can merge one of them:<br /> For example, you can merge one of them:<br />
18 19 <div class="xcode"> <div class="xcode">
19 20 git checkout master<br /> git checkout master<br />
20 git merge mr/@@mr@@
21 git merge mr/@@if("@@mr::id@@" == ""){{ID}}{{@@mr::id@@}}
21 22 </div> </div>
File root/themes/default/main.css changed (mode: 100644) (index f73e7b1..8957882)
4 4 } }
5 5
6 6 html { html {
7 height: 100%;
8 7 } }
9 8
10 9 body { body {
 
... ... body {
12 11 font-size: 11pt; font-size: 11pt;
13 12 line-height: 105%; line-height: 105%;
14 13 background-color: #CCCCCC; background-color: #CCCCCC;
15 height: 100%;
16 14 } }
17 15
18 16 table { table {
 
... ... a {
37 35 } }
38 36
39 37 .xcode { .xcode {
40 margin-left: 5px;
41 38 border-left: 4px solid #F00; border-left: 4px solid #F00;
42 39 font-size: 10pt; font-size: 10pt;
40 margin: 5px;
43 41 padding-left: 5px; padding-left: 5px;
44 42 font-family: monospace; font-family: monospace;
43 line-height: 120%;
45 44 } }
46 45
47 46 form { } form { }
 
... ... legend { padding: 0px 2pt; }
173 172
174 173
175 174 #container { #container {
176 height: 100%;
177 175 display: flex; display: flex;
178 176 flex-flow: column nowrap; flex-flow: column nowrap;
179 177 align-items: stretch; align-items: stretch;
 
... ... legend { padding: 0px 2pt; }
330 328
331 329 .repo_container { .repo_container {
332 330 text-align: left; text-align: left;
331 display: flex;
332 flex-flow: column nowrap;
333 333 } }
334 334
335 335 .repo_header { } .repo_header { }
 
... ... legend { padding: 0px 2pt; }
359 359 .urls ul { list-style-type: none; } .urls ul { list-style-type: none; }
360 360 .urls ul li { .urls ul li {
361 361 display: inline; display: inline;
362 border: 1px solid #cccccc;
362 border: 1px solid #aaa;
363 363 border-radius: 4px 4px 4px 4px; border-radius: 4px 4px 4px 4px;
364 364 font-size: 9pt; font-size: 9pt;
365 365 padding: 3px 3px; padding: 3px 3px;
 
... ... legend { padding: 0px 2pt; }
466 466 padding: 5px; padding: 5px;
467 467 box-shadow: 0px 2px 3px #666666; box-shadow: 0px 2px 3px #666666;
468 468 align-self: flex-start; align-self: flex-start;
469 border: 1px solid #000;
470 border-radius: 4px;
471 }
472 .mess:not(:first-child) {
473 margin-top: 4pt;
469 474 } }
470 475
471 476 .error { .error {
472 477 background-color: #F00; background-color: #F00;
473 border: 1px solid #000;
474 478 color: #000; color: #000;
475 479 } }
476 480
 
... ... legend { padding: 0px 2pt; }
482 486
483 487 .ok { .ok {
484 488 background-color: #8F8; background-color: #8F8;
485 border: 1px solid #FFF;
489 border: 1px solid #000;
486 490 color: #000; color: #000;
487 491 } }
488 492
 
... ... legend { padding: 0px 2pt; }
559 563 align-content: space-between; align-content: space-between;
560 564 align-items: stretch; align-items: stretch;
561 565 } }
566
567 .merge_info {
568 }
569
570 .merge_status {
571 padding: 2pt;
572 border: 1px solid #999;
573 border-radius: 4px 4px 4px 4px;
574 align-self: flex-start;
575 }
576 .merge_status_ok {
577 background-color: #bfb;
578 }
579 .merge_status_nok {
580 background-color: #fbb;
581 }
582
583 .table_log {
584 }
585 .table_log:not(:first-child) {
586 margin-top: 8pt;
587 }
588
589 .conflicts {
590 padding: 2pt;
591 border: 1px solid #999;
592 border-radius: 4px 4px 4px 4px;
593 align-self: flex-start;
594 background-color: #fbb;
595 }
File root/themes/default/repo/bug/main.html changed (mode: 100644) (index 8fc001f..8985894)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::sub2::list@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug">List</a></li>
4 @@if(@@allow_bug_add@@ == 1){{
5 <li@@if(@@menu::sub2::add@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/add">Add</a></li>
6 }}
7 <li@@if(@@menu::sub2::search@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/search">Search</a></li>
8 </ul>
9 </div>
10
11 1 @@bug_body@@ @@bug_body@@
File root/themes/default/repo/bug/menu.html copied from file root/themes/default/repo/bug/main.html (similarity 96%) (mode: 100644) (index 8fc001f..cd51239)
7 7 <li@@if(@@menu::sub2::search@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/search">Search</a></li> <li@@if(@@menu::sub2::search@@ == 1){{ class="selected"}}><a href="@@url_repo@@/bug/search">Search</a></li>
8 8 </ul> </ul>
9 9 </div> </div>
10
11 @@bug_body@@
File root/themes/default/repo/log/header.html changed (mode: 100644) (index df4d8e6..36ecddb)
1 <br />
2 <table summary="log">
1 <table class="table_log" summary="log">
3 2 <tr> <tr>
4 3 <th>Subject</th> <th>Subject</th>
5 4 <th>SHA-1</th> <th>SHA-1</th>
File root/themes/default/repo/log/line.html changed (mode: 100644) (index 0316e34..efcf769)
1 1 <tr> <tr>
2 2 <td>@@subject@@</td> <td>@@subject@@</td>
3 <td><a href="@@if("@@commit_url@@" != ""){{@@commit_url@@}}{{@@url_repo@@/source/log/commit/@@sha1_short@@}}">@@sha1_short@@</a></td>
3 <td><a href="@@if("@@commit_url@@" != ""){{@@commit_url@@}}{{@@url_repo@@/source/log/commit/@@sha1@@}}">@@sha1@@</a></td>
4 4 <td>@@author name@@</td> <td>@@author name@@</td>
5 5 <td>@@author date UTC@@</td> <td>@@author date UTC@@</td>
6 6 </tr> </tr>
File root/themes/default/repo/mail/merge_failed.body.txt added (mode: 100644) (index 0000000..75b1e0a)
1 Hello!
2
3 Repo: @@ri::name@@
4 Your merge failed.
5
6 --
7 RocketGit Team
8 http://rocketgit.com/
File root/themes/default/repo/mail/merge_failed.head.txt copied from file root/themes/default/mail/admin/report1.head.txt (similarity 100%)
File root/themes/default/repo/mail/merge_failed.subj.txt copied from file root/themes/default/mail/admin/report1.subj.txt (similarity 100%)
File root/themes/default/repo/mr/conflicts.html added (mode: 100644) (index 0000000..af52bc6)
1 <b>Conflicts:</b><br />
2 <div class="conflicts">
3 @@status@@
4 </div>
File root/themes/default/repo/mr/list/header.html changed (mode: 100644) (index 2212c42..eb1d462)
2 2 <tr> <tr>
3 3 <th>ID</th> <th>ID</th>
4 4 <th>Date / time</th> <th>Date / time</th>
5 <th>Ref</th>
5 <th>Who</th>
6 <th>Against ref</th>
6 7 <th>From</th> <th>From</th>
7 8 <th>To</th> <th>To</th>
8 @@if(@@can_admin@@ == 1){{<th>IP</th>}}{{}}
9 @@if("@@mr::op@@" == "closed"){{<th>Done</th>}}
10 @@if(@@can_admin@@ == 1){{<th>IP</th>}}
9 11 </tr> </tr>
10 12
File root/themes/default/repo/mr/list/line.html changed (mode: 100644) (index 4838c88..e90bab4)
1 1 <tr> <tr>
2 2 <td><a href="@@url_repo@@/mr/@@id@@">@@id@@</a></td> <td><a href="@@url_repo@@/mr/@@id@@">@@id@@</a></td>
3 3 <td>@@date_utc@@</td> <td>@@date_utc@@</td>
4 <td>@@who_nice@@</td>
4 5 <td>@@refname@@</td> <td>@@refname@@</td>
5 <td>@@old_rev_short@@</td>
6 <td>@@new_rev_short@@</td>
7 @@if(@@can_admin@@ == 1){{<td>@@ip@@</td>}}{{}}
6 <td>@@old_rev@@</td>
7 <td>@@new_rev@@</td>
8 @@if("@@mr::op@@" == "closed"){{<td>@@done_nice@@</td>}}
9 @@if(@@can_admin@@ == 1){{<td>@@ip@@</td>}}
8 10 </tr> </tr>
File root/themes/default/repo/mr/menu.html added (mode: 100644) (index 0000000..1bc0aa3)
1 <div class="menu menu3">
2 <ul>
3 <li@@if(@@menu::mr::pending@@ == 1){{ class="selected"}}><a href="@@url_repo@@/mr/pending">Pending</a></li>
4 <li@@if(@@menu::mr::closed@@ == 1){{ class="selected"}}><a href="@@url_repo@@/mr/closed">Closed</a></li>
5 <li@@if(@@menu::mr::create@@ == 1){{ class="selected"}}><a href="@@url_repo@@/mr/create">Create</a></li>
6 </ul>
7 </div>
File root/themes/default/repo/mr/merge_in_progress.html added (mode: 100644) (index 0000000..844b7c0)
1 <div class="mess ok">
2 Your merge was queued with success.
3 </div>
File root/themes/default/repo/mr/page.html changed (mode: 100644) (index 43c3495..df3a7ff)
1 <div>
2 Pull request <b>@@id@@</b> (@@old_rev_short@@ -> @@new_rev_short@@)<br />
3 <b>Ref</b>: @@refname@@<br />
4 <b>Date</b>: @@date_utc@@<br />
5 @@if(@@can_admin@@ == 1){{<b>IP</b>: @@ip@@<br />}}{{}}
1 <div class="merge_info">
2 Pull request <b>@@mr::id@@</b> (@@mr::old_rev@@ -> @@mr::new_rev@@)<br />
3 <b>By</b>: @@mr::who_nice@@<br />
4 <b>Against ref</b>: @@mr::refname@@<br />
5 <b>Date</b>: @@mr::date_utc@@<br />
6 @@if(@@can_admin@@ == 1){{<b>From IP</b>: @@mr::ip@@<br />}}
6 7 </div> </div>
7 8
8 @@diff@@
9 @@if(@@mr::merge_in_progress@@ == 1){{
10 @@if(@@mr::already_merged@@ == 1){{
11 <div class="merge_status merge_status_ok">
12 Already merged at @mr::done_nice@@.
13 </div>
14 }}
15 }}{{
16 @@if(@@mr::can_merge_without_conflicts@@ == 1){{
17 <div class="formarea merge_status merge_status_ok">
18 This pull request can be merged without conflicts.
19 @@if(@@can_admin@@ == 1){{
20 <form method="post" action="@@url_repo@@/mr/@@mr::id@@/merge">
21 <input type="hidden" name="token" value="@@rg_form_token@@" />
22
23 <p>
24 <label for="merge_ff">Allow fast-forward?</label>
25 <select name="merge_ff" id="merge_ff">
26 <option value="0">No</option>
27 <option value="1">Yes</option>
28 </select>
29 </p>
30
31 <p>
32 <label for="merge_msg">Merge message</label><br />
33 <textarea name="merge_msg" id="merge_msg" rows="4" cols="80">Merge pull request @@mr::id@@ into @@mr::refname@@.</textarea>
34 </p>
35
36 <input type="submit" name="button" value="Merge" />
37 </form>
38 }}
39 </div>
40 }}{{
41 <div class="merge_status merge_status_nok">
42 This pull request cannot be merged without conflicts.<br />
43 </div>
44 }}
45 }}
46
47 @@mr::body@@
48
49 @@mr::hints@@
File root/themes/default/repo/mr/req-pull.txt added (mode: 100644) (index 0000000..718c14a)
1 The following changes since commit @@start@@
2
3 @@%ci@@ (@@date_local@@)
4
5 are available in the git repository at:
6
7 @@url@@
8
9 for you to fetch changes up to @@end@@
10
11 @@%ci@@ (@@date_local@@)
12
13 ----------------------------------------------------------------
14
File root/themes/default/user/keys/add.html changed (mode: 100644) (index 0907d92..fdb1f99)
9 9 <input type="hidden" name="token" value="@@rg_form_token@@" /> <input type="hidden" name="token" value="@@rg_form_token@@" />
10 10
11 11 <p> <p>
12 <label for="key">Key string (starts with ssh- or with ecdsa-)</label><br />
12 <label for="key">Key string (starts with ssh- or with ecdsa-; do not worry about line wraps)</label><br />
13 13 <textarea name="key" id="key" rows="6" cols="80">@@key@@</textarea> <textarea name="key" id="key" rows="6" cols="80">@@key@@</textarea>
14 14 </p> </p>
15 15
File root/themes/default/user/settings/wh/http/show.html changed (mode: 100644) (index fe3ca4d..61e50da)
5 5 </tr> </tr>
6 6
7 7 <tr> <tr>
8 <td>Client cert</td>
9 <td>@@client_cert_short@@</td>
8 <td>Custom body</td>
9 <td>@@custom_body_nlbr@@</td>
10 10 </tr> </tr>
11 11
12 12 <tr> <tr>
13 <td>Custom body</td>
14 <td>@@custom_body_nlbr@@</td>
13 <td>Client cert</td>
14 <td>@@client_cert_short@@</td>
15 15 </tr> </tr>
16 16
17 17 <tr> <tr>
File tests/.gitignore changed (mode: 100644) (index 2a1ed93..1e08974)
... ... ca
22 22 pr_anon.git pr_anon.git
23 23 *.tmp *.tmp
24 24 wh_cloud.git wh_cloud.git
25 git_log1.final
File tests/Makefile changed (mode: 100644) (index a23a63f..ea75a33)
... ... git2:
104 104 clean: clean:
105 105 @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \ @rm -rf git_log1 *.log *.strace *.strace.* *.out *.lock err-* *.diff \
106 106 http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \ http.arond *.pub git2key git2 *.in q_merge_requests/mr-* \
107 qstats/* repos/* helper helper.pub keys/* ca *.pid pr_anon.git \
108 *.tmp base ubase wh_cloud.git
107 qstats/* repos/* helper helper.pub keys/* ca *.pid \
108 _pr_anon.git *.tmp base ubase wh_cloud.git
File tests/git_log1.expected changed (mode: 100644) (index 40a55f2..8c237d9)
1 1 <div class="diff"> <div class="diff">
2 2 <br /> <br />
3 <a name="file-dis1"></a>
3 <a name="file-uniq-id-dis1"></a>
4 4 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
5 5 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> changed (mode: 100644) (index 2c4179b..2bf9115):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> changed (mode: 100644) (index 2c4179b..2bf9115):</td></tr>
6 6 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e
 
10 10 </div> </div>
11 11 <div class="diff"> <div class="diff">
12 12 <br /> <br />
13 <a name="file-dis1"></a>
13 <a name="file-uniq-id-dis1"></a>
14 14 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
15 15 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> added (mode: 100644) (index 0000000..2c4179b):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> added (mode: 100644) (index 0000000..2c4179b):</td></tr>
16 16 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 
19 19 </div> </div>
20 20 <div class="diff"> <div class="diff">
21 21 <br /> <br />
22 <a name="file-a b c"></a>
22 <a name="file-uniq-id-a b c"></a>
23 23 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
24 24 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a b c</b> added (mode: 100644) (index 0000000..72943a1):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a b c</b> added (mode: 100644) (index 0000000..72943a1):</td></tr>
25 25 1 cl-e cl-g aaa 1 cl-e cl-g aaa
 
27 27 </div> </div>
28 28 <div class="diff"> <div class="diff">
29 29 <br /> <br />
30 <a name="file-a3"></a>
30 <a name="file-uniq-id-a3"></a>
31 31 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
32 32 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> deleted (index 193814c..0000000):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> deleted (index 193814c..0000000):</td></tr>
33 33 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e
 
35 35 </div> </div>
36 36 <div class="diff"> <div class="diff">
37 37 <br /> <br />
38 <a name="file-a3"></a>
38 <a name="file-uniq-id-a3"></a>
39 39 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
40 40 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> renamed from a2 (similarity 100%):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> renamed from a2 (similarity 100%):</td></tr>
41 41 </table> </table>
42 42 <br /> <br />
43 <a name="file-c"></a>
43 <a name="file-uniq-id-c"></a>
44 44 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
45 45 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>c</b> added (mode: 100644) (index 0000000..8ded189):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>c</b> added (mode: 100644) (index 0000000..8ded189):</td></tr>
46 46 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaa 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaa
 
48 48 </div> </div>
49 49 <div class="diff"> <div class="diff">
50 50 <br /> <br />
51 <a name="file-a2"></a>
51 <a name="file-uniq-id-a2"></a>
52 52 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
53 53 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a2</b> added (mode: 100644) (index 0000000..193814c):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a2</b> added (mode: 100644) (index 0000000..193814c):</td></tr>
54 54 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 
56 56 </div> </div>
57 57 <div class="diff"> <div class="diff">
58 58 <br /> <br />
59 <a name="file-empty.txt"></a>
59 <a name="file-uniq-id-empty.txt"></a>
60 60 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
61 61 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>empty.txt</b> added (mode: 100644) (index 0000000..e69de29):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>empty.txt</b> added (mode: 100644) (index 0000000..e69de29):</td></tr>
62 62 </table> </table>
63 63 </div> </div>
64 64 <div class="diff"> <div class="diff">
65 65 <br /> <br />
66 <a name="file-xx&quot;yy"></a>
66 <a name="file-uniq-id-xx&quot;yy"></a>
67 67 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
68 68 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>xx&quot;yy</b> added (mode: 100644) (index 0000000..e69de29):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>xx&quot;yy</b> added (mode: 100644) (index 0000000..e69de29):</td></tr>
69 69 </table> </table>
70 70 </div> </div>
71 71 <div class="diff"> <div class="diff">
72 72 <br /> <br />
73 <a name="file-a"></a>
73 <a name="file-uniq-id-a"></a>
74 74 <table class="chunk" summary="chunk"> <table class="chunk" summary="chunk">
75 75 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a</b> added (mode: 100644) (index 0000000..193814c):</td></tr> <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a</b> added (mode: 100644) (index 0000000..193814c):</td></tr>
76 76 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
File tests/git_log1.final deleted (index 40a55f2..0000000)
1 <div class="diff">
2 <br />
3 <a name="file-dis1"></a>
4 <table class="chunk" summary="chunk">
5 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> changed (mode: 100644) (index 2c4179b..2bf9115):</td></tr>
6 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e
7 2 1 cl-e baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
8 2 cl-e cl-g caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
9 </table>
10 </div>
11 <div class="diff">
12 <br />
13 <a name="file-dis1"></a>
14 <table class="chunk" summary="chunk">
15 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>dis1</b> added (mode: 100644) (index 0000000..2c4179b):</td></tr>
16 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
17 2 cl-e cl-g baaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
18 </table>
19 </div>
20 <div class="diff">
21 <br />
22 <a name="file-a b c"></a>
23 <table class="chunk" summary="chunk">
24 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a b c</b> added (mode: 100644) (index 0000000..72943a1):</td></tr>
25 1 cl-e cl-g aaa
26 </table>
27 </div>
28 <div class="diff">
29 <br />
30 <a name="file-a3"></a>
31 <table class="chunk" summary="chunk">
32 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> deleted (index 193814c..0000000):</td></tr>
33 1 cl-r aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa cl-e
34 </table>
35 </div>
36 <div class="diff">
37 <br />
38 <a name="file-a3"></a>
39 <table class="chunk" summary="chunk">
40 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a3</b> renamed from a2 (similarity 100%):</td></tr>
41 </table>
42 <br />
43 <a name="file-c"></a>
44 <table class="chunk" summary="chunk">
45 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>c</b> added (mode: 100644) (index 0000000..8ded189):</td></tr>
46 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaa
47 </table>
48 </div>
49 <div class="diff">
50 <br />
51 <a name="file-a2"></a>
52 <table class="chunk" summary="chunk">
53 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a2</b> added (mode: 100644) (index 0000000..193814c):</td></tr>
54 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
55 </table>
56 </div>
57 <div class="diff">
58 <br />
59 <a name="file-empty.txt"></a>
60 <table class="chunk" summary="chunk">
61 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>empty.txt</b> added (mode: 100644) (index 0000000..e69de29):</td></tr>
62 </table>
63 </div>
64 <div class="diff">
65 <br />
66 <a name="file-xx&quot;yy"></a>
67 <table class="chunk" summary="chunk">
68 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>xx&quot;yy</b> added (mode: 100644) (index 0000000..e69de29):</td></tr>
69 </table>
70 </div>
71 <div class="diff">
72 <br />
73 <a name="file-a"></a>
74 <table class="chunk" summary="chunk">
75 <tr style="border: 1px; background: #dddddd"><td colspan="4">File <b>a</b> added (mode: 100644) (index 0000000..193814c):</td></tr>
76 1 cl-e cl-g aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
77 </table>
78 </div>
File tests/git_log1.php changed (mode: 100644) (index 38b19fe..4e19e73)
... ... file_put_contents(dirname(__FILE__) . "/git_log1.out", print_r($r, TRUE));
29 29
30 30 $final = ''; $final = '';
31 31 foreach ($r as $commit_index => $commit_info) { foreach ($r as $commit_index => $commit_info) {
32 $a = rg_git_diff($commit_info['files'], dirname(__FILE__) . "/git_log1.tmpl");
32 $a = rg_git_diff('uniq-id', $commit_info['files'],
33 dirname(__FILE__) . "/git_log1.tmpl");
33 34 if ($a === FALSE) { if ($a === FALSE) {
34 35 rg_log("Cannot call rg_git_diff for commit_index $commit_index" rg_log("Cannot call rg_git_diff for commit_index $commit_index"
35 36 . " (" . rg_git_error() . ")!"); . " (" . rg_git_error() . ")!");
File tests/helpers.inc.php changed (mode: 100644) (index 868ee47..564560b)
... ... function rg_test_upload_ssh_key($db, $rg_ui, $key_name, $good_sid)
185 185 { {
186 186 global $test_url; global $test_url;
187 187
188 // we must regenerate the key because else we will not be the correct user
188 189 rg_log("Generating a SSH key [$key_name]"); rg_log("Generating a SSH key [$key_name]");
189 @unlink("keys/" . $key_name); @unlink("keys/" . $key_name . ".pub");
190 if (file_exists('keys/' . $key_name))
191 unlink('keys/' . $key_name);
192 if (file_exists('keys/' . $key_name . '.pub'))
193 unlink('keys/' . $key_name . '.pub');
190 194 $out = shell_exec("ssh-keygen -t rsa -N '' -C \"Key for RocketGit\"" $out = shell_exec("ssh-keygen -t rsa -N '' -C \"Key for RocketGit\""
191 . " -f keys/" . $key_name . " </dev/null");
195 . " -f keys/" . escapeshellarg($key_name) . " </dev/null");
192 196 if (!file_exists("keys/" . $key_name . ".pub")) { if (!file_exists("keys/" . $key_name . ".pub")) {
193 197 rg_log("Could not generate ssh key: " . $out); rg_log("Could not generate ssh key: " . $out);
194 198 exit(1); exit(1);
 
... ... function rg_test_wh_add_edit($db, $rg_ui, $good_sid, $htype, $extra)
324 328 } }
325 329 } }
326 330
331 /*
332 * Check if a pull request hit the database
333 * Returns the row or exits
334 */
335 function rg_test_mr_in_db($db, $repo_id)
336 {
337 rg_log_enter('Check if the pull request is in database...');
338 $tries = 10;
339 while ($tries > 0) {
340 $sql = 'SELECT * FROM merge_requests'
341 . ' WHERE repo_id = ' . $repo_id
342 . ' AND done = 0';
343 $res = rg_sql_query($db, $sql);
344 $rows = rg_sql_num_rows($res);
345 if ($rows > 0)
346 $row = rg_sql_fetch_array($res);
347 rg_sql_free_result($res);
348 if ($rows > 0)
349 break;
350
351 sleep(1);
352 $tries--;
353 }
354 if ($rows == 0) {
355 rg_log('Seems the pull request did not hit the database!');
356 exit(1);
357 }
358
359 rg_log_exit();
360 return $row;
361 }
362
327 363 ?> ?>
File tests/http.inc.php changed (mode: 100644) (index 9fa5465..625186d)
... ... function do_req($url, &$data, &$headers)
98 98 // Check if a '@@' is present // Check if a '@@' is present
99 99 if (strstr($ret['body'], '@@')) { if (strstr($ret['body'], '@@')) {
100 100 $t = explode('@@', $ret['body']); $t = explode('@@', $ret['body']);
101 $t = explode("\n", $t[1]);
102 rg_log_ml("We have unresolved variables: [" . $t[0] . "]!");
103 exit(1);
101 $t = explode('@@', $t[1]);
102 if (!strstr($t[0], ' ')) {
103 rg_log_ml("We have unresolved variables: [" . $t[0] . "]!");
104 exit(1);
105 }
104 106 } }
105 107
106 108 // find sid // find sid
 
... ... function do_req($url, &$data, &$headers)
142 144 $ret['tokens']['logout'] = $t[0]; $ret['tokens']['logout'] = $t[0];
143 145 } }
144 146
145 $ret['totp_secret'] = FALSE;
146 147 $x = preg_match_all('/ class="secret_token">([A-Z0-9]*)</', $ret['body'], $matches); $x = preg_match_all('/ class="secret_token">([A-Z0-9]*)</', $ret['body'], $matches);
147 148 if (($x !== FALSE) && (isset($matches[1])) && isset($matches[1][0])) { if (($x !== FALSE) && (isset($matches[1])) && isset($matches[1][0])) {
148 149 $ret['totp_secret'] = $matches[1][0]; $ret['totp_secret'] = $matches[1][0];
File tests/http_totp.php changed (mode: 100644) (index fca104e..b69f3af)
... ... if ($r === FALSE) {
115 115 exit(1); exit(1);
116 116 } }
117 117 $good_token = $r['tokens']['user_totp_enroll']; $good_token = $r['tokens']['user_totp_enroll'];
118 $key = $r['totp_secret'];
118 $key = isset($r['totp_secret']) ? $r['totp_secret'] : FALSE;
119 119 if ($key === FALSE) { if ($key === FALSE) {
120 120 rg_log_ml('r: ' . print_r($r, TRUE)); rg_log_ml('r: ' . print_r($r, TRUE));
121 121 rg_log("Cannot find totp::secret!"); rg_log("Cannot find totp::secret!");
File tests/pr_anon.php changed (mode: 100644) (index 796444b..9ab4a67)
... ... $rg_event_socket = "/var/lib/rocketgit/sockets/event.sock";
25 25
26 26
27 27 rg_log(''); rg_log('');
28 rg_log("Creating user...");
28 rg_log_enter('Creating user...');
29 29 rg_test_create_user($db, $rg_ui); rg_test_create_user($db, $rg_ui);
30 rg_log_exit();
30 31
31 32
32 33 rg_log(''); rg_log('');
33 rg_log('Creating a repo');
34 rg_log_enter('Login...');
35 $r = test_login($test_url, $rg_ui, $good_sid);
36 if ($r === FALSE) {
37 rg_log("Cannot login!");
38 exit(1);
39 }
40 rg_log_exit();
41
42
43 rg_log('');
44 rg_log_enter('Creating and upload a ssh key...');
45 rg_test_upload_ssh_key($db, $rg_ui, 'pr_anon', $good_sid);
46 rg_log_exit();
47
48
49 rg_log('');
50 rg_log_enter('Creating a repo');
34 51 $repo = array('repo_id' => 0, 'public' => 1); $repo = array('repo_id' => 0, 'public' => 1);
35 52 rg_test_create_repo($db, $rg_ui, $repo); rg_test_create_repo($db, $rg_ui, $repo);
53 rg_log_exit();
54
36 55
56 $url = '/user/' . $rg_ui['username'] . '/' . $repo['name'] . '/mr/';
37 57
58
59 // TODO: still needed?! Now, we have it by default.
60 if (0) {
38 61 rg_log(''); rg_log('');
39 rg_log("Giving anon push rights to any user");
62 rg_log_enter("Giving anon push rights to any user");
40 63 $x = array(); $x = array();
41 64 $x['right_id'] = 0; $x['right_id'] = 0;
42 65 $x['who'] = $rg_ui['uid']; $x['who'] = $rg_ui['uid'];
 
... ... if ($r !== TRUE) {
52 75 rg_log("We cannot give rights to the user"); rg_log("We cannot give rights to the user");
53 76 exit(1); exit(1);
54 77 } }
78 rg_log_exit();
79 }
55 80
56 81
57 82 rg_log(''); rg_log('');
58 rg_log('Do an anonymous push...');
59 system('rm -rf pr_anon.git');
60 system('git init pr_anon.git');
61 system('cd pr_anon.git; echo "change1" > a');
62 system('cd pr_anon.git; git add a; git commit -m "change1 desc"');
63 system('cd pr_anon.git; echo "change2" > a; git commit -a -m "change2 desc"');
64 //system('cd pr_anon.git; git remote add origin '
65 // . ' ssh://rocketgit@' . $rg_ssh_host . ':' . $rg_ssh_port
66 // . '/user/' . escapeshellarg($rg_ui['username']) . '/'
67 // . escapeshellarg($repo['name']));
68 system('cd pr_anon.git; git remote add origin '
83 rg_log_enter('Preparing repo...');
84 system('rm -rf _pr_anon.git');
85 system('git init _pr_anon.git');
86 system('cd _pr_anon.git; git remote add origin_ssh '
87 . ' ssh://rocketgit@' . $rg_ssh_host . ':' . $rg_ssh_port
88 . '/user/' . escapeshellarg($rg_ui['username']) . '/'
89 . escapeshellarg($repo['name']));
90 system('cd _pr_anon.git; git remote add origin_git '
69 91 . ' git://' . $rg_git_host . ':' . $rg_git_port . ' git://' . $rg_git_host . ':' . $rg_git_port
70 92 . '/user/' . escapeshellarg($rg_ui['username']) . '/' . '/user/' . escapeshellarg($rg_ui['username']) . '/'
71 93 . escapeshellarg($repo['name'])); . escapeshellarg($repo['name']));
72 system('cd pr_anon.git; git push origin master');
94 rg_log_exit();
73 95
74 96
75 97 rg_log(''); rg_log('');
76 rg_log('Check if the pull request has been done...');
77 $tries = 10;
78 while ($tries > 0) {
79 $sql = 'SELECT * FROM merge_requests WHERE repo_id = ' . $repo['repo_id'];
80 $res = rg_sql_query($db, $sql);
81 $rows = rg_sql_num_rows($res);
82 if ($rows > 0)
83 $row = rg_sql_fetch_array($res);
84 rg_sql_free_result($res);
85 if ($rows > 0)
86 break;
98 rg_log_enter('Do an non-anonymous push...');
99 system('export GIT_SSH_COMMAND="ssh -o IdentityFile=../keys/pr_anon";'
100 . 'cd _pr_anon.git; echo "change1" > a;'
101 . 'git add a; git commit -m "change1 desc";'
102 . 'echo "change2" > a; git commit -a -m "change2 desc";'
103 . 'git push origin_ssh master');
104 rg_log_exit();
87 105
88 sleep(1);
89 $tries--;
106
107 rg_log('');
108 rg_log_enter('Do an anonymous push...');
109 system('cd _pr_anon.git; echo "change3" >> a;'
110 . 'git add a; git commit -m "anon change1 desc";'
111 . 'echo "change4" >> a; git commit -a -m "anon change2 desc";'
112 . 'git push origin_git master');
113 rg_log_exit();
114
115
116 rg_log('');
117 rg_log_enter('Check if merge is in db and is agains correct branch...');
118 $mri = rg_test_mr_in_db($db, $repo['repo_id']);
119 if (strcmp($mri['refname'], 'refs/heads/master') != 0) {
120 rg_log_ml('mri: ' . print_r($mri, TRUE));
121 rg_log('Seems the ref is not master: ' . $mri['refname'] . '!');
122 exit(1);
90 123 } }
91 if ($rows == 0) {
92 rg_log('Seems the pull request did not hit the database!');
124 rg_log_exit();
125
126
127 rg_log('');
128 rg_log_enter('Loading the merge requests page - just to see it appears there');
129 $data = array();
130 $headers = array("Cookie: sid=" . $good_sid);
131 $r = do_req($test_url . '/user/' . $rg_ui['username']
132 . '/' . $repo['name'] . '/mr?t=pr_anon', $data, $headers);
133 if (!strstr($r['body'], '>' . $mri['id'] . '<')) {
134 rg_log_ml('r: ' . print_r($r, TRUE));
135 rg_log('id link not found!');
93 136 exit(1); exit(1);
94 137 } }
95 $ns = $row['namespace'];
96 $ref = $row['refname'];
97 if (strcmp($ref, 'refs/heads/master') != 0) {
98 rg_log('Seems the ref is not master: ' . $ref . '!');
138 rg_log_exit();
139
140
141 rg_log('');
142 rg_log_enter('Loading the merge request specific page');
143 $data = array();
144 $headers = array("Cookie: sid=" . $good_sid);
145 $r = do_req($test_url . $url . $mri['id'] . '?t=pr_anon', $data, $headers);
146 if (!strstr($r['body'], 'This pull request can be merged without conflicts')) {
147 rg_log_ml('r: ' . print_r($r, TRUE));
148 rg_log('Pull request does not appear as mergeable');
99 149 exit(1); exit(1);
100 150 } }
151 rg_log_exit();
101 152
102 153
103 154 rg_log(''); rg_log('');
104 rg_log('Login, so we can load the merge request...');
105 $r = test_login($test_url, $rg_ui, $good_sid);
155 rg_log_enter('Merging pull request...');
156 $data = array('token' => $r['tokens']['mr_merge'],
157 'merge_ff' => 0, 'merge_msg' => 'This is the merge message <xss>');
158 $r = do_req($test_url . $url . $mri['id'] . '/merge', $data, $headers);
106 159 if ($r === FALSE) { if ($r === FALSE) {
107 rg_log("Cannot login!");
160 rg_log('Cannot post merge form');
108 161 exit(1); exit(1);
109 162 } }
163 $tries = 0;
164 while (1) {
165 $sql = 'SELECT * FROM merge_requests'
166 . ' WHERE repo_id = ' . $repo['repo_id']
167 . ' AND done > 0 AND id = ' . $mri['id'];
168 $res = rg_sql_query($db, $sql);
169 $rows = rg_sql_num_rows($res);
170 rg_sql_free_result($res);
171 if ($rows == 1)
172 break;
173
174 if ($tries == 10) {
175 rg_log('merge_request was not marked as done!');
176 exit(1);
177 }
178 $tries++;
179 sleep(1);
180 }
181 rg_log_exit();
110 182
111 183
112 184 rg_log(''); rg_log('');
113 rg_log('Loading the merge requests page - just to see it appears there');
185 rg_log_enter('Now, try to see what happens when a merge is with conflicts...');
186 system('cd _pr_anon.git;'
187 . 'git pull origin_git master;'
188 . 'echo "change2" > a;'
189 . 'git commit -a -m "conflict1b";'
190 . 'git push origin_git master');
191 system('export GIT_SSH_COMMAND="ssh -o IdentityFile=../keys/pr_anon";'
192 . 'cd _pr_anon.git;'
193 . 'git reset --hard HEAD^1;'
194 . ' echo "change1" > a;'
195 . 'git commit -a -m "conflict1a";'
196 . 'git push origin_ssh master');
197 $mri = rg_test_mr_in_db($db, $repo['repo_id']);
114 198 $data = array(); $data = array();
115 199 $headers = array("Cookie: sid=" . $good_sid); $headers = array("Cookie: sid=" . $good_sid);
116 $r = do_req($test_url . '/user/' . $rg_ui['username']
117 . '/' . $repo['name'] . '/mr?t=pr_anon', $data, $headers);
118 if (!strstr($r['body'], '>' . $ns . '<')) {
200 $r = do_req($test_url . $url . $mri['id'] . '?t=pr_anon', $data, $headers);
201 if (!strstr($r['body'], 'This pull request cannot be merged without conflicts')) {
119 202 rg_log_ml('r: ' . print_r($r, TRUE)); rg_log_ml('r: ' . print_r($r, TRUE));
120 rg_log('namespace link not found!');
203 rg_log('Pull request does not appear as non-mergeable');
121 204 exit(1); exit(1);
122 205 } }
206 rg_log_exit();
123 207
124 208
125 209 rg_log(''); rg_log('');
126 rg_log('Loading the merge request specific page');
210 rg_log_enter('Loading conflicts page...');
127 211 $data = array(); $data = array();
128 212 $headers = array("Cookie: sid=" . $good_sid); $headers = array("Cookie: sid=" . $good_sid);
129 $r = do_req($test_url . '/user/' . $rg_ui['username']
130 . '/' . $repo['name'] . '/mr/' . $ns . '?t=pr_anon', $data, $headers);
131 rg_log_ml('r: ' . print_r($r, TRUE));
132
213 $r = do_req($test_url . $url . $mri['id'] . '?t=pr_anon', $data, $headers);
214 if (!strstr($r['body'], 'Conflicts:')) {
215 rg_log_ml('r: ' . print_r($r, TRUE));
216 rg_log('Errors in conflicts page!');
217 exit(1);
218 }
219 rg_log_exit();
133 220
134 221 rg_log("OK!"); rg_log("OK!");
135 222 ?> ?>
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://rocketgit.com/user/catalinux/rocketgit

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/catalinux/rocketgit

Clone this repository using git:
git clone git://git.rocketgit.com/user/catalinux/rocketgit

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