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

Added back the repo stats

Author: Catalin(ux) M. BOIE
Author date (UTC): 2015-09-10 04:44
Committer: Catalin(ux) M. BOIE
Commit date (UTC): 2015-09-10 04:44
Tree: 73bcdb6e37aa869a027e5c9440588b9fd6d3465e
Parents: 0f13d65e13211a91ce077b4a09307e54e9113f38
File Lines added Lines deleted
TODO 31 46
inc/git.inc.php 58 29
inc/repo.inc.php 27 0
inc/user/repo-page.php 1 4
root/themes/default/repo/main.html 2 0
root/themes/default/repo/stats.html 0 1
root/themes/default/repo/stats/authors/footer.html 0 0
root/themes/default/repo/stats/authors/header.html 11 0
root/themes/default/repo/stats/authors/line.html 8 0
root/themes/default/repo/stats/authors/nodata.html 1 0
root/themes/default/repo/stats/stats.html 11 0
tests/.gitignore 1 0
tests/git.php 22 0

File TODO changed (mode: 100644) (index d75422e..a6b74aa)
1 1 == Where I stopped last time == == Where I stopped last time ==
2 [ ] Test with an empty commit what happens in rg_git_log with patches == TRUE.
3 [ ]
4
5 == BEFORE NEXT RELEASE ==
6 [ ] build rg_user_git_stats that will lookup email into stats and resolve them
7 to be rg links?
8 [ ] repo:stats: seems the number of commits is limited somehow!
9 [ ] repo:stats: do not generate patch, but use '--numstat'.
10 I know it was a problem to parse it, in the past, but...
2 11 [ ] totp: store last ts used, and do not allow reuse. [ ] totp: store last ts used, and do not allow reuse.
3 12 The problem is if both session sends the same token (the attacker and The problem is if both session sends the same token (the attacker and
4 13 the good user). But the attacker can be the first. In this case, the good user). But the attacker can be the first. In this case,
5 14 the user will be denied access! But, he used the good token also, the user will be denied access! But, he used the good token also,
6 15 should I invalidate both sessions and send a recover code by e-mail? should I invalidate both sessions and send a recover code by e-mail?
7 What should I do?
8 [ ]
9
10 == BEFORE NEXT RELEASE ==
16 What should I do? We may also just lock the account and let the user
17 contact the admin. It is clear that an attacker has access to the
18 password and to the token.
19 I need to think more.
20 [ ] NO_DELAY for AF_UNIX socket?
11 21 [ ] When we copy the tree to prepare the push, copy in a temp folder and do [ ] When we copy the tree to prepare the push, copy in a temp folder and do
12 22 a rename to prevent partial trees? I know I give back an error, but ... a rename to prevent partial trees? I know I give back an error, but ...
13 23 [ ] We must clean somehow the namespace dir; think about pushes that fails [ ] We must clean somehow the namespace dir; think about pushes that fails
 
23 33 remote: RocketGit: No rights to delete an annotated tag. remote: RocketGit: No rights to delete an annotated tag.
24 34 remote: ========== remote: ==========
25 35 remote: error: hook declined to update refs/tags/tag2 remote: error: hook declined to update refs/tags/tag2
26
27 [ ] Extend rg_cache_count for the other rg_cache_* commands.
28 36 [ ] Restart the cache daemon when an upgrade takes place. [ ] Restart the cache daemon when an upgrade takes place.
29 37 Done, test. Done, test.
30 [ ] Report number of lines of code (and how much it worth) and number of other
31 type of documents.
38 [ ] Report number of lines of code (and how much a project worth) and
39 number of other type of documents.
32 40 [ ] Add some flags for users: "Coming from GitHub", to be able to give [ ] Add some flags for users: "Coming from GitHub", to be able to give
33 41 tailored hints. tailored hints.
34 [ ] totp: take care of the race: simultaneously login with the same token.
35 42 [ ] totp: warn user that if a token is not validated for 1 month will be deleted? [ ] totp: warn user that if a token is not validated for 1 month will be deleted?
36 43 [ ] totp: allow prefix for IP addresses. [ ] totp: allow prefix for IP addresses.
37 44 [ ] totp: think about authorizing a push, not the ip (ip may be dynamic). [ ] totp: think about authorizing a push, not the ip (ip may be dynamic).
 
39 46 to be sent back: to be sent back:
40 47 ssh ... totp val-push <push_id> <token> ssh ... totp val-push <push_id> <token>
41 48 and remove the push from pending. and remove the push from pending.
42 [ ] "repo was changed": nothing interesting?!
49 [ ] "repo was changed" mail: nothing interesting?!
43 50 If nothing changed, do not send the mail. If nothing changed, do not send the mail.
44 [ ] The URL to the repo presnet in mail is rocketgit.com. We may want to use
51 [ ] The URL to the repo present in mail is rocketgit.com. We may want to use
45 52 the http host name in there. the http host name in there.
46 53 [ ] bugs: if none present, just go to 'Add' page. [ ] bugs: if none present, just go to 'Add' page.
47 54 [ ] Seems 'push' is denied for owner! [ ] Seems 'push' is denied for owner!
 
