gitalytics 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ - require 'haml_helper'
2
+ !!!
3
+ %html{lang: "en"}
4
+ %head
5
+ %meta{content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
6
+ %meta{charset: "utf-8"}/
7
+ %meta{content: "IE=edge", "http-equiv" => "X-UA-Compatible"}/
8
+ %meta{content: "width=device-width, initial-scale=1.0", name: "viewport"}/
9
+ %meta{content: "Gitalytics Report", name: "description"}/
10
+ %meta{content: "Gonzalo Robaina", name: "author"}/
11
+ %title Gitalytics report
12
+ / Bootstrap core CSS
13
+ %link{crossorigin: "anonymous", href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css", integrity: "sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7", rel: "stylesheet"}/
14
+ %link{crossorigin: "anonymous", href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css", integrity: "sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r", rel: "stylesheet"}/
15
+ / HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries
16
+ /[if lt IE 9]
17
+ <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
18
+ <script src="https://oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js"></script>
19
+ = render :css
20
+ %body
21
+ / Wrap all page content here
22
+ #wrap
23
+ / Fixed navbar
24
+ .navbar.navbar-default.navbar-fixed-top{role: "navigation"}
25
+ .container
26
+ .navbar-header
27
+ %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
28
+ %span.sr-only Toggle navigation
29
+ %span.icon-bar
30
+ %span.icon-bar
31
+ %span.icon-bar
32
+ %a.navbar-brand{href: "https://rubygems.org/gems/gitalytics"} Gitalytics
33
+ .collapse.navbar-collapse
34
+ %ul.nav.navbar-nav
35
+ %li.active
36
+ %a{data: {toggle: :tab}, href: "#dashboard"} Dashboard
37
+ %li
38
+ %a{data: {toggle: :tab}, href: "#authors"} Authors
39
+ %li
40
+ %a{data: {toggle: :tab}, href: "#commits"} Commits
41
+ %li
42
+ %a{data: {toggle: :tab}, href: "#dates"} Dates
43
+ / <li><a href="#contact">Contact</a></li>
44
+ / /.nav-collapse
45
+ / Begin page content
46
+ .container
47
+ .tab-content
48
+ = render :dashboard, users: @users, commits: @commits
49
+ = render :authors, users: @users
50
+ = render :commits, commits: @commits
51
+ = render :dates, commits: @commits
52
+ #footer
53
+ .container
54
+ %p.text-muted
55
+ Gitalytics v#{Gitalytics::VERSION} by
56
+ %a{href: "http://gonzalo.robaina.me"} Gonzalo Robaina
57
+ /
58
+ External JavaScript Files
59
+ \==================================================
60
+ %script{src: "https://code.jquery.com/jquery-2.2.4.min.js"}
61
+ %script{crossorigin: "anonymous", integrity: "sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS", src: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"}
62
+ %script{src: "https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.6/Chart.min.js"}
63
+ = render :javascript, { users: @users, weekday_commits: @weekday_commits }
@@ -4,37 +4,46 @@
4
4
  Encoding.default_external = Encoding::UTF_8
5
5
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
6
6
 
7
+ require 'benchmark'
7
8
  require 'optparse'
8
9
  require 'gitalytics'
9
10
 
10
11
  options = {
12
+ benchmark: false,
11
13
  browser: false,
12
14
  format: 'cli',
13
15
  group_by: 'name'
14
16
  }
15
17
 
16
18
  OptionParser.new do |opts|
17
- opts.banner = "Usage: gitalytics [options]"
19
+ opts.banner = 'Usage: gitalytics [options]'
18
20
 
19
- opts.on("-v", "--version", "Display gem version") do |v|
21
+ opts.on('-v', '--version', 'Display gem version') do
20
22
  p "Gitalytics #{Gitalytics::VERSION}"
21
23
  exit
22
24
  end
23
25
 
24
- opts.on("-h", "--html", "Outputs html report and displays it in default web browser") do |v|
26
+ opts.on('-h', '--html', 'Outputs html report and displays it in default web browser') do
25
27
  options[:format] = 'html'
26
28
  options[:browser] = true
27
29
  end
28
30
 
29
- opts.on("-n", "--no-browser", "Do not open html report in browser") do |v|
31
+ opts.on('-n', '--no-browser', 'Do not open html report in browser') do
30
32
  options[:format] = 'html'
31
33
  options[:browser] = false
32
34
  end
33
35
 
34
- opts.on("-e", "--group-email", "Group commits by author's email address") do |v|
36
+ opts.on('-e', '--group-email', "Group commits by author's email address") do
35
37
  options[:group_by] = 'email'
36
38
  end
39
+
40
+ opts.on('-b', '--benchmark', 'Benchmark gitalytics') do
41
+ options[:benchmark] = true
42
+ end
37
43
  end.parse!
38
44
 
39
- Dir.chdir($1 || '.')
40
- Gitalytics.analyze(options)
45
+ if options[:benchmark]
46
+ puts Benchmark.measure { Gitalytics.analyze(options) }
47
+ else
48
+ Gitalytics.analyze(options)
49
+ end
@@ -4,25 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'gitalytics/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "gitalytics"
7
+ spec.name = 'gitalytics'
8
8
  spec.version = Gitalytics::VERSION
9
9
 
10
- spec.authors = ["Gonzalo Robaina"]
11
- spec.email = "gonzalor@gmail.com"
10
+ spec.authors = ['Gonzalo Robaina']
11
+ spec.email = 'gonzalo@robaina.me'
12
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"
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
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0")
19
19
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
20
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
- spec.require_paths = ["lib"]
21
+ spec.require_paths = ['lib']
22
22
 
23
- spec.required_ruby_version = '>= 1.9.3'
23
+ spec.required_ruby_version = '>= 2.0.0'
24
24
 
25
- spec.add_development_dependency "bundler", "~> 1.7"
26
- spec.add_development_dependency "rake", "~> 10.0"
27
- spec.add_dependency "color-generator"
25
+ spec.add_development_dependency 'bundler', '~> 1.7'
26
+ spec.add_development_dependency 'rake', '~> 10.0'
27
+ spec.add_development_dependency 'byebug'
28
+ spec.add_dependency 'color-generator'
29
+ spec.add_dependency 'haml'
28
30
  end
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
 
3
- require 'erb'
3
+ require 'haml'
4
4
  require 'matrix'
5
5
  require 'gitalytics/commit'
6
6
  require 'gitalytics/gitlog'
@@ -8,6 +8,7 @@ require 'gitalytics/user'
8
8
  require 'gitalytics/version'
9
9
 
10
10
  module Gitalytics
11
+ OUTPUT_FILE = 'gitalytics_result.html'.freeze
11
12
 
12
13
  module_function
13
14
 
@@ -32,31 +33,35 @@ module Gitalytics
32
33
  end
33
34
  end
34
35
 
36
+ def prepare_data(data)
37
+ @users = data[:users].sort { |x, y| y.commits.length <=> x.commits.length }
38
+ @commits = data[:commits]
39
+ weekday_commits = @users.map(&:weekday_commits)
40
+ @weekday_commits = weekday_commits.map { |a| Vector[*a] }.inject(:+).to_a
41
+ end
42
+
43
+ def template_file
44
+ dir = File.dirname(__FILE__)
45
+ filepath = File.join(dir, '..', 'assets', 'gitalytics.html.haml')
46
+ File.read(filepath)
47
+ end
48
+
35
49
  def output_html_report(data, open_in_browser)
36
- template_file = File.read(File.join(File.dirname(__FILE__), "..", "assets", "gitalytics.html.erb"))
37
- erb = ERB.new(template_file)
38
- output_file = "gitalytics_result.html"
39
- File.open(output_file, 'w+') do |file|
40
- @users = data[:users].sort do |x, y|
41
- y.commits.length <=> x.commits.length
42
- end
43
- @commits = data[:commits]
44
- weekday_commits = @users.map(&:weekday_commits)
45
- @weekday_commits = weekday_commits.map { |a| Vector[*a] }.inject(:+).to_a
46
-
47
- file.write(erb.result(binding))
50
+ File.open(OUTPUT_FILE, 'w+') do |file|
51
+ prepare_data(data)
52
+ file.write(Haml::Engine.new(template_file).render(self))
48
53
  end
49
- open_report_in_browser(output_file) if open_in_browser
54
+ open_report_in_browser if open_in_browser
50
55
  end
51
56
 
52
- def open_report_in_browser(filename)
53
- host = RbConfig::CONFIG['host_os']
54
- if host =~ /mswin|mingw|cygwin/
55
- system "start #{filename}"
56
- elsif host =~ /darwin/
57
- system "open #{filename}"
58
- elsif host =~ /linux|bsd/
59
- system "xdg-open #{filename}"
57
+ def open_report_in_browser
58
+ case RbConfig::CONFIG['host_os']
59
+ when /mswin|mingw|cygwin/
60
+ system "start #{OUTPUT_FILE}"
61
+ when /darwin/
62
+ system "open #{OUTPUT_FILE}"
63
+ when /linux|bsd/
64
+ system "xdg-open #{OUTPUT_FILE}"
60
65
  end
61
66
  end
62
67
  end
@@ -1,5 +1,4 @@
1
1
  class Commit
2
-
3
2
  attr_accessor :hash, :author, :date, :subject, :summary
4
3
 
5
4
  def initialize(hash)
@@ -8,15 +7,14 @@ class Commit
8
7
  end
9
8
 
10
9
  def insertions
11
- summary.inject(0) { |total, current| total + current[:insertions] }
10
+ summary.inject(0) { |a, e| a + e[:insertions] }
12
11
  end
13
12
 
14
13
  def deletions
15
- summary.inject(0) { |total, current| total + current[:deletions] }
14
+ summary.inject(0) { |a, e| a + e[:deletions] }
16
15
  end
17
16
 
18
17
  def files_committed
19
- summary.map{ |s| s[:filename] }
18
+ summary.map { |s| s[:filename] }
20
19
  end
21
-
22
20
  end
@@ -3,20 +3,19 @@ require 'gitalytics/user'
3
3
  require 'date'
4
4
 
5
5
  module GitLog
6
-
7
6
  module_function
8
7
 
9
- def parse_git_log(group_by)
10
- users, commits = [], []
8
+ @users = []
9
+ @commits = []
11
10
 
12
- log = get_log
13
- blocks = get_blocks(log)
11
+ def parse_git_log(group_by)
12
+ blocks = get_blocks(get_log)
14
13
 
15
14
  blocks.each do |(hash, block_string)|
16
- commits << parse_block(hash, block_string, users, group_by)
15
+ @commits << parse_block(hash, block_string, group_by)
17
16
  end
18
17
 
19
- {users: users, commits: commits}
18
+ { users: @users, commits: @commits }
20
19
  end
21
20
 
22
21
  def get_log
@@ -25,13 +24,13 @@ module GitLog
25
24
 
26
25
  def get_blocks(log_string)
27
26
  commits = log_string.scan(/^([a-f0-9]{40})/).map(&:first)
28
- blocks = log_string.split(/^[a-f0-9]{40}/).map(&:strip)
27
+ blocks = log_string.split(/^[a-f0-9]{40}/).map(&:strip)
29
28
  blocks.shift # get rid of first empty string
30
29
 
31
30
  commits.zip(blocks)
32
31
  end
33
32
 
34
- def parse_block(hash, block_string, users, group_by)
33
+ def parse_block(hash, block_string, group_by)
35
34
  commit = Commit.new(hash)
36
35
 
37
36
  block_string.encode!('UTF-8', 'UTF8-MAC') if defined?(Encoding::UTF8_MAC)
@@ -41,41 +40,39 @@ module GitLog
41
40
  commit.subject = data[:subject]
42
41
  commit.date = Date.parse(data[:date])
43
42
 
44
- get_commit_author(data, commit, users, group_by)
43
+ get_commit_author(data, commit, group_by)
45
44
  get_commit_summary(block_string, commit)
46
45
 
47
46
  commit
48
47
  end
49
48
 
50
49
  def get_commit_summary(block_string, commit)
51
- block_string.scan(/^(?<insertions>\d+)\s+(?<deletions>\d+)\s+(?<filename>.*)$/).each do |summary|
50
+ regex = /^(?<insertions>\d+)\s+(?<deletions>\d+)\s+(?<filename>.*)$/
51
+ block_string.scan(regex).each do |summary|
52
52
  commit.summary << {
53
53
  insertions: summary[0].to_i,
54
54
  deletions: summary[1].to_i,
55
- filename: summary[2],
55
+ filename: summary[2]
56
56
  }
57
57
  end
58
58
  end
59
59
 
60
- def get_commit_author(data, commit, users, group_by)
61
- user = get_user(data[:name], data[:email], users, group_by)
60
+ def get_commit_author(data, commit, group_by)
61
+ user = get_user(data[:name], data[:email], 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, 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
67
+ def get_user(name, email, group_by)
68
+ case group_by
69
+ when 'name'
70
+ u = @users.index { |user| user.name == name }
71
+ when 'email'
72
+ u = @users.index { |user| user.email == email }
76
73
  end
77
- users << new_user = User.new(name, email)
74
+ return @users[u] if u
75
+ @users << new_user = User.new(name, email)
78
76
  new_user
79
77
  end
80
-
81
78
  end
@@ -2,14 +2,15 @@ require 'color-generator'
2
2
  require 'digest/md5'
3
3
 
4
4
  class User
5
-
6
5
  attr_accessor :name, :email, :commits, :colors
7
6
 
8
7
  def initialize(name, email)
9
- self.name = name
10
- self.email = email
8
+ self.name = name
9
+ self.email = email
11
10
  self.commits = []
12
- self.colors = ColorGenerator.new(saturation: 0.3, lightness: 0.75).create_rgb.join(', ')
11
+ self.colors = ColorGenerator.new(saturation: 0.3, lightness: 0.75)
12
+ .create_rgb
13
+ .join(', ')
13
14
  end
14
15
 
15
16
  def gravatar
@@ -33,11 +34,11 @@ class User
33
34
  end
34
35
 
35
36
  def total_insertions
36
- commits.map(&:insertions).inject(0) { |total, current| total + current }
37
+ commits.map(&:insertions).inject(0) { |a, e| a + e }
37
38
  end
38
39
 
39
40
  def total_deletions
40
- commits.map(&:deletions).inject(0) { |total, current| total + current }
41
+ commits.map(&:deletions).inject(0) { |a, e| a + e }
41
42
  end
42
43
 
43
44
  def total_changes
@@ -45,7 +46,8 @@ class User
45
46
  end
46
47
 
47
48
  def summary
48
- "#{name} has made #{commits.count} commits on #{working_days} separate days during a span of #{commits_period} days."
49
+ "#{name} has made #{commits.count} commits on #{working_days} "\
50
+ "separate days during a span of #{commits_period} days."
49
51
  end
50
52
 
51
53
  def rgba(opacity = 1)
@@ -53,10 +55,8 @@ class User
53
55
  end
54
56
 
55
57
  def weekday_commits
56
- days = Array.new(7) {0}
57
- commits.each do |c|
58
- days[c.date.wday] += 1
59
- end
58
+ days = Array.new(7) { 0 }
59
+ commits.each { |c| days[c.date.wday] += 1 }
60
60
  days
61
61
  end
62
62
  end
@@ -1,3 +1,3 @@
1
1
  module Gitalytics
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.1"
3
3
  end
@@ -0,0 +1,8 @@
1
+ module Haml::Helpers
2
+ def render(partial, locals = {})
3
+ dir = File.dirname(__FILE__)
4
+ filepath = File.join(dir, '..', 'assets', "_#{partial}.html.haml")
5
+ file = File.read(filepath)
6
+ Haml::Engine.new(file).render(Object.new, locals)
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ 2013-02-13 23:11:16 -0200 Gonzalo Robaina <gonzalor@gmail.com> Print basic commit report on the console
2
+
3
+ 6 1 bin/gitalytics
4
+ 33 6 lib/gitalytics.rb
@@ -0,0 +1,4 @@
1
+ 2012-12-19 06:04:59 -0800 Gonzalo Robaina <gonzalor@gmail.com> Initial commit
2
+
3
+ 16 0 .gitignore
4
+ 4 0 README.md
@@ -0,0 +1,7 @@
1
+ 2012-12-06 10:29:49 -0200 Gonzalo Robaina <gonzalor@gmail.com> initial commit
2
+
3
+ 1 0 README.md
4
+ 3 0 bin/gitalytics
5
+ 13 0 gitalytics.gemspec
6
+ 49 0 lib/gist.rb
7
+ 11 0 lib/gitalytics.rb
@@ -0,0 +1,15 @@
1
+ bea63e76c7c6d5afd42ac5b24a911b36e5c261f9 2013-02-13 23:11:16 -0200 Gonzalo Robaina <gonzalor@gmail.com> Print basic commit report on the console
2
+
3
+ 6 1 bin/gitalytics
4
+ 33 6 lib/gitalytics.rb
5
+ d392710a9e657c72e73ca87df3ed2c8c802441e4 2012-12-19 06:04:59 -0800 Gonzalo Robaina <gonzalor@gmail.com> Initial commit
6
+
7
+ 16 0 .gitignore
8
+ 4 0 README.md
9
+ 9a99ae5dbc1eaadf268ca925cce9b68d10216151 2012-12-06 10:29:49 -0200 Gonzalo Robaina <gonzalor@gmail.com> initial commit
10
+
11
+ 1 0 README.md
12
+ 3 0 bin/gitalytics
13
+ 13 0 gitalytics.gemspec
14
+ 49 0 lib/gist.rb
15
+ 11 0 lib/gitalytics.rb