gitalytics 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.coveralls.yml +1 -0
- data/.gitignore +14 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +31 -0
- data/Gemfile +9 -0
- data/README.md +65 -0
- data/Rakefile +8 -0
- data/assets/gitalytics.html.erb +286 -47
- data/bin/gitalytics +8 -2
- data/gitalytics.gemspec +28 -0
- data/lib/gitalytics.rb +13 -7
- data/lib/{commit.rb → gitalytics/commit.rb} +0 -0
- data/lib/{gitlog.rb → gitalytics/gitlog.rb} +18 -12
- data/lib/{user.rb → gitalytics/user.rb} +12 -11
- data/lib/gitalytics/version.rb +3 -0
- data/test/lib/test_commit.rb +42 -0
- data/test/lib/test_gitlog.rb +105 -0
- data/test/lib/test_user.rb +86 -0
- data/test/test_helper.rb +2 -0
- metadata +72 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3f105e2f5f0c549981b100e5ebfa66d22c86fef
|
4
|
+
data.tar.gz: 432428efcdfea8e4dc3c3eec59ece71a39092692
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90fcb57c95019c47583cb0f6c9cc909d12addb5db13e430e118dc8f5ea2028adde466c9ac16ba7b862344ca93eb003a97d6ce5869edc33810a68d9269572f935
|
7
|
+
data.tar.gz: ffb1ecd259992afa952df44a83d5c01f2492e3c855084d85a27068cd0366390f63ab622383f701ee0b08e7de9a06aa92412e55af3af7ab5cc21ae9bbb549af84
|
data/.coveralls.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
service_name: travis-ci
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
## Gitalytics Changelog
|
2
|
+
|
3
|
+
#### v.1.3.0
|
4
|
+
* Changed CLI output text.
|
5
|
+
* Re-structure of gem's source code.
|
6
|
+
* Authors are now grouped by name.
|
7
|
+
* Added CLI option -e to group authors by email (old behavior).
|
8
|
+
* Updated Chart.js version.
|
9
|
+
* Updated Bootstrap version.
|
10
|
+
* Updated HTML report design.
|
11
|
+
|
12
|
+
#### v.1.2.1
|
13
|
+
* Fixed bug that prevented gitalytics to initialize correctly. (Thanks @willyschwindt)
|
14
|
+
|
15
|
+
#### v.1.2.0
|
16
|
+
* Git log parser totally refactored. (Thanks @grilix)
|
17
|
+
* Gitalytics now open html report in browser automatically. (Thanks @surendrans)
|
18
|
+
* Moved classes and modules to external files.
|
19
|
+
* Added CLI option -n that prevents report to load automatically in web browser.
|
20
|
+
* Dashboard added with some quick stats for your git repository.
|
21
|
+
|
22
|
+
#### v1.1.1
|
23
|
+
* Add Changelog :)
|
24
|
+
* Update Readme.
|
25
|
+
* Fix bug which preventing authors with special characters to be shown on the report. (thanks @afrojas)
|
26
|
+
* Fix bug which may result in a broken report if the user uses a default format for git log. (thanks @dgiunta)
|
27
|
+
|
28
|
+
#### v1.1.0
|
29
|
+
* Add Insertions vs. Deletions graph for Users.
|
30
|
+
* Add weekday commits count graph for Users.
|
31
|
+
* Change the way it shows the authors information.
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
## Gitalytics
|
2
|
+
|
3
|
+
Get commits statistics for your git repository
|
4
|
+
Based on gist by Tobin Harris: https://gist.github.com/tobinharris/396634
|
5
|
+
|
6
|
+
[![Code Climate](https://codeclimate.com/github/pepito2k/gitalytics.png)](https://codeclimate.com/github/pepito2k/gitalytics)
|
7
|
+
[![Gem Version](https://badge.fury.io/rb/gitalytics.png)](http://badge.fury.io/rb/gitalytics)
|
8
|
+
[![Dependency Status](https://gemnasium.com/pepito2k/gitalytics.png)](https://gemnasium.com/pepito2k/gitalytics)
|
9
|
+
[![Build Status](https://travis-ci.org/pepito2k/gitalytics.png)](https://travis-ci.org/pepito2k/gitalytics)
|
10
|
+
[![Coverage Status](https://coveralls.io/repos/pepito2k/gitalytics/badge.png?branch=master)](https://coveralls.io/r/pepito2k/gitalytics?branch=master)
|
11
|
+
|
12
|
+
![Gitalytics Screenshot](http://photos.gonzalo.robaina.me/gitalytics_screen.png "Gitalytics Screenshot")
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
### Manual installation
|
17
|
+
|
18
|
+
gem install gitalytics
|
19
|
+
|
20
|
+
### Using bundler
|
21
|
+
Add gitalytics to your Gemfile
|
22
|
+
|
23
|
+
gem "gitalytics"
|
24
|
+
|
25
|
+
Install the gem
|
26
|
+
|
27
|
+
bundle install
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
Open a terminal window pointing to your git repository and just run the gitalytics command:
|
31
|
+
|
32
|
+
$ gitalytics
|
33
|
+
|
34
|
+
If you'd like to get a fancy html report like the one in the screenshot above, you will need to run the following command:
|
35
|
+
|
36
|
+
$ gitalytics -h
|
37
|
+
|
38
|
+
If you want to have the html report but don't want it to be opened right away just write:
|
39
|
+
|
40
|
+
$ gitalytics -n
|
41
|
+
|
42
|
+
Note that gitalytics groups authors by name, you can change that and group by email using:
|
43
|
+
|
44
|
+
$ gitalytics -e
|
45
|
+
|
46
|
+
## License
|
47
|
+
Copyright (c) 2016 Gonzalo Robaina
|
48
|
+
|
49
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
50
|
+
of this software and associated documentation files (the "Software"), to deal
|
51
|
+
in the Software without restriction, including without limitation the rights
|
52
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
53
|
+
copies of the Software, and to permit persons to whom the Software is
|
54
|
+
furnished to do so, subject to the following conditions:
|
55
|
+
|
56
|
+
The above copyright notice and this permission notice shall be included in
|
57
|
+
all copies or substantial portions of the Software.
|
58
|
+
|
59
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
60
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
61
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
62
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
63
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
64
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
65
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
data/assets/gitalytics.html.erb
CHANGED
@@ -4,13 +4,14 @@
|
|
4
4
|
<meta charset="utf-8">
|
5
5
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
-
<meta name="description" content="">
|
8
|
-
<meta name="author" content="">
|
7
|
+
<meta name="description" content="Gitalytics Report">
|
8
|
+
<meta name="author" content="Gonzalo Robaina">
|
9
9
|
|
10
10
|
<title>Gitalytics report</title>
|
11
11
|
|
12
12
|
<!-- Bootstrap core CSS -->
|
13
|
-
<link href="
|
13
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
14
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
|
14
15
|
|
15
16
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
16
17
|
<!--[if lt IE 9]>
|
@@ -40,10 +41,115 @@
|
|
40
41
|
|
41
42
|
/* Set the fixed height of the footer here */
|
42
43
|
#footer {
|
43
|
-
height: 60px;
|
44
44
|
background-color: #f5f5f5;
|
45
|
+
height: 60px;
|
46
|
+
margin-top: 60px;
|
45
47
|
}
|
46
48
|
|
49
|
+
/* Twitter Profile styles
|
50
|
+
-------------------------------------------------- */
|
51
|
+
.twPc-div {
|
52
|
+
background: #fff none repeat scroll 0 0;
|
53
|
+
border: 1px solid #e1e8ed;
|
54
|
+
border-radius: 6px;
|
55
|
+
height: 150px;
|
56
|
+
max-width: 340px;
|
57
|
+
margin-bottom: 40px;
|
58
|
+
}
|
59
|
+
.twPc-bg {
|
60
|
+
border-bottom: 1px solid #e1e8ed;
|
61
|
+
border-radius: 4px 4px 0 0;
|
62
|
+
height: 40px;
|
63
|
+
width: 100%;
|
64
|
+
}
|
65
|
+
.twPc-block {
|
66
|
+
display: block !important;
|
67
|
+
}
|
68
|
+
.twPc-button {
|
69
|
+
margin: -35px -10px 0;
|
70
|
+
text-align: right;
|
71
|
+
width: 100%;
|
72
|
+
}
|
73
|
+
.twPc-avatarLink {
|
74
|
+
background-color: #fff;
|
75
|
+
border-radius: 6px;
|
76
|
+
display: inline-block !important;
|
77
|
+
float: left;
|
78
|
+
margin: -30px 5px 0 8px;
|
79
|
+
max-width: 100%;
|
80
|
+
padding: 1px;
|
81
|
+
vertical-align: bottom;
|
82
|
+
}
|
83
|
+
.twPc-avatarImg {
|
84
|
+
border: 2px solid #fff;
|
85
|
+
border-radius: 7px;
|
86
|
+
box-sizing: border-box;
|
87
|
+
color: #fff;
|
88
|
+
height: 72px;
|
89
|
+
width: 72px;
|
90
|
+
}
|
91
|
+
.twPc-divUser {
|
92
|
+
margin: 5px 0 0;
|
93
|
+
}
|
94
|
+
.twPc-divName {
|
95
|
+
font-size: 18px;
|
96
|
+
font-weight: 700;
|
97
|
+
line-height: 21px;
|
98
|
+
white-space: nowrap;
|
99
|
+
overflow: hidden;
|
100
|
+
text-overflow: ellipsis
|
101
|
+
}
|
102
|
+
.twPc-divName a {
|
103
|
+
color: inherit !important;
|
104
|
+
}
|
105
|
+
.twPc-divStats {
|
106
|
+
margin-left: 11px;
|
107
|
+
padding: 10px 0;
|
108
|
+
}
|
109
|
+
.twPc-Arrange {
|
110
|
+
box-sizing: border-box;
|
111
|
+
display: table;
|
112
|
+
margin: 0;
|
113
|
+
min-width: 100%;
|
114
|
+
padding: 0;
|
115
|
+
table-layout: auto;
|
116
|
+
}
|
117
|
+
ul.twPc-Arrange {
|
118
|
+
list-style: outside none none;
|
119
|
+
margin: 0;
|
120
|
+
padding: 0;
|
121
|
+
}
|
122
|
+
.twPc-ArrangeSizeFit {
|
123
|
+
display: table-cell;
|
124
|
+
padding: 0;
|
125
|
+
vertical-align: top;
|
126
|
+
}
|
127
|
+
.twPc-ArrangeSizeFit a:hover {
|
128
|
+
text-decoration: none;
|
129
|
+
}
|
130
|
+
.twPc-StatValue {
|
131
|
+
display: block;
|
132
|
+
font-size: 18px;
|
133
|
+
font-weight: 500;
|
134
|
+
transition: color 0.15s ease-in-out 0s;
|
135
|
+
}
|
136
|
+
.twPc-StatValue.commits {
|
137
|
+
color: #a650c0;
|
138
|
+
}
|
139
|
+
.twPc-StatValue.insertions {
|
140
|
+
color: #539734;
|
141
|
+
}
|
142
|
+
.twPc-StatValue.deletions {
|
143
|
+
color: #c03c24;
|
144
|
+
}
|
145
|
+
.twPc-StatLabel {
|
146
|
+
color: #8899a6;
|
147
|
+
font-size: 10px;
|
148
|
+
letter-spacing: 0.02em;
|
149
|
+
overflow: hidden;
|
150
|
+
text-transform: uppercase;
|
151
|
+
transition: color 0.15s ease-in-out 0s;
|
152
|
+
}
|
47
153
|
|
48
154
|
/* Custom page CSS
|
49
155
|
-------------------------------------------------- */
|
@@ -96,6 +202,14 @@
|
|
96
202
|
font-size: 48px;
|
97
203
|
}
|
98
204
|
|
205
|
+
#authors li {
|
206
|
+
list-style: none;
|
207
|
+
}
|
208
|
+
|
209
|
+
.usersColorLegend {
|
210
|
+
vertical-align: middle;
|
211
|
+
}
|
212
|
+
|
99
213
|
</style>
|
100
214
|
</head>
|
101
215
|
|
@@ -120,6 +234,8 @@
|
|
120
234
|
<ul class="nav navbar-nav">
|
121
235
|
<li class="active"><a href="#dashboard" data-toggle="tab">Dashboard</a></li>
|
122
236
|
<li><a href="#authors" data-toggle="tab">Authors</a></li>
|
237
|
+
<li><a href="#commits" data-toggle="tab">Commits</a></li>
|
238
|
+
<li><a href="#dates" data-toggle="tab">Dates</a></li>
|
123
239
|
<!-- <li><a href="#contact">Contact</a></li> -->
|
124
240
|
</ul>
|
125
241
|
</div><!--/.nav-collapse -->
|
@@ -129,6 +245,7 @@
|
|
129
245
|
<!-- Begin page content -->
|
130
246
|
<div class="container">
|
131
247
|
<div class="tab-content">
|
248
|
+
<!-- Start Dashboard -->
|
132
249
|
<div class="tab-pane active" id="dashboard">
|
133
250
|
<div class="page-header">
|
134
251
|
<h1>Dashboard</h1>
|
@@ -183,30 +300,136 @@
|
|
183
300
|
</div>
|
184
301
|
</div>
|
185
302
|
</div>
|
303
|
+
<!-- End Dashboard -->
|
304
|
+
<!-- Start Authors -->
|
186
305
|
<div class="tab-pane" id="authors">
|
187
306
|
<div class="page-header">
|
188
307
|
<h1>Authors</h1>
|
189
308
|
<p class="lead">Compare the quantity of commits made by each of your repository contributors.<br/> Check who is writing most of the code of your project and maybe give him/her a prize! ;)</p>
|
309
|
+
</div>
|
310
|
+
<div class="row">
|
311
|
+
<p>So far, <%= @users.size %> contributors commited something to your project.</p>
|
190
312
|
<% @users.each do |user| %>
|
191
|
-
<
|
192
|
-
|
313
|
+
<div class="col-md-4">
|
314
|
+
<!-- Twitter Profile start -->
|
315
|
+
<div class="twPc-div">
|
316
|
+
<a class="twPc-bg twPc-block" style="background-color: <%= user.rgba %>"></a>
|
317
|
+
<div>
|
318
|
+
|
319
|
+
<a title="<%= user.name %>" href="#" class="twPc-avatarLink">
|
320
|
+
<img alt="<%= user.name %>" src="<%= "http://www.gravatar.com/avatar/#{user.gravatar}?d=mm" %>" class="twPc-avatarImg">
|
321
|
+
</a>
|
322
|
+
|
323
|
+
<div class="twPc-divUser">
|
324
|
+
<div class="twPc-divName">
|
325
|
+
<a href="#"><%= user.name %></a>
|
326
|
+
</div>
|
327
|
+
<span>
|
328
|
+
<a href="mailto:<%= user.email %>"><span><%= user.email %></span></a>
|
329
|
+
</span>
|
330
|
+
</div>
|
331
|
+
|
332
|
+
<div class="twPc-divStats">
|
333
|
+
<ul class="twPc-Arrange">
|
334
|
+
<li class="twPc-ArrangeSizeFit">
|
335
|
+
<span class="twPc-StatLabel twPc-block">Commits</span>
|
336
|
+
<span class="twPc-StatValue commits"><%= user.commits.size %></span>
|
337
|
+
</li>
|
338
|
+
<li class="twPc-ArrangeSizeFit">
|
339
|
+
<span class="twPc-StatLabel twPc-block">Inserts</span>
|
340
|
+
<span class="twPc-StatValue insertions"><%= user.total_insertions %></span>
|
341
|
+
</li>
|
342
|
+
<li class="twPc-ArrangeSizeFit">
|
343
|
+
<span class="twPc-StatLabel twPc-block">Deletes</span>
|
344
|
+
<span class="twPc-StatValue deletions"><%= user.total_deletions %></span>
|
345
|
+
</li>
|
346
|
+
</ul>
|
347
|
+
</div>
|
348
|
+
</div>
|
349
|
+
</div>
|
350
|
+
<!-- Twitter Profile end -->
|
351
|
+
</div>
|
193
352
|
<% end %>
|
194
353
|
</div>
|
195
354
|
|
196
355
|
<div class="row">
|
356
|
+
<h2>Commits count per user</h2>
|
197
357
|
<div class="col-md-6">
|
198
|
-
<h2>Commits count per user</h2>
|
199
358
|
<canvas id="usersPieChart" width="550" height="400"></canvas>
|
200
359
|
</div>
|
201
360
|
<div class="col-md-6">
|
202
|
-
<
|
203
|
-
|
361
|
+
<ul>
|
362
|
+
<% @users.each do |u| %>
|
363
|
+
<li>
|
364
|
+
<canvas class="usersColorLegend" width="30" height="15" style="background-color: <%= u.rgba %>"></canvas>
|
365
|
+
<%= u.name %>
|
366
|
+
</li>
|
367
|
+
<% end %>
|
368
|
+
<ul>
|
204
369
|
</div>
|
205
370
|
</div>
|
206
|
-
<hr>
|
371
|
+
<!-- <hr>
|
207
372
|
<h2>Insertions vs. Deletions</h2>
|
208
|
-
<canvas id="usersBarChart" width="1100" height="400"></canvas>
|
373
|
+
<canvas id="usersBarChart" width="1100" height="400"></canvas> -->
|
374
|
+
</div>
|
375
|
+
<!-- End Authors -->
|
376
|
+
<!-- Start Commits -->
|
377
|
+
<div class="tab-pane" id="commits">
|
378
|
+
<div class="page-header">
|
379
|
+
<h1>Commits</h1>
|
380
|
+
<p class="lead">A few basic stats on single commits.</p>
|
381
|
+
</div>
|
382
|
+
|
383
|
+
<% shortest_commit = @commits.min_by { |c| c.subject.length } %>
|
384
|
+
<% longest_commit = @commits.max_by { |c| c.subject.length } %>
|
385
|
+
|
386
|
+
<h2>Shortest commit message</h2>
|
387
|
+
<blockquote>
|
388
|
+
<p><%=shortest_commit.subject %></p>
|
389
|
+
<footer><%=shortest_commit.author.name %> <cite><%=shortest_commit.date.strftime('%a %-d, %B %Y') %></cite></footer>
|
390
|
+
</blockquote>
|
391
|
+
|
392
|
+
<hr/>
|
393
|
+
|
394
|
+
<h2>Longest commit message</h2>
|
395
|
+
<blockquote>
|
396
|
+
<p><%=longest_commit.subject %></p>
|
397
|
+
<footer><%=longest_commit.author.name %> <cite><%=longest_commit.date.strftime('%a %-d, %B %Y') %></cite></footer>
|
398
|
+
</blockquote>
|
399
|
+
|
209
400
|
</div>
|
401
|
+
<!-- End Commits -->
|
402
|
+
<!-- Start Dates -->
|
403
|
+
<div class="tab-pane" id="dates">
|
404
|
+
<div class="page-header">
|
405
|
+
<h1>Dates</h1>
|
406
|
+
<p class="lead">When are those commits happening?</p>
|
407
|
+
</div>
|
408
|
+
|
409
|
+
<% first_commit = @commits.min_by(&:date) %>
|
410
|
+
<% last_commit = @commits.max_by(&:date) %>
|
411
|
+
|
412
|
+
<h2>First Commit Ever</h2>
|
413
|
+
<blockquote>
|
414
|
+
<p><%=first_commit.subject %></p>
|
415
|
+
<footer><%=first_commit.author.name %> <cite><%=first_commit.date.strftime('%a %-d, %B %Y') %></cite></footer>
|
416
|
+
</blockquote>
|
417
|
+
|
418
|
+
<hr/>
|
419
|
+
|
420
|
+
<h2>Last Commit</h2>
|
421
|
+
<blockquote>
|
422
|
+
<p><%=last_commit.subject %></p>
|
423
|
+
<footer><%=last_commit.author.name %> <cite><%=last_commit.date.strftime('%a %-d, %B %Y') %></cite></footer>
|
424
|
+
</blockquote>
|
425
|
+
|
426
|
+
<hr/>
|
427
|
+
|
428
|
+
<h2>Most Busy Days</h2>
|
429
|
+
<canvas id="daysBarChart" width="1100" height="400"></canvas>
|
430
|
+
|
431
|
+
</div>
|
432
|
+
<!-- End Dates -->
|
210
433
|
</div>
|
211
434
|
</div>
|
212
435
|
</div>
|
@@ -218,63 +441,79 @@
|
|
218
441
|
</div>
|
219
442
|
|
220
443
|
|
221
|
-
<!--
|
444
|
+
<!-- External JavaScript Files
|
222
445
|
================================================== -->
|
223
|
-
|
224
|
-
<script src="https://
|
225
|
-
<script src="
|
226
|
-
<script src="http://cdnjs.cloudflare.com/ajax/libs/Chart.js/0.2.0/Chart.min.js"></script>
|
446
|
+
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
|
447
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
|
448
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.min.js"></script>
|
227
449
|
<script>
|
228
450
|
$('.user-avatar').popover({ trigger: 'hover', html: true }).click(function(e){
|
229
451
|
e.preventDefault();
|
230
452
|
});
|
231
453
|
|
232
454
|
// Data for Users Pie Chart
|
233
|
-
var data = [<%= @users.map{|d| "{ value: #{d.commits.count}, color: '#{d.rgba}' }" }.join(',') %>];
|
234
|
-
var ctx = document.getElementById("usersPieChart").getContext("2d");
|
235
|
-
var usersPieChart = new Chart(ctx).Pie(data);
|
236
|
-
|
237
|
-
// Data for Insertions vs. Deletions Bar Chart
|
238
455
|
var data = {
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
},
|
246
|
-
{
|
247
|
-
data: [<%= @users.map{|d| "#{d.total_deletions}" }.join(',') %>],
|
248
|
-
fillColor: 'rgba(234, 80, 44, 0.5)',
|
249
|
-
strokeColor: 'rgba(234, 80, 44, 1)'
|
250
|
-
}
|
251
|
-
]
|
456
|
+
datasets: [{
|
457
|
+
data: [<%= @users.map{|u| "#{u.commits.count}" }.join(', ') %>],
|
458
|
+
backgroundColor: [<%= @users.map{|u| "'#{u.rgba}'" }.join(', ') %>]
|
459
|
+
}],
|
460
|
+
labels: [<%= @users.map{|u| "'#{u.name}'" }.join(', ') %>
|
461
|
+
]
|
252
462
|
};
|
253
|
-
var ctx = document.getElementById("
|
254
|
-
var
|
463
|
+
var ctx = document.getElementById("usersPieChart").getContext("2d");
|
464
|
+
var usersPieChart = new Chart(ctx,{
|
465
|
+
type: 'pie',
|
466
|
+
data: data,
|
467
|
+
options: {
|
468
|
+
legend: {
|
469
|
+
display: false
|
470
|
+
}
|
471
|
+
}
|
472
|
+
});
|
473
|
+
|
474
|
+
// // Data for Insertions vs. Deletions Bar Chart
|
475
|
+
// var data = {
|
476
|
+
// labels: [<%= @users.map{|d| "'#{d.name}'" }.join(',') %>],
|
477
|
+
// datasets: [
|
478
|
+
// {
|
479
|
+
// data: [<%= @users.map{|d| "#{d.total_insertions}" }.join(',') %>],
|
480
|
+
// fillColor: 'rgba(196, 234, 44, 0.5)',
|
481
|
+
// strokeColor: 'rgba(196, 234, 44, 1)'
|
482
|
+
// },
|
483
|
+
// {
|
484
|
+
// data: [<%= @users.map{|d| "#{d.total_deletions}" }.join(',') %>],
|
485
|
+
// fillColor: 'rgba(234, 80, 44, 0.5)',
|
486
|
+
// strokeColor: 'rgba(234, 80, 44, 1)'
|
487
|
+
// }
|
488
|
+
// ]
|
489
|
+
// };
|
490
|
+
// var ctx = document.getElementById("usersBarChart").getContext("2d");
|
491
|
+
// var usersBarChart = new Chart(ctx).Bar(data);
|
255
492
|
|
256
493
|
// Data for Weekday commits per user
|
257
494
|
var data = {
|
258
495
|
labels: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
|
259
496
|
datasets: [
|
260
|
-
<% @users.each_with_index do |user, i| %>
|
261
497
|
{
|
262
|
-
|
263
|
-
|
264
|
-
pointColor : "<%= user.rgba %>",
|
265
|
-
pointStrokeColor : "#fff",
|
266
|
-
data : [<%= user.weekday_commits.join(', ') %>]
|
267
|
-
}<%= ',' unless i + 1 == @users.count %>
|
268
|
-
<% end %>
|
498
|
+
data : [<%= @weekday_commits.join(', ') %>]
|
499
|
+
}
|
269
500
|
]
|
270
501
|
};
|
271
|
-
var ctx = document.getElementById("
|
272
|
-
var
|
502
|
+
var ctx = document.getElementById("daysBarChart").getContext("2d");
|
503
|
+
var myBarChart = new Chart(ctx, {
|
504
|
+
type: 'bar',
|
505
|
+
data: data,
|
506
|
+
options: {
|
507
|
+
legend: {
|
508
|
+
display: false
|
509
|
+
}
|
510
|
+
}
|
511
|
+
});
|
273
512
|
|
274
513
|
// Makes dashboard items link to tabs
|
275
514
|
$('a[data-open-tab]').click(function(e) {
|
276
515
|
e.preventDefault();
|
277
|
-
$('a[href="#' + $(this).attr('data-open-tab') + '"]').click();
|
516
|
+
$('.navbar-nav').find('a[href="#' + $(this).attr('data-open-tab') + '"]').click();
|
278
517
|
});
|
279
518
|
</script>
|
280
519
|
</body>
|
data/bin/gitalytics
CHANGED
@@ -8,7 +8,9 @@ require 'optparse'
|
|
8
8
|
require 'gitalytics'
|
9
9
|
|
10
10
|
options = {
|
11
|
-
|
11
|
+
browser: false,
|
12
|
+
format: 'cli',
|
13
|
+
group_by: 'name'
|
12
14
|
}
|
13
15
|
|
14
16
|
OptionParser.new do |opts|
|
@@ -28,7 +30,11 @@ OptionParser.new do |opts|
|
|
28
30
|
options[:format] = 'html'
|
29
31
|
options[:browser] = false
|
30
32
|
end
|
33
|
+
|
34
|
+
opts.on("-e", "--group-email", "Group commits by author's email address") do |v|
|
35
|
+
options[:group_by] = 'email'
|
36
|
+
end
|
31
37
|
end.parse!
|
32
38
|
|
33
39
|
Dir.chdir($1 || '.')
|
34
|
-
Gitalytics.
|
40
|
+
Gitalytics.analyze(options)
|
data/gitalytics.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'gitalytics/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gitalytics"
|
8
|
+
spec.version = Gitalytics::VERSION
|
9
|
+
|
10
|
+
spec.authors = ["Gonzalo Robaina"]
|
11
|
+
spec.email = "gonzalor@gmail.com"
|
12
|
+
|
13
|
+
spec.summary = "Git Analytics"
|
14
|
+
spec.description = "Get usefull analytics from your git log"
|
15
|
+
spec.homepage = "http://gonza.uy/gitalytics"
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = '>= 1.9.3'
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_dependency "color-generator"
|
28
|
+
end
|
data/lib/gitalytics.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require 'erb'
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
4
|
+
require 'matrix'
|
5
|
+
require 'gitalytics/commit'
|
6
|
+
require 'gitalytics/gitlog'
|
7
|
+
require 'gitalytics/user'
|
8
|
+
require 'gitalytics/version'
|
7
9
|
|
8
|
-
|
10
|
+
module Gitalytics
|
9
11
|
|
10
|
-
|
12
|
+
module_function
|
11
13
|
|
12
14
|
def analyze(options)
|
13
|
-
data = GitLog.parse_git_log
|
15
|
+
data = GitLog.parse_git_log(options[:group_by])
|
14
16
|
|
15
17
|
case options[:format]
|
16
18
|
when 'html'
|
@@ -22,6 +24,8 @@ class Gitalytics
|
|
22
24
|
|
23
25
|
private
|
24
26
|
|
27
|
+
module_function
|
28
|
+
|
25
29
|
def output_cli_report(users)
|
26
30
|
users.each do |user|
|
27
31
|
puts user.summary
|
@@ -37,6 +41,9 @@ class Gitalytics
|
|
37
41
|
y.commits.length <=> x.commits.length
|
38
42
|
end
|
39
43
|
@commits = data[:commits]
|
44
|
+
weekday_commits = @users.map(&:weekday_commits)
|
45
|
+
@weekday_commits = weekday_commits.map { |a| Vector[*a] }.inject(:+).to_a
|
46
|
+
|
40
47
|
file.write(erb.result(binding))
|
41
48
|
end
|
42
49
|
open_report_in_browser(output_file) if open_in_browser
|
@@ -52,5 +59,4 @@ class Gitalytics
|
|
52
59
|
system "xdg-open #{filename}"
|
53
60
|
end
|
54
61
|
end
|
55
|
-
|
56
62
|
end
|
File without changes
|
@@ -1,22 +1,22 @@
|
|
1
|
-
require 'commit'
|
2
|
-
require 'user'
|
1
|
+
require 'gitalytics/commit'
|
2
|
+
require 'gitalytics/user'
|
3
3
|
require 'date'
|
4
4
|
|
5
5
|
module GitLog
|
6
6
|
|
7
7
|
module_function
|
8
8
|
|
9
|
-
def parse_git_log
|
9
|
+
def parse_git_log(group_by)
|
10
10
|
users, commits = [], []
|
11
11
|
|
12
12
|
log = get_log
|
13
13
|
blocks = get_blocks(log)
|
14
14
|
|
15
15
|
blocks.each do |(hash, block_string)|
|
16
|
-
commits << parse_block(hash, block_string, users)
|
16
|
+
commits << parse_block(hash, block_string, users, group_by)
|
17
17
|
end
|
18
18
|
|
19
|
-
{
|
19
|
+
{users: users, commits: commits}
|
20
20
|
end
|
21
21
|
|
22
22
|
def get_log
|
@@ -31,7 +31,7 @@ module GitLog
|
|
31
31
|
commits.zip(blocks)
|
32
32
|
end
|
33
33
|
|
34
|
-
def parse_block(hash, block_string, users)
|
34
|
+
def parse_block(hash, block_string, users, group_by)
|
35
35
|
commit = Commit.new(hash)
|
36
36
|
|
37
37
|
block_string.encode!('UTF-8', 'UTF8-MAC') if defined?(Encoding::UTF8_MAC)
|
@@ -41,7 +41,7 @@ module GitLog
|
|
41
41
|
commit.subject = data[:subject]
|
42
42
|
commit.date = Date.parse(data[:date])
|
43
43
|
|
44
|
-
get_commit_author(data, commit, users)
|
44
|
+
get_commit_author(data, commit, users, group_by)
|
45
45
|
get_commit_summary(block_string, commit)
|
46
46
|
|
47
47
|
commit
|
@@ -57,16 +57,22 @@ module GitLog
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def get_commit_author(data, commit, users)
|
61
|
-
user = get_user(data[:name], data[:email], users)
|
60
|
+
def get_commit_author(data, commit, users, group_by)
|
61
|
+
user = get_user(data[:name], data[:email], users, group_by)
|
62
62
|
|
63
63
|
commit.author = user
|
64
64
|
user.commits << commit
|
65
65
|
end
|
66
66
|
|
67
|
-
def get_user(name, email, users)
|
68
|
-
|
69
|
-
|
67
|
+
def get_user(name, email, users, group_by)
|
68
|
+
if group_by == 'name'
|
69
|
+
users.each do |user|
|
70
|
+
return user if user.name == name
|
71
|
+
end
|
72
|
+
elsif group_by == 'email'
|
73
|
+
users.each do |user|
|
74
|
+
return user if user.email == email
|
75
|
+
end
|
70
76
|
end
|
71
77
|
users << new_user = User.new(name, email)
|
72
78
|
new_user
|
@@ -1,19 +1,15 @@
|
|
1
|
+
require 'color-generator'
|
1
2
|
require 'digest/md5'
|
2
|
-
require 'CGI'
|
3
3
|
|
4
4
|
class User
|
5
5
|
|
6
6
|
attr_accessor :name, :email, :commits, :colors
|
7
7
|
|
8
8
|
def initialize(name, email)
|
9
|
-
self.name
|
10
|
-
self.email
|
9
|
+
self.name = name
|
10
|
+
self.email = email
|
11
11
|
self.commits = []
|
12
|
-
self.colors
|
13
|
-
end
|
14
|
-
|
15
|
-
def escaped_name
|
16
|
-
CGI.escapeHTML(name)
|
12
|
+
self.colors = ColorGenerator.new(saturation: 0.3, lightness: 0.75).create_rgb.join(', ')
|
17
13
|
end
|
18
14
|
|
19
15
|
def gravatar
|
@@ -44,8 +40,12 @@ class User
|
|
44
40
|
commits.map(&:deletions).inject(0) { |total, current| total + current }
|
45
41
|
end
|
46
42
|
|
43
|
+
def total_changes
|
44
|
+
total_insertions + total_deletions
|
45
|
+
end
|
46
|
+
|
47
47
|
def summary
|
48
|
-
"#{name} has made #{commits.count} commits
|
48
|
+
"#{name} has made #{commits.count} commits on #{working_days} separate days during a span of #{commits_period} days."
|
49
49
|
end
|
50
50
|
|
51
51
|
def rgba(opacity = 1)
|
@@ -54,8 +54,9 @@ class User
|
|
54
54
|
|
55
55
|
def weekday_commits
|
56
56
|
days = Array.new(7) {0}
|
57
|
-
commits.each
|
57
|
+
commits.each do |c|
|
58
|
+
days[c.date.wday] += 1
|
59
|
+
end
|
58
60
|
days
|
59
61
|
end
|
60
|
-
|
61
62
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'gitalytics/commit'
|
4
|
+
|
5
|
+
class TestCommit < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@commit = Commit.new('abcdef0123456789')
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_commit(commit)
|
12
|
+
commit.summary << {
|
13
|
+
insertions: 3,
|
14
|
+
deletions: 2,
|
15
|
+
filename: 'a.rb'
|
16
|
+
}
|
17
|
+
commit.summary << {
|
18
|
+
insertions: 4,
|
19
|
+
deletions: 3,
|
20
|
+
filename: 'b.rb'
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_that_count_insertions
|
25
|
+
build_commit(@commit)
|
26
|
+
|
27
|
+
assert_equal(7, @commit.insertions)
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_that_count_deletions
|
31
|
+
build_commit(@commit)
|
32
|
+
|
33
|
+
assert_equal(5, @commit.deletions)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_that_count_files_committed
|
37
|
+
build_commit(@commit)
|
38
|
+
|
39
|
+
assert_equal(['a.rb', 'b.rb'], @commit.files_committed)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'gitalytics/gitlog'
|
4
|
+
|
5
|
+
class TestCommit < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def git_log
|
8
|
+
|
9
|
+
%q(bea63e76c7c6d5afd42ac5b24a911b36e5c261f9 2013-02-13 23:11:16 -0200 Gonzalo Robaina <gonzalor@gmail.com> Print basic commit report on the console
|
10
|
+
|
11
|
+
6 1 bin/gitalytics
|
12
|
+
33 6 lib/gitalytics.rb
|
13
|
+
d392710a9e657c72e73ca87df3ed2c8c802441e4 2012-12-19 06:04:59 -0800 Gonzalo Robaina <gonzalor@gmail.com> Initial commit
|
14
|
+
|
15
|
+
16 0 .gitignore
|
16
|
+
4 0 README.md
|
17
|
+
9a99ae5dbc1eaadf268ca925cce9b68d10216151 2012-12-06 10:29:49 -0200 Gonzalo Robaina <gonzalor@gmail.com> initial commit
|
18
|
+
|
19
|
+
1 0 README.md
|
20
|
+
3 0 bin/gitalytics
|
21
|
+
13 0 gitalytics.gemspec
|
22
|
+
49 0 lib/gist.rb
|
23
|
+
11 0 lib/gitalytics.rb
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_get_blocks
|
28
|
+
expected_blocks = [
|
29
|
+
%q(2013-02-13 23:11:16 -0200 Gonzalo Robaina <gonzalor@gmail.com> Print basic commit report on the console
|
30
|
+
|
31
|
+
6 1 bin/gitalytics
|
32
|
+
33 6 lib/gitalytics.rb),
|
33
|
+
|
34
|
+
%q(2012-12-19 06:04:59 -0800 Gonzalo Robaina <gonzalor@gmail.com> Initial commit
|
35
|
+
|
36
|
+
16 0 .gitignore
|
37
|
+
4 0 README.md),
|
38
|
+
|
39
|
+
%q(2012-12-06 10:29:49 -0200 Gonzalo Robaina <gonzalor@gmail.com> initial commit
|
40
|
+
|
41
|
+
1 0 README.md
|
42
|
+
3 0 bin/gitalytics
|
43
|
+
13 0 gitalytics.gemspec
|
44
|
+
49 0 lib/gist.rb
|
45
|
+
11 0 lib/gitalytics.rb)
|
46
|
+
]
|
47
|
+
|
48
|
+
expected_commits = [
|
49
|
+
'bea63e76c7c6d5afd42ac5b24a911b36e5c261f9',
|
50
|
+
'd392710a9e657c72e73ca87df3ed2c8c802441e4',
|
51
|
+
'9a99ae5dbc1eaadf268ca925cce9b68d10216151',
|
52
|
+
]
|
53
|
+
blocks = GitLog.get_blocks(git_log)
|
54
|
+
|
55
|
+
assert_equal(expected_commits, blocks.map(&:first))
|
56
|
+
assert_equal(expected_blocks, blocks.map(&:last))
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_parse_block
|
60
|
+
blocks = GitLog.get_blocks(git_log)
|
61
|
+
hash, block = blocks.last
|
62
|
+
|
63
|
+
users = []
|
64
|
+
commit = GitLog.parse_block(hash, block, users, 'email')
|
65
|
+
|
66
|
+
assert_equal(
|
67
|
+
['README.md', 'bin/gitalytics', 'gitalytics.gemspec', 'lib/gist.rb', 'lib/gitalytics.rb'],
|
68
|
+
commit.files_committed
|
69
|
+
)
|
70
|
+
assert_equal(77, commit.insertions)
|
71
|
+
assert_equal(0, commit.deletions)
|
72
|
+
assert_equal('Gonzalo Robaina', commit.author.name)
|
73
|
+
assert_equal('gonzalor@gmail.com', commit.author.email)
|
74
|
+
assert_equal('initial commit', commit.subject)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_get_user_creates_the_user
|
78
|
+
users = []
|
79
|
+
user = GitLog.get_user('name', 'email@example.com', users, 'name')
|
80
|
+
|
81
|
+
assert_equal(1, users.count)
|
82
|
+
assert_equal(user, users.last)
|
83
|
+
assert_equal('name', user.name)
|
84
|
+
assert_equal('email@example.com', user.email)
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_get_user_returns_the_user
|
88
|
+
users = [User.new('name', 'email@example.com')]
|
89
|
+
|
90
|
+
user = GitLog.get_user('name', 'email@example.com', users, 'email')
|
91
|
+
assert_equal(user, users.last)
|
92
|
+
assert_equal('name', user.name)
|
93
|
+
assert_equal('email@example.com', user.email)
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_get_commit_author_links_user_and_commit
|
97
|
+
data = { name: 'test', email: 'test@email.com' }
|
98
|
+
commit = Commit.new(hash)
|
99
|
+
users = []
|
100
|
+
|
101
|
+
GitLog.get_commit_author(data, commit, users, 'name')
|
102
|
+
assert_equal(users.last, commit.author)
|
103
|
+
assert_equal(users.last.commits.last, commit)
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'test_helper.rb')
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'gitalytics/user'
|
4
|
+
require 'gitalytics/commit'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
class TestUser < MiniTest::Unit::TestCase
|
8
|
+
|
9
|
+
def setup
|
10
|
+
@user = User.new('John Doe', 'john@doe.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_commit(hash, date, summary_data)
|
14
|
+
Commit.new(hash).tap do |commit|
|
15
|
+
commit.date = Date.parse(date)
|
16
|
+
summary_data.each { |summary| commit.summary << summary }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_commits(user)
|
21
|
+
user.commits << create_commit('abcdef', '2000-01-10', [{ # weekday: 1
|
22
|
+
filename: 'a.rb',
|
23
|
+
insertions: 1,
|
24
|
+
deletions: 0,
|
25
|
+
}])
|
26
|
+
user.commits << create_commit('abcdef', '2000-01-01', [{ # weekday: 6
|
27
|
+
filename: 'c.rb',
|
28
|
+
insertions: 0,
|
29
|
+
deletions: 1,
|
30
|
+
}])
|
31
|
+
user.commits << create_commit('abcdef', '2000-01-01', [{ # weekday: 6
|
32
|
+
filename: 'd.rb',
|
33
|
+
insertions: 4,
|
34
|
+
deletions: 5
|
35
|
+
}])
|
36
|
+
user.commits << create_commit('abcdef', '2000-01-08', [{ # weekday: 6
|
37
|
+
filename: 'e.rb',
|
38
|
+
insertions: 1,
|
39
|
+
deletions: 1
|
40
|
+
}])
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_initial_color
|
44
|
+
assert_match(/\d{1,3}, \d{1,3}, \d{1,3}/, @user.colors)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_gravatar_is_md5
|
48
|
+
assert_match(/[a-f0-9]{32}/, @user.gravatar)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_first_commit
|
52
|
+
create_commits(@user)
|
53
|
+
|
54
|
+
assert_equal(Date.parse('2000-1-1'), @user.first_commit.date)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_last_commit
|
58
|
+
create_commits(@user)
|
59
|
+
|
60
|
+
assert_equal(Date.parse('2000-1-10'), @user.last_commit.date)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_working_days
|
64
|
+
create_commits(@user)
|
65
|
+
|
66
|
+
assert_equal(3, @user.working_days)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_weekday_commits
|
70
|
+
create_commits(@user)
|
71
|
+
|
72
|
+
assert_equal([0, 1, 0, 0, 0, 0, 3], @user.weekday_commits)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_total_insertions
|
76
|
+
create_commits(@user)
|
77
|
+
|
78
|
+
assert_equal(6, @user.total_insertions)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_total_deletions
|
82
|
+
create_commits(@user)
|
83
|
+
|
84
|
+
assert_equal(7, @user.total_deletions)
|
85
|
+
end
|
86
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gitalytics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Robaina
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2016-07-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: color-generator
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
13
55
|
description: Get usefull analytics from your git log
|
14
56
|
email: gonzalor@gmail.com
|
15
57
|
executables:
|
@@ -17,13 +59,27 @@ executables:
|
|
17
59
|
extensions: []
|
18
60
|
extra_rdoc_files: []
|
19
61
|
files:
|
62
|
+
- ".coveralls.yml"
|
63
|
+
- ".gitignore"
|
64
|
+
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
66
|
+
- Gemfile
|
67
|
+
- Gemfile.lock
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
20
70
|
- assets/gitalytics.html.erb
|
21
71
|
- bin/gitalytics
|
22
|
-
-
|
72
|
+
- gitalytics.gemspec
|
23
73
|
- lib/gitalytics.rb
|
24
|
-
- lib/
|
25
|
-
- lib/
|
26
|
-
|
74
|
+
- lib/gitalytics/commit.rb
|
75
|
+
- lib/gitalytics/gitlog.rb
|
76
|
+
- lib/gitalytics/user.rb
|
77
|
+
- lib/gitalytics/version.rb
|
78
|
+
- test/lib/test_commit.rb
|
79
|
+
- test/lib/test_gitlog.rb
|
80
|
+
- test/lib/test_user.rb
|
81
|
+
- test/test_helper.rb
|
82
|
+
homepage: http://gonza.uy/gitalytics
|
27
83
|
licenses:
|
28
84
|
- MIT
|
29
85
|
metadata: {}
|
@@ -33,18 +89,22 @@ require_paths:
|
|
33
89
|
- lib
|
34
90
|
required_ruby_version: !ruby/object:Gem::Requirement
|
35
91
|
requirements:
|
36
|
-
- -
|
92
|
+
- - ">="
|
37
93
|
- !ruby/object:Gem::Version
|
38
|
-
version:
|
94
|
+
version: 1.9.3
|
39
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
96
|
requirements:
|
41
|
-
- -
|
97
|
+
- - ">="
|
42
98
|
- !ruby/object:Gem::Version
|
43
99
|
version: '0'
|
44
100
|
requirements: []
|
45
101
|
rubyforge_project:
|
46
|
-
rubygems_version: 2.4.
|
102
|
+
rubygems_version: 2.4.3
|
47
103
|
signing_key:
|
48
104
|
specification_version: 4
|
49
105
|
summary: Git Analytics
|
50
|
-
test_files:
|
106
|
+
test_files:
|
107
|
+
- test/lib/test_commit.rb
|
108
|
+
- test/lib/test_gitlog.rb
|
109
|
+
- test/lib/test_user.rb
|
110
|
+
- test/test_helper.rb
|