58 65 this easily becasue I just call git-shell. this easily becasue I just call git-shell.
59 66 But, at least the fetch can be recorded in stats. But, at least the fetch can be recorded in stats.
60 67 [ ] Add cache in rg_git_log. [ ] Add cache in rg_git_log.
61 [ ] unit test for login by token
62 68 [ ] Unit test for fetching by ssh a public repo regarding TOTP [ ] Unit test for fetching by ssh a public repo regarding TOTP
63 [ ] Do I need to update last time used for login_tokens when accessing by ssh?
64 Pretty sure, yes.
65 69 [ ] history: add 2fa ssh validation. [ ] history: add 2fa ssh validation.
70 [ ] Add history for totp enrollment.
66 71 [ ] ionut: Check this to not be send X-PHP-Originating-Script: 0:user.inc.php [ ] ionut: Check this to not be send X-PHP-Originating-Script: 0:user.inc.php
67 72 [ ] VM: Test if IPv4/IPv6 address is shown at login time. [ ] VM: Test if IPv4/IPv6 address is shown at login time.
68 73 [ ] When listing repos on user homepage, we should not add also the user. [ ] When listing repos on user homepage, we should not add also the user.
 
76 81 [ ] In the report, send also stats about the events, especially the failed ones. [ ] In the report, send also stats about the events, especially the failed ones.
77 82 [ ] Document backup procedure. [ ] Document backup procedure.
78 83 [ ] "Forgot password": rate limit it! [ ] "Forgot password": rate limit it!
79 [ ] Add history for totp enrollment.
80 84 [ ] Add history for logins/logouts/API. [ ] Add history for logins/logouts/API.
81 85 [ ] Add max_requests per hour for plans and enforce them. [ ] Add max_requests per hour for plans and enforce them.
82 86 [ ] Protect login by country/ua? [ ] Protect login by country/ua?
 
90 94 Hm. What about the settings?! I must be able to do a select... Hm. What about the settings?! I must be able to do a select...
91 95 [ ] totp: warn user if s/he is low on scratch login codes. [ ] totp: warn user if s/he is low on scratch login codes.
92 96 [ ] totp:scratch: delete them after use? [ ] totp:scratch: delete them after use?
93 [ ] totp: Build a Android application which will be able to authenticate also
97 [ ] totp: Build an Android application which will be able to authenticate also
94 98 the server to the user. the server to the user.
95 [ ] totp: update 'utime' for login tokens
96 [ ] totp: mark last timestamp used for ok login to not be able to reuse the
97 token; what if the time is in the future? we will not cache it.
98 Better, do not allow the same ts.
99 99 [ ] totp: switch to 'password' type for login_token (login page)? [ ] totp: switch to 'password' type for login_token (login page)?
100 100 [ ] totp: hints: [ ] totp: hints:
101 101 AWS asks for two consecutive codes. why? AWS asks for two consecutive codes. why?
 
116 116 (check https://korg.wiki.kernel.org/userdoc/gitolite_2fa) (check https://korg.wiki.kernel.org/userdoc/gitolite_2fa)
117 117 [ ] Use PAM (man pam_start) to be able to use any type of auth, including LDAP. [ ] Use PAM (man pam_start) to be able to use any type of auth, including LDAP.
118 118 [ ] http://www.cybertec.at/shrinking-the-storage-footprint-of-data/ [ ] http://www.cybertec.at/shrinking-the-storage-footprint-of-data/
119 [ ] Allow repo admins to delete notes/bugs/etc.
119 [ ] Allow repo admins/owners to delete notes/bugs/etc.
120 120 [ ] Seems that some other unit test is messing with repo.php ids. [ ] Seems that some other unit test is messing with repo.php ids.
121 121 Change ids to be protected from interference. Change ids to be protected from interference.
122 122 [ ] Use bintray.com to distribute isos? [ ] Use bintray.com to distribute isos?
 
126 126 Check! Check!
127 127 [ ] After login, show the last ip and date of the last login? [ ] After login, show the last ip and date of the last login?
128 128 [ ] Users should be able to check the plans. [ ] Users should be able to check the plans.
129 [ ] I should show some 'plan' islands when you create the account
129 [ ] I should show some plan 'islands' when you create the account
130 130 so the user will know the disk space and bandwidth. so the user will know the disk space and bandwidth.
131 131 [ ] In a table, if nothing can be deleted, do not show the delete button. [ ] In a table, if nothing can be deleted, do not show the delete button.
132 132 [ ] web hooks: start with a http post to a user server. [ ] web hooks: start with a http post to a user server.
 
181 181 why the push failed. Carefull, not too much info. For example: why the push failed. Carefull, not too much info. For example:
182 182 "You have no key uploaded, go to ..." "You have no key uploaded, go to ..."
183 183 [ ] For 'log' and 'tree' we have decorations for links! [ ] For 'log' and 'tree' we have decorations for links!
184 [ ] Sign vm images.
184 185 [ ] In "Tree" section, seems the path is doubled. [ ] In "Tree" section, seems the path is doubled.
185 186 [ ] Hint: where in fs you can find the repo. Only for admins? [ ] Hint: where in fs you can find the repo. Only for admins?
186 187 [ ] Hints should not call rg_template, let next rg_template_table to do it. [ ] Hints should not call rg_template, let next rg_template_table to do it.
 
189 190 [ ] Saving fields in forms when session exired to be reused next time. [ ] Saving fields in forms when session exired to be reused next time.
190 191 [ ] Compression off for ssh because objects are already compressed? [ ] Compression off for ssh because objects are already compressed?
191 192 [ ] Add a random token in header to prevent watermarking (this is the name?). [ ] Add a random token in header to prevent watermarking (this is the name?).
192 [ ] User home page link is missing from top bar! use login_ui::homepage.
193 193 [ ] Add "Spread the word!" on website. [ ] Add "Spread the word!" on website.
194 194 [ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html [ ] https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html
195 195 [ ] git-name-rev is nice. [ ] git-name-rev is nice.
 
201 201 [ ] git-filter-branch is very powerful: offer it to the clients! [ ] git-filter-branch is very powerful: offer it to the clients!
202 202 [ ] word-break: break-all; pentru tabelele cu cod. asta permite wrap-ul [ ] word-break: break-all; pentru tabelele cu cod. asta permite wrap-ul
203 203 oriunde - still needed?! oriunde - still needed?!
204 [ ] On upgrade, we must restart the cache daemon?
205 204 [ ] Backup for rg2! [ ] Backup for rg2!
206 [ ] Sign vm images.
207 205 [ ] Add uid to events so we can delete old events for tests or abusing users? [ ] Add uid to events so we can delete old events for tests or abusing users?
208 206 [ ] Should we just set no password somehow for ssh access to be able to signal [ ] Should we just set no password somehow for ssh access to be able to signal
209 207 the user that has no key uploaded? the user that has no key uploaded?
210 [ ] When getting another IP, allow ssh on port 443(https)?
208 [ ] rocketgit.com: When getting another IP, allow ssh on port 443(https)?
211 209 [ ] Investigate --decorate/--word-diff for git log. [ ] Investigate --decorate/--word-diff for git log.
212 210 [ ] client_win.html hint is not used. [ ] client_win.html hint is not used.
213 211 [ ] merge.html hint is not used. [ ] merge.html hint is not used.
 
217 215 [ ] I am able to disable merge/pull requests? Anon yes, but the other ones? [ ] I am able to disable merge/pull requests? Anon yes, but the other ones?
218 216 [ ] report1: add disk space [ ] report1: add disk space
219 217 [ ] Compress logs (when we are short in disk space)? [ ] Compress logs (when we are short in disk space)?
220 [ ] nofollow
221 218 [ ] Check other filesystems: nils2 etc for virtual machine. [ ] Check other filesystems: nils2 etc for virtual machine.
222 219 [ ] Add right 'allow bad commit messages'. [ ] Add right 'allow bad commit messages'.
223 220 [ ] Add a new section in 'Rights' to enforce a regex on the commit message. [ ] Add a new section in 'Rights' to enforce a regex on the commit message.
 
226 223 [ ] Need to add comments for merge request. Find a way to propagate them in the [ ] Need to add comments for merge request. Find a way to propagate them in the
227 224 git repo? git repo?
228 225 [ ] Implement 'clone' because is easy. The mrs will be a little bit harder. [ ] Implement 'clone' because is easy. The mrs will be a little bit harder.
229 [ ] Because I show the merge re request id, somebody can change the commits.
226 [ ] Because I show the merge request id, somebody can change the commits.
230 227 Somehow, it should be locked? Somehow, it should be locked?
231 228 [ ] Maybe we should not allow bug creation as anonymous? [ ] Maybe we should not allow bug creation as anonymous?
232 229 How do the anonymous person will edit it? A cookie? How do the anonymous person will edit it? A cookie?
 
239 236 of brute force attack on his account. With that token he will be able of brute force attack on his account. With that token he will be able
240 237 to bypass rate limitting. By cookie? to bypass rate limitting. By cookie?
241 238 [ ] slogan: it is not rocket science [ ] slogan: it is not rocket science
242 [ ] Only one daemon should update the structure, else they will conflict.
243 Done. Check.
244 [ ] nofollow la logout; poate si in alte parti
239 [ ] nofollow for logout; maybe also in other places
245 240 [ ] Check if SSL cyphers are ok [ ] Check if SSL cyphers are ok
246 241 [ ] Se pare ca autogenerez drepturi 'All' pentru orice user asupra repo-ului. [ ] Se pare ca autogenerez drepturi 'All' pentru orice user asupra repo-ului.
247 242 Se pare ca si la "Path rights"! Se pare ca si la "Path rights"!
 
275 270 [ ] Configuration: a number of months to keep history (see slaves). [ ] Configuration: a number of months to keep history (see slaves).
276 271 [ ] vagrant install? [ ] vagrant install?
277 272 [ ] If I generated some activity on an object, do not notify myself. [ ] If I generated some activity on an object, do not notify myself.
278 [ ] Show the age of a repo/user/bug/etc.
273 [ ] Show the age of a repo/user/bug/etc. Hm. This will prevent the caching.
279 274 [ ] We should update the size of the repos only if is dirty (something pushed). [ ] We should update the size of the repos only if is dirty (something pushed).
280 275 [ ] Before custom hooks, allow enforcing a custom regex for a commit. [ ] Before custom hooks, allow enforcing a custom regex for a commit.
281 276 [ ] rg_repo_delete trebuie sa stearga si rights si bugs si notes si bug files [ ] rg_repo_delete trebuie sa stearga si rights si bugs si notes si bug files
 
... ... mails to be saved in a folder, so we can parse them and verify them.
308 303 the operations for later. the operations for later.
309 304 [ ] We should not delete the tokens. They will be cleaned hourly? [ ] We should not delete the tokens. They will be cleaned hourly?
310 305 [ ] Remove all texts from code and move them to templates. [ ] Remove all texts from code and move them to templates.
311 At least in forgot.php.
312 306 [ ] Storing password in database must apply multiple hashes. Check owasp. [ ] Storing password in database must apply multiple hashes. Check owasp.
313 307 They recommend SHA-256(private_key, salt + pass). Think more. They recommend SHA-256(private_key, salt + pass). Think more.
314 308 [ ] Regenerate salt on every successful login? Or after some pre-defined time? [ ] Regenerate salt on every successful login? Or after some pre-defined time?
 
... ... Daca as lega good.com de a/b, as putea elimina cookie-urile rele.
351 345 rebase branches. rebase branches.
352 346 [ ] Should we delete previous session when user calls login if the user is [ ] Should we delete previous session when user calls login if the user is
353 347 already logged-in? already logged-in?
354 [ ] Talk in installation about a php compiler?
355 348 [ ] security_violation_no_exit -> security_violation? To not spend resources? [ ] security_violation_no_exit -> security_violation? To not spend resources?
356 349 [ ] We should be able to have multiple logins (think desktop and phone). [ ] We should be able to have multiple logins (think desktop and phone).
357 350 [ ] Test if cache is faster than postgres. If not, get rid of cache! [ ] Test if cache is faster than postgres. If not, get rid of cache!
 
... ... But, we have a problem with the expiration time!
390 383 changes. changes.
391 384 [ ] What happens when a user adds a non-existing one letter code for rights? [ ] What happens when a user adds a non-existing one letter code for rights?
392 385 I should filter it out. I should filter it out.
393 [ ] Log attempts to inject <> inside vars. Maybe in rg_var_str?
386 [ ] Log attempts to inject < and > inside vars. Maybe in rg_var_str?
394 387 [ ] We should not call cosmetic in rights hl because we anyway load again the [ ] We should not call cosmetic in rights hl because we anyway load again the
395 388 list. Seems I do not do it. list. Seems I do not do it.
396 389 [ ] Get rid of 'qstats'. [ ] Get rid of 'qstats'.
 
... ... But, we have a problem with the expiration time!
430 423 [ ] Repo owner can e-mail to users that watch? [ ] Repo owner can e-mail to users that watch?
431 424 [ ] Enforce commit messages formats based on a regex. [ ] Enforce commit messages formats based on a regex.
432 425 [ ] Add redirect to HTTPS and enable HSTS [ ] Add redirect to HTTPS and enable HSTS
433 [ ] If a user has all rights, show "All" instead of full list.
434 Do this in rg_rights_text?
435 426 [ ] Should a user see her/his rights? [ ] Should a user see her/his rights?
436 427 [ ] Add rights 'allow non-ascii file names'. [ ] Add rights 'allow non-ascii file names'.
437 428 [ ] We should not show delete checkboxes/buttons if a user is not allowed [ ] We should not show delete checkboxes/buttons if a user is not allowed
438 429 to delete items. to delete items.
439 [ ] In cache, what if a var has \n in it?
440 430 [ ] Purge deleted bugs (and notes) in background [ ] Purge deleted bugs (and notes) in background
441 431 [ ] Event for bug delete. [ ] Event for bug delete.
442 432 [ ] Cineva sterge un bug, si apoi altcineva apasa "delete" pe acelasi bug. [ ] Cineva sterge un bug, si apoi altcineva apasa "delete" pe acelasi bug.
 
... ... But, we have a problem with the expiration time!
453 443 [ ] We may allow a list of paths/refs for rights, not only a single one. [ ] We may allow a list of paths/refs for rights, not only a single one.
454 444 [ ] Audit all regular expressions (at least /D). Especially in conf file. [ ] Audit all regular expressions (at least /D). Especially in conf file.
455 445 [ ] I should set 'display_errors' to OFF. [ ] I should set 'display_errors' to OFF.
456 [ ] Maybe add db.users.last_ip_failed? Or the history is enough?
446 [ ] Maybe add db.users.last_ip_failed? Or the history is enough? Yep, log failed logins.
457 447 [ ] db.users.last_ip is used for last IP used for login? [ ] db.users.last_ip is used for last IP used for login?
458 448 [ ] repos.disk_quota_mb must be dropped and do a look-up in plan. [ ] repos.disk_quota_mb must be dropped and do a look-up in plan.
459 449 [ ] Integrate max_public/private_repos into HL. [ ] Integrate max_public/private_repos into HL.
 
... ... But, we have a problem with the expiration time!
477 467 [ ] $user -> $rg['user'] [ ] $user -> $rg['user']
478 468 [ ] $repo -> $rg['repo'] [ ] $repo -> $rg['repo']
479 469 [ ] $org... -> $rg['org...'] [ ] $org... -> $rg['org...']
480 [ ] Seems that for tests we do not have a log file, but is specified in the file!
481 470 [ ] Doar unele functii high-level ar trebui sa aiba pasat $rg-ul. [ ] Doar unele functii high-level ar trebui sa aiba pasat $rg-ul.
482 471 Restul, nu! Restul, nu!
483 472 [ ] rg_re_repopage($rg)? [ ] rg_re_repopage($rg)?
484 473 [ ] We may have a problem creating bugs. We must test for failures at every [ ] We may have a problem creating bugs. We must test for failures at every
485 474 step. step.
486 [ ] Rights: for public repos, we make a prio 0 rule to allow fetch (maybe other rights).
487 It will not be in database, it will be generated if repo is public.
488 If repo is becoming private, that rule will not be inserted anymore.
489 475 [ ] When listing repos, check the rights! [ ] When listing repos, check the rights!
490 476 For example, a user is allowed to edit a repo, but is not the owner. For example, a user is allowed to edit a repo, but is not the owner.
491 477 It is not enough to check 'public = 1'. This may generate a lots It is not enough to check 'public = 1'. This may generate a lots
492 478 of look-ups for rights. :( Not if we cache the whole rights list. of look-ups for rights. :( Not if we cache the whole rights list.
493 479 [ ] Add a reason for suspended accounts? Maybe also for other operations? [ ] Add a reason for suspended accounts? Maybe also for other operations?
494 [ ] We should add 'rights.who' to record who gave that right. May be more
495 admins for the same repo.
496 480 [ ] 'users.rights' is still used?! [ ] 'users.rights' is still used?!
497 481 [ ] Maybe add an indirection level: Projects. Because an admin may use [ ] Maybe add an indirection level: Projects. Because an admin may use
498 482 rocketgit only for the bug tracker, for example. Or only for mailing rocketgit only for the bug tracker, for example. Or only for mailing
 
... ... But, we have a problem with the expiration time!
559 543 Or, maybe the first page to contain best repos and search form. Or, maybe the first page to contain best repos and search form.
560 544 [ ] Add possibility to change user time zone. [ ] Add possibility to change user time zone.
561 545 [ ] At least for notes, add also y/m/d/h/m/s 'ago' next to exact time [ ] At least for notes, add also y/m/d/h/m/s 'ago' next to exact time
546 But, this will prevent caches!
562 547 [ ] We need a matrix testing with: [ ] We need a matrix testing with:
563 548 un-logged in user, logged-in user, owner un-logged in user, logged-in user, owner
564 549 vs vs
 
... ... But, we have a problem with the expiration time!
576 561 [ ] Admin should be able to stop queue processing. [ ] Admin should be able to stop queue processing.
577 562 [ ] When we delete a repo, we must delete also rights and bugs etc. Same [ ] When we delete a repo, we must delete also rights and bugs etc. Same
578 563 for a user deletion. for a user deletion.
579 [ ] rights.misc2 is not used now. Drop it.
564 [ ] rights.misc2 is not used now. Drop it?
580 565 [ ] How do we set rg_git_host? Now it shows r1i! [ ] How do we set rg_git_host? Now it shows r1i!
581 566 [ ] Do not test if we watch a bug if the bug is new. [ ] Do not test if we watch a bug if the bug is new.
582 567 [ ] repo-home->"Lock repo" + hint=(options to block fetches/commits/bug/etc.) [ ] repo-home->"Lock repo" + hint=(options to block fetches/commits/bug/etc.)

File inc/git.inc.php changed (mode: 100644) (index cc1da62..5b04442)
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
692 692 $ret = FALSE; $ret = FALSE;
693 693 while (1) { while (1) {
694 694 if (!file_exists($path . "/refs/heads/master")) { if (!file_exists($path . "/refs/heads/master")) {
695 rg_log("Repo is empty.");
696 break;
695 if (!file_exists($path . "/.git/refs/heads/master")) {
696 rg_log("Repo is empty.");
697 break;
698 }
697 699 } }
698 700
699 701 $max_count = ($max == 0) ? "" : " --max-count=$max"; $max_count = ($max == 0) ? "" : " --max-count=$max";
700 $patches = $also_patch ? " --patch" : "";
702 $patches = $also_patch ? " --patch" : " --shortstat";
701 703
702 704 if (empty($from) && empty($to)) { if (empty($from) && empty($to)) {
703 705 $from_to = ""; $from_to = "";
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
761 763 // vars // vars
762 764 $y['vars']['lines_add'] = 0; $y['vars']['lines_add'] = 0;
763 765 $y['vars']['lines_del'] = 0; $y['vars']['lines_del'] = 0;
766 $y['vars']['files_cahnged'] = 0;
764 767 $x = explode ("\0", trim($parts[0])); $x = explode ("\0", trim($parts[0]));
765 768 $count = count($x); $count = count($x);
766 769 for ($i = 0; $i < $count - 1; $i++) { for ($i = 0; $i < $count - 1; $i++) {
 
... ... function rg_git_log($path, $max, $from, $to, $also_patch)
774 777 } }
775 778 } }
776 779
777 // patches
778 if (isset($parts[1])) {
780 if ($also_patch) {
781 // patches
779 782 $y['files'] = rg_git_diff2array($parts[1], $_extra); $y['files'] = rg_git_diff2array($parts[1], $_extra);
780 783 if ($y['files'] === FALSE) if ($y['files'] === FALSE)
781 784 break; break;
782 785
783 786 $y['vars']['lines_add'] = $_extra['lines_add']; $y['vars']['lines_add'] = $_extra['lines_add'];
784 787 $y['vars']['lines_del'] = $_extra['lines_del']; $y['vars']['lines_del'] = $_extra['lines_del'];
788 // TODO: add files_cahnged field!
789 } else {
790 // stortstat
791 rg_log('DEBUG parts[1]: ' . print_r($parts[1], TRUE));
792 $t = explode(',', $parts[1]);
793 $y['vars']['files_changed'] = intval($t[0]);
794
795 for ($i = 1; $i < 3; $i++) {
796 if (!isset($t[$i]))
797 break;
798
799 $x = trim($t[$i]);
800 rg_log('DEBUG: x=[' . $x . ']');
801 if (strstr($x, 'insert'))
802 $y['vars']['lines_add'] += intval($x);
803 else if (strstr($x, 'deletion'))
804 $y['vars']['lines_del'] += intval($x);
805 else
806 rg_log('BUG: unknown field: ' . $x);
807 }
808
809 rg_log('DEBUG lines_add=' . $y['vars']['lines_add']);
810 rg_log('DEBUG lines_del=' . $y['vars']['lines_del']);
785 811 } }
786 812
787 813 // final additions // final additions
 
... ... function rg_git_log_template($log, $dir, $rg)
822 848 * Build statistics * Build statistics
823 849 * TODO: Use caching * TODO: Use caching
824 850 * TODO: count merges * TODO: count merges
851 * Do not forget that the log is from most recent to the oldest
825 852 */ */
826 853 function rg_git_stats($log) function rg_git_stats($log)
827 854 { {
828 $ret = array(
829 "authors" => array(),
830 "commits" => 0,
831 "lines_add" => 0,
832 "lines_del" => 0
833 );
855 $i = array(
856 'commits' => 0,
857 'lines_add' => 0,
858 'lines_del' => 0,
859 'start_date' => '',
860 'start_author' => '',
861 'last_date' => '',
862 'last_author' => ''
863 );
864
865 $ret = array('authors' => array(), 'global' => $i);
834 866
835 867 foreach ($log as $index => $ci) { foreach ($log as $index => $ci) {
836 868 $v = $ci['vars']; $v = $ci['vars'];
837 869
838 if (!isset($ret['project_start_date'])) {
839 $ret['project_start_date'] = $v['author date'];
840 $ret['project_start_author'] = $v['author name'];
870 if (empty($ret['global']['last_date'])) {
871 $ret['global']['last_date'] = $v['author date UTC'];
872 $ret['global']['last_author'] = $v['author name'];
841 873 } }
842 $ret['project_last_date'] = $v['author date'];
843 $ret['project_last_author'] = $v['author name'];
874 $ret['global']['start_date'] = $v['author date UTC'];
875 $ret['global']['start_author'] = $v['author name'];
844 876
845 877 // global stats // global stats
846 $ret['lines_add'] += intval($v['lines_add']);
847 $ret['lines_del'] += intval($v['lines_del']);
848 $ret['commits']++;
878 $ret['global']['lines_add'] += intval($v['lines_add']);
879 $ret['global']['lines_del'] += intval($v['lines_del']);
880 $ret['global']['commits']++;
849 881
850 882 // stats per author // stats per author
851 $a = $v['author name'];
883 $a = $v['author email'];
852 884 if (!isset($ret['authors'][$a])) { if (!isset($ret['authors'][$a])) {
853 $ret['authors'][$a] = array(
854 'first_commit' => 0,
855 'last_commit' => 0,
856 'commits' => 0,
857 'lines_add' => 0,
858 'lines_del' => 0);
885 $ret['authors'][$a] = $i;
886 $ret['authors'][$a]['author'] = $v['author name'];
859 887 } }
888
860 889 $ret['authors'][$a]['commits']++; $ret['authors'][$a]['commits']++;
861 890 $ret['authors'][$a]['lines_add'] += intval($v['lines_add']); $ret['authors'][$a]['lines_add'] += intval($v['lines_add']);
862 891 $ret['authors'][$a]['lines_del'] += intval($v['lines_del']); $ret['authors'][$a]['lines_del'] += intval($v['lines_del']);
863 if ($ret['authors'][$a]['first_commit'] == 0)
864 $ret['authors'][$a]['first_commit'] = $v['author date'];
865 $ret['authors'][$a]['last_commit'] = $v['author date'];
892 if (empty($ret['authors'][$a]['last_date']))
893 $ret['authors'][$a]['last_date'] = $v['author date UTC'];
894 $ret['authors'][$a]['start_date'] = $v['author date UTC'];
866 895 } }
867 896
868 897 return $ret; return $ret;

File inc/repo.inc.php changed (mode: 100644) (index 5b5d62d..c27873b)
... ... function rg_repo_cosmetic(&$row)
643 643 } else { } else {
644 644 $row['HTML:description_nlbr'] = '-'; $row['HTML:description_nlbr'] = '-';
645 645 } }
646
647 if (isset($row['itime']))
648 $row['HTML:itime_nice'] = gmdate('Y-m-d H:i', $row['itime']);
646 649 } }
647 650
648 651 /* /*
 
... ... function rg_repo_discover($db, $op, $rg, $ui)
1724 1727 return $ret; return $ret;
1725 1728 } }
1726 1729
1730 /*
1731 * Show some stats about a repo
1732 */
1733 function rg_repo_stats($rg)
1734 {
1735 if ($rg['ri']['git_dir_done'] == 0)
1736 return rg_template('repo/no_git_dir.html', $rg, TRUE /*xss*/);
1737
1738 $path = rg_repo_path_by_id($rg['ri']['uid'], $rg['ri']['repo_id']);
1739 $log = rg_git_log($path, 0 /*max*/, '', '', FALSE);
1740 if ($log === FALSE)
1741 return rg_template('internal_err.html', $rg, TRUE /*xss*/);
1742
1743 $s = rg_git_stats($log);
1744 // TODO: can this return error?
1745 rg_log_ml('DEBUG: stats: ' . print_r($s, TRUE));
1746 $rg['ri']['stats'] = $s['global'];
1747
1748 $rg['ri']['HTML:authors'] = rg_template_table('repo/stats/authors',
1749 $s['authors'], $rg);
1750
1751 return rg_template('repo/stats/stats.html', $rg, TRUE /*xss*/);
1752 }
1753
1727 1754 ?> ?>

File inc/user/repo-page.php changed (mode: 100644) (index 71ca65c..721b20c)
... ... if (strcmp($_subop, "history") == 0) {
237 237 include($INC . "/user/repo/bug/main.php"); include($INC . "/user/repo/bug/main.php");
238 238 $_repo_body .= $bug_body; $_repo_body .= $bug_body;
239 239 } else if (strcmp($_subop, "stats") == 0) { } else if (strcmp($_subop, "stats") == 0) {
240 if ($rg['ri']['git_dir_done'] == 0)
241 $_repo_body .= rg_template("repo/no_git_dir.html", $rg, TRUE /* xss */);
242 else
243 $_repo_body .= rg_template("repo/stats.html", $rg, TRUE /* xss */);
240 $_repo_body .= rg_repo_stats($rg);
244 241 } else if (strcmp($_subop, "mr") == 0) { } else if (strcmp($_subop, "mr") == 0) {
245 242 if ($rg['ri']['git_dir_done'] == 0) { if ($rg['ri']['git_dir_done'] == 0) {
246 243 $_repo_body .= rg_template("repo/no_git_dir.html", $rg, TRUE /* xss */); $_repo_body .= rg_template("repo/no_git_dir.html", $rg, TRUE /* xss */);

File root/themes/default/repo/main.html changed (mode: 100644) (index f30a8ed..28ba8f2)
5 5 <a href="@@url_user@@">@@page_ui::username@@</a> / <a href="@@url_repo@@">@@ri::name@@</a> <a href="@@url_user@@">@@page_ui::username@@</a> / <a href="@@url_repo@@">@@ri::name@@</a>
6 6 (@@if(@@ri::public@@ == 1){{public}}{{private}}) (@@if(@@ri::public@@ == 1){{public}}{{private}})
7 7 (License: @@if("@@ri::license@@" == ""){{Unspecified}}{{@@ri::license@@}}) (License: @@if("@@ri::license@@" == ""){{Unspecified}}{{@@ri::license@@}})
8 (since @@ri::itime_nice@@)
8 9 </div> </div>
9 10 <div class="repo_desc"> <div class="repo_desc">
10 11 @@ri::description_nlbr@@ @@ri::description_nlbr@@
 
19 20 <li@@if(@@per_repo_menu::source@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/source">Source</a></li> <li@@if(@@per_repo_menu::source@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/source">Source</a></li>
20 21 <li@@if(@@per_repo_menu::mr@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/mr">Merge requests</a></li> <li@@if(@@per_repo_menu::mr@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/mr">Merge requests</a></li>
21 22 <li@@if(@@per_repo_menu::bug@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/bug">Bugs</a></li> <li@@if(@@per_repo_menu::bug@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/bug">Bugs</a></li>
23 <li@@if(@@per_repo_menu::stats@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/stats">Stats</a></li>
22 24 @@if(@@can_admin@@ == 1){{<li@@if(@@per_repo_menu::admin@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin">Admin</a></li>}}{{}} @@if(@@can_admin@@ == 1){{<li@@if(@@per_repo_menu::admin@@ == 1){{ class="selected"}}{{}}><a href="@@url_repo@@/admin">Admin</a></li>}}{{}}
23 25 </ul> </ul>
24 26 </div> </div>

File root/themes/default/repo/stats.html deleted (index 8be9ac2..0000000)
1 Not yet implemented. Any feedback about this is appreciated.

File root/themes/default/repo/stats/authors/footer.html copied from file root/themes/default/repo/bug/list/footer.html (similarity 100%)

File root/themes/default/repo/stats/authors/header.html added (mode: 100644) (index 0000000..ab1265d)
1 <br />
2
3 <table summary="authors stats">
4 <tr>
5 <th>Author</th>
6 <th>Commits</th>
7 <th>Lines added</th>
8 <th>Lines deleted</th>
9 <th>First commit</th>
10 <th>Last commit</th>
11 </tr>

File root/themes/default/repo/stats/authors/line.html added (mode: 100644) (index 0000000..e7dfdaf)
1 <tr>
2 <td>@@author@@</td>
3 <td>@@commits@@</td>
4 <td>@@lines_add@@</td>
5 <td>@@lines_del@@</td>
6 <td>@@start_date@@</td>
7 <td>@@last_date@@</td>
8 </tr>

File root/themes/default/repo/stats/authors/nodata.html added (mode: 100644) (index 0000000..e25f181)
1 y

File root/themes/default/repo/stats/stats.html added (mode: 100644) (index 0000000..65dada6)
1 Added on this site on <b>@@ri::itime_nice@@</b>.<br />
2 Disk space used: <b>@@ri::disk_used_mb@@ MiB</b>.<br />
3 Bugs reported: <b>@@ri::last_bug_id@@</b>.<br />
4 <br />
5 Project started on <b>@@ri::stats::start_date@@</b> by <b>@@ri::stats::start_author@@</b>.<br />
6 Last commit on <b>@@ri::stats::last_date@@</b> by <b>@@ri::stats::last_author@@</b>.<br />
7 Number of commits: <b>@@ri::stats::commits@@</b>.<br />
8 Number of lines added: <b>@@ri::stats::lines_add@@</b>.<br />
9 Number of lines deleted: <b>@@ri::stats::lines_del@@</b>.<br />
10
11 @@ri::authors@@

File tests/.gitignore changed (mode: 100644) (index 30261ee..ad248e1)
... ... git2key.pub
15 15 git_log1 git_log1
16 16 q_merge_requests q_merge_requests
17 17 qstats qstats
18 git_bin

File tests/git.php changed (mode: 100644) (index 05b5f2f..ecef385)
... ... $rg_no_db = TRUE;
13 13 require_once("common.php"); require_once("common.php");
14 14
15 15
16 rg_log('');
17 rg_log("Testing rg_git_log for binary files");
18 system("git init git_bin; cd git_bin;"
19 . " echo -e \x01\x02 > a; git add a; git commit -a -m \"aaa\";"
20 . " echo -e \x01\x03 > a; git commit -a -m \"bbb\"");
21 $r = rg_git_log('git_bin/.git', 0, '', '', FALSE);
22 if ($r[0]['vars']['lines_add'] != 1) {
23 rg_log_ml(print_r($r[0], TRUE));
24 rg_log('git_bin: lines_add is incorrect');
25 exit(1);
26 }
27 if ($r[0]['vars']['lines_del'] != 1) {
28 rg_log_ml(print_r($r[0], TRUE));
29 rg_log('git_bin: lines_del is incorrect');
30 exit(1);
31 }
32 system("rm -rf git_bin");
33
34
35 rg_log('');
16 36 rg_log("Testing git_reference..."); rg_log("Testing git_reference...");
17 37 $s = "refs"; $s = "refs";
18 38 $e = $s; $e = $s;
 
... ... if ($r !== TRUE) {
38 58 exit(1); exit(1);
39 59 } }
40 60
61
62
41 63 /* /*
42 64 rg_log("[*] Populate repo..."); rg_log("[*] Populate repo...");
43 65 file_put_contents("git.tmp/a", "aaa"); file_put_contents("git.tmp/a", "aaa");
Hints

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

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

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

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