git_team_stats 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5157e6d24bbac821867bd8c7dd0384a3202169db
4
+ data.tar.gz: 136c1b15bcf2263f886c67685dd5b95cc032dd53
5
+ SHA512:
6
+ metadata.gz: fdda33147352b1d66709a865b84e03428bb6a2068486cce3104d2fa00412f9b829d75d1eb7410a75200d470a4874cc694af657578f0987c9d5a00060df6d0f7b
7
+ data.tar.gz: 8d2d3ac426e201a568a222e7e923c637736d63e3839401b841bad95f6be34008031e83e849dcfc8b6ff2d4f6a6a9f7446a27a9c5579da58ea07c492bfd3fdbb1
@@ -0,0 +1,28 @@
1
+ {
2
+ "users" : [
3
+ {
4
+ "name" : "you",
5
+ "aliases" : ["Your Alias #1", "yourotheralias"],
6
+ "default" : true
7
+ },
8
+ {
9
+ "name" : "collaborator",
10
+ "aliases" : ["Their alias"]
11
+ }
12
+ ],
13
+ "projects" : [
14
+ {
15
+ "name" : "project 1",
16
+ "repos" : ["~/src/proj1", "~/src/dependencies/proj1-dep"],
17
+ "ignored_directories" : ["Some/directory/you/forgot/to/gitignore/"],
18
+ "default" : true,
19
+ "start_date" : 1369253382,
20
+ "end_date" : 1369356790
21
+ },
22
+ {
23
+ "name" : "Other project",
24
+ "repos" : ["~/src/OtherProject"],
25
+ "ignored_directories" : []
26
+ }
27
+ ]
28
+ }
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .git_team_stats.json
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git_team_stats.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Simon Holroyd
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,206 @@
1
+ # GitTeamStats
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'git_team_stats'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install git_team_stats
18
+
19
+
20
+ ## Configure
21
+
22
+ Configuration uses ```.gitstatistics.json``` file. To start, add your own ```.gitstatistics.json``` based off of ```.gitstatistics.json.example``` and edit according to your needs.
23
+
24
+ ```json
25
+ {
26
+ "users" : [
27
+ {
28
+ "name" : "you",
29
+ "aliases" : ["Your Alias #1", "yourotheralias"],
30
+ "default" : true
31
+ },
32
+ {
33
+ "name" : "collaborator",
34
+ "aliases" : ["Their alias"]
35
+ }
36
+ ],
37
+ "projects" : [
38
+ {
39
+ "name" : "project 1",
40
+ "repos" : ["~/src/proj1", "~/src/dependencies/proj1-dep"],
41
+ "ignored_directories" : ["Some/directory/you/forgot/to/gitignore/"],
42
+ "default" : true,
43
+ "start_date" : 1369253382,
44
+ "end_date" : 1369356790
45
+ },
46
+ {
47
+ "name" : "Other project",
48
+ "repos" : ["~/src/OtherProject"],
49
+ "ignored_directories" : []
50
+ }
51
+ ]
52
+ }
53
+ ```
54
+
55
+ ### Defaults
56
+
57
+ If ```projects``` is left empty, the program will default to running on the current working directory
58
+
59
+ ## Usage
60
+
61
+ Basic usage is as follows
62
+
63
+ ```
64
+ $ git_team_stats [global options] command [command options] [arguments...]
65
+ ```
66
+
67
+ ### Options
68
+
69
+ **cache_path**: ```--cache_path=path```
70
+ - The path to your cache files (default: ./tmp)
71
+
72
+ **config_path**: ```--config_path=path```
73
+ - The path to your config file (default: ./.git_team_stats.json)
74
+
75
+ **project**: ```--project=name```
76
+ - The project name to run on (default: none). Make sure you have projects set in your config file.
77
+
78
+ **help**: ```--help```
79
+ - Show this message
80
+
81
+ **ignore_cache**: ```--ignore_cache```
82
+ - A switch to turn off loading from cache
83
+
84
+ **no_cache**: ```--no_cache```
85
+ - A switch to turn off writing to cache
86
+
87
+ ### Commands
88
+
89
+ ##### Count Commits
90
+
91
+ ```
92
+ $ git_team_stats count_commits
93
+ ```
94
+
95
+ Returns the total number of commits across all your repos in the given project
96
+
97
+
98
+ ##### Inspect Commits
99
+
100
+ ```
101
+ $ git_team_stats inspect_commits
102
+ ```
103
+
104
+ Runs the full inspection on your project repos
105
+
106
+
107
+ ##### Team Cumulative Commits
108
+
109
+ ```
110
+ $ git_team_stats team_cumulative_stats
111
+ ```
112
+
113
+ Gather cumulative statistics on the team. Example output:
114
+
115
+ ```
116
+ ~~~ Cumulative Team Statistics ~~~~~~~~
117
+ commits : 1641
118
+ lines : 73630
119
+ edits : 196752
120
+ languages:
121
+ Objective-C
122
+ edits : 127530
123
+ lines : 47940
124
+ Ruby
125
+ edits : 2810
126
+ lines : 2118
127
+ Markdown
128
+ edits : 3592
129
+ lines : 112
130
+ Shell
131
+ edits : 427
132
+ lines : 381
133
+ YAML
134
+ edits : 203
135
+ lines : 165
136
+ PHP
137
+ edits : 16206
138
+ lines : 10630
139
+ SCSS
140
+ edits : 4746
141
+ lines : 3164
142
+ JavaScript
143
+ edits : 12926
144
+ lines : 11672
145
+ JSON
146
+ edits : 7221
147
+ lines : 7183
148
+ ```
149
+
150
+
151
+ ##### User Cumulative Commits
152
+
153
+ ```
154
+ $ git_team_stats user_cumulative_stats [--user]
155
+ ```
156
+
157
+ Gather cumulative statistics on a team member. Note you should either have a default user in your config file or pass a user name in the CLI. Example output:
158
+
159
+ ```
160
+ ~~~ Cumulative User Statistics (Simon Holroyd) ~~~~~~~~
161
+ commits : 839
162
+ lines : 82525
163
+ edits : 110461
164
+ languages:
165
+ Objective-C
166
+ edits : 97762
167
+ lines : 75868
168
+ Markdown
169
+ edits : 1720
170
+ lines : 1696
171
+ PHP
172
+ edits : 1636
173
+ lines : 660
174
+ SCSS
175
+ edits : 1719
176
+ lines : 977
177
+ JavaScript
178
+ edits : 173
179
+ lines : 41
180
+ ```
181
+
182
+
183
+ ##### Team Most Productive Hour
184
+
185
+ Coming soon
186
+
187
+ ##### User Most Productive Hour
188
+
189
+ Coming soon
190
+
191
+ ##### Codebase over time
192
+
193
+ Coming soon
194
+
195
+ ##### User contribution over time
196
+
197
+ Coming soon
198
+
199
+
200
+ ## Contributing
201
+
202
+ 1. Fork it
203
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
204
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
205
+ 4. Push to the branch (`git push origin my-new-feature`)
206
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake'
4
+ require 'json'
5
+ require 'gli'
6
+ require 'progress_bar'
7
+ require 'language_sniffer'
8
+ require 'git_team_stats'
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+ require 'progress_bar'
5
+ require 'language_sniffer'
6
+ require 'gli'
7
+ require 'git_team_stats'
8
+
9
+ include GLI::App
10
+
11
+ program_desc 'Analyze commits and committers in mulitple git repos and output project-level statistics'
12
+
13
+ desc "The path to your config file"
14
+ flag [:config_path], :default_value => File.join(Dir.pwd,'.git_team_stats.json')
15
+ desc "The path to your cache files"
16
+ flag [:cache_path], :default_value => File.join(Dir.pwd,'tmp')
17
+ desc "The time period to group values by"
18
+ flag [:time_period], :default_value => :week
19
+ desc "The project name to run on"
20
+ flag [:project], :default_value => :none
21
+ desc "A switch to turn off loading from cache"
22
+ switch [:ignore_cache]
23
+ desc "A switch to turn off writing to cache"
24
+ switch [:no_cache]
25
+
26
+ pre do |global_options,command,options,args|
27
+ $dir = Dir.pwd
28
+
29
+ $users = []
30
+ $projects = []
31
+ $project = nil
32
+
33
+ if File.exists? global_options[:config_path]
34
+ config = JSON.parse(File.read(global_options[:config_path]), {:symbolize_names => true})
35
+
36
+ $users = (config[:users].empty?) ? [] : config[:users]
37
+ $projects = (config[:projects].empty?) ? [] : config[:projects]
38
+
39
+ end
40
+
41
+
42
+ if $projects.empty?
43
+ $projects.push({
44
+ :name => "current",
45
+ :repos => [Dir.pwd],
46
+ :ignored_directories => [],
47
+ :default => true
48
+ })
49
+ end
50
+
51
+ true
52
+ end
53
+
54
+ def require_user(options)
55
+
56
+ if options[:user] == :none
57
+ if $users.select{ :default == true }.empty?
58
+ help_now!('user is required, either as a command line arg or a default in .git_team_stats.json')
59
+ else
60
+ $user = $users.select{ :default == true }[0]
61
+ end
62
+ else
63
+ $user = {
64
+ :name => options[:user].to_s,
65
+ :aliases => [options[:user].to_s]
66
+ }
67
+ end
68
+
69
+ end
70
+
71
+ def require_project(global_options)
72
+ if global_options[:project] == :none
73
+ if !$projects.select{ |proj| proj[:default] == true }.empty?
74
+ $project = $projects.select{ |proj| proj[:default] == true }[0]
75
+ end
76
+ else
77
+ if !$projects.select{ |proj| proj[:name] == global_options[:project] }.empty?
78
+ $project = $projects.select{ |proj| proj[:name] == global_options[:project] }[0]
79
+ end
80
+ end
81
+ if ($project == nil)
82
+ puts $projects
83
+ help_now!('project is required, either as a command line arg or a default in .git_team_stats.json')
84
+ end
85
+
86
+ GitTeamStats.start($project)
87
+
88
+ load_cache(global_options)
89
+
90
+ end
91
+
92
+ def load_cache(global_options)
93
+ if (global_options[:ignore_cache])
94
+ return
95
+ end
96
+
97
+ cache_file_path = File.join(global_options[:cache_path], GitTeamStats.get_cache_file_name() + '.json')
98
+
99
+ if (File.exist?(cache_file_path))
100
+ output = JSON.parse(File.open(cache_file_path, 'rb').read, {:symbolize_names => true})
101
+ puts "Loading data from cache".color(:yellow)
102
+ GitTeamStats.load_from_cache(output)
103
+ end
104
+
105
+ end
106
+
107
+
108
+ desc "Count the total commits in the project"
109
+ command :count_commits do |c|
110
+ c.action do |global_options,options,args|
111
+ require_project(global_options)
112
+
113
+ GitTeamStats.inspect_commits()
114
+ puts "Total commits : " + GitTeamStats.count_commits().to_s
115
+ end
116
+ end
117
+
118
+ desc "Run the standard project inspection"
119
+ command :inspect_commits do |c|
120
+ c.action do |global_options,options,args|
121
+ require_project(global_options)
122
+
123
+ puts GitTeamStats.inspect_commits()
124
+
125
+ end
126
+ end
127
+
128
+ desc "Gather cumulative statistics on the team"
129
+ command :team_cumulative_stats do |c|
130
+ c.action do |global_options,options,args|
131
+ require_project(global_options)
132
+
133
+ stats = GitTeamStats.team_cumulative_stats()
134
+ puts "~~~ Cumulative Team Statistics ~~~~~~~~".color(:green)
135
+ stats.each{ |key, value|
136
+ if (key == :file_types)
137
+ puts "languages: "
138
+ value.each{ |language, data|
139
+ puts " " + language.to_s
140
+ puts " edits : " + data[:edits].to_s
141
+ puts " lines : " + data[:lines].to_s
142
+ }
143
+ else
144
+ puts key.to_s + " : " + value.to_s
145
+ end
146
+ }
147
+
148
+ end
149
+ end
150
+
151
+ desc "Gather cumulative statistics on a specific user"
152
+ command :user_cumulative_stats do |c|
153
+ c.flag [:user], :default_value => :none
154
+ c.action do |global_options,options,args|
155
+ require_project(global_options)
156
+ require_user(options)
157
+
158
+ stats = GitTeamStats.user_cumulative_stats($user)
159
+ headline = "~~~ Cumulative User Statistics (%s) ~~~~~~~~" % $user[:name].to_s
160
+ puts headline.color(:green)
161
+ stats.each{ |key, value|
162
+ if (key == :file_types)
163
+ puts "languages: "
164
+ value.each{ |language, data|
165
+ puts " " + language.to_s
166
+ puts " edits : " + data[:edits].to_s
167
+ puts " lines : " + data[:lines].to_s
168
+ }
169
+ else
170
+ puts key.to_s + " : " + value.to_s
171
+ end
172
+ }
173
+ end
174
+ end
175
+
176
+
177
+ post do |global_options,command,options,args|
178
+ if (global_options[:no_cache])
179
+ return
180
+ end
181
+
182
+ if (Dir.exist?(global_options[:cache_path]))
183
+ output = GitTeamStats.get_cache_output()
184
+ cache_file_path = File.join(global_options[:cache_path], GitTeamStats.get_cache_file_name() + '.json')
185
+
186
+ if (File.exist?(cache_file_path))
187
+ f = File.open(cache_file_path, "w+")
188
+ else
189
+ f = File.new(cache_file_path, "w+")
190
+ end
191
+ f.write(output.to_json)
192
+ f.close()
193
+
194
+
195
+ else
196
+ puts "Could not cache results, could not write to cache directory".color(:yellow)
197
+ end
198
+
199
+ true
200
+ end
201
+
202
+ on_error do |exception|
203
+ puts exception
204
+ end
205
+
206
+
207
+ exit run(ARGV)
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_team_stats/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git_team_stats"
8
+ spec.version = GitTeamStats::VERSION
9
+ spec.authors = ["Simon Holroyd"]
10
+ spec.email = ["sholroyd@gmail.com"]
11
+ spec.description = %q{git_team_stats is a gem that compiles contribution statistics for projects that span mulitple repos}
12
+ spec.summary = %q{git_team_stats is a gem that compiles contribution statistics for projects that span mulitple repos}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency 'json'
25
+ spec.add_dependency 'progress_bar'
26
+ spec.add_dependency 'rainbow'
27
+ spec.add_dependency 'language_sniffer'
28
+ spec.add_dependency 'gli'
29
+
30
+
31
+ end
@@ -0,0 +1,138 @@
1
+ require "git_team_stats/version"
2
+ require "git_team_stats/git_parse"
3
+
4
+ module GitTeamStats
5
+
6
+ @project = nil
7
+
8
+ @inspected = false
9
+
10
+ def self.start(project)
11
+ @project = project
12
+
13
+ @commits_in_detail = []
14
+
15
+ @project[:parsers] = []
16
+
17
+ @project[:repos].each do |repo|
18
+ @project[:parsers].push(
19
+ GitParse.new(repo)
20
+ )
21
+ end
22
+
23
+ end
24
+
25
+ def self.count_commits
26
+ count = 0
27
+
28
+ if !@inspected
29
+ self.inspect_commits()
30
+ end
31
+
32
+ return @commits_in_detail.length
33
+ end
34
+
35
+ def self.collect_commits
36
+ unless @inspected
37
+
38
+ @project[:parsers].each do |parser|
39
+ parser.get_commits()
40
+ end
41
+ end
42
+ end
43
+
44
+ def self.inspect_commits
45
+ unless @inspected
46
+
47
+ self.collect_commits()
48
+
49
+ @project[:parsers].each do |parser|
50
+ @commits_in_detail += parser.get_commit_details()
51
+ end
52
+
53
+ @inspected = true
54
+ end
55
+ end
56
+
57
+ def self.team_cumulative_stats
58
+ self.inspect_commits()
59
+
60
+ team_cumulative = {
61
+ :commits => 0,
62
+ :lines => 0,
63
+ :edits => 0,
64
+ :file_types => {}
65
+ }
66
+ @commits_in_detail.each do |commit|
67
+ team_cumulative[:commits] += 1
68
+ team_cumulative[:lines] += commit[:lines]
69
+ team_cumulative[:edits] += commit[:edits]
70
+
71
+ commit[:file_types].each do |language, details|
72
+ if team_cumulative[:file_types].key? language
73
+ team_cumulative[:file_types][language][:lines] += details[:lines]
74
+ team_cumulative[:file_types][language][:edits] += details[:edits]
75
+ else
76
+ team_cumulative[:file_types][language] = {
77
+ :lines => details[:lines],
78
+ :edits => details[:edits]
79
+ }
80
+ end
81
+ end
82
+ end
83
+
84
+ return team_cumulative
85
+ end
86
+
87
+ def self.user_cumulative_stats(user)
88
+ self.inspect_commits()
89
+
90
+ user_cumulative = {
91
+ :commits => 0,
92
+ :lines => 0,
93
+ :edits => 0,
94
+ :file_types => {}
95
+ }
96
+ @commits_in_detail.each do |commit|
97
+ if user[:aliases].any?{ |name| name == commit[:committer] }
98
+ user_cumulative[:commits] += 1
99
+ user_cumulative[:lines] += commit[:lines]
100
+ user_cumulative[:edits] += commit[:edits]
101
+
102
+ commit[:file_types].each do |language, details|
103
+ if user_cumulative[:file_types].key? language
104
+ user_cumulative[:file_types][language][:lines] += details[:lines]
105
+ user_cumulative[:file_types][language][:edits] += details[:edits]
106
+ else
107
+ user_cumulative[:file_types][language] = {
108
+ :lines => details[:lines],
109
+ :edits => details[:edits]
110
+ }
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ return user_cumulative
117
+ end
118
+
119
+ def self.get_cache_output
120
+ return @commits_in_detail
121
+ end
122
+
123
+ def self.load_from_cache(data)
124
+ @commits_in_detail = data
125
+ @inspected = true
126
+ end
127
+
128
+ def self.get_cache_file_name
129
+ hash_str = ""
130
+ @project[:parsers].each{ |parser|
131
+ hash_str += parser.get_head_short_hash().to_s + "-"
132
+ }
133
+
134
+ return $project[:name].to_s + "-" + hash_str + @project[:start_date].to_s + '-' + @project[:end_date].to_s
135
+ end
136
+
137
+
138
+ end
@@ -0,0 +1,197 @@
1
+ require 'progress_bar'
2
+ require 'rainbow'
3
+ require 'language_sniffer'
4
+
5
+ class GitParse
6
+
7
+
8
+ def initialize(directory)
9
+ @commits = []
10
+
11
+ @ignored_directories = []
12
+ @start_date = nil
13
+ @end_date = nil
14
+
15
+ @directory = directory
16
+ end
17
+
18
+
19
+ def execute(command, directory = ".")
20
+ directory = `cd #{directory}; #{command}`
21
+ end
22
+
23
+
24
+ def get_commits
25
+
26
+ hash = ""
27
+
28
+ puts "finding commits in #{@directory}".color(:yellow)
29
+ rev_list = get_rev_list()
30
+ bar = ProgressBar.new(rev_list.lines.length, :bar, :percentage, :eta);
31
+ rev_list.lines.each do |line|
32
+ bar.increment!
33
+ if ( line =~ /^commit ([\w]+)/)
34
+ hash = $1
35
+ next
36
+ else hash != ""
37
+ if ( line =~ /^([\d]+)\s(.+)\s<(.+)>$/ )
38
+ timestamp = $1.to_i
39
+ committer = $2
40
+ email = $3
41
+ end
42
+
43
+ @commits.push({
44
+ :hash => hash,
45
+ :committer => committer,
46
+ :path => @directory,
47
+ :timestamp => timestamp,
48
+ })
49
+
50
+ hash = ""
51
+ end
52
+ end
53
+
54
+ return @commits
55
+ end
56
+
57
+
58
+
59
+ def count_commits
60
+ if @commits.empty?
61
+ get_commits()
62
+ end
63
+
64
+ return @commits.count
65
+ end
66
+
67
+ def get_authors
68
+ users = []
69
+ get_authors_from_shortlog().lines.each do |line|
70
+ if !users.any? {|user| user[:name] = line }
71
+ users.push({
72
+ :name => line.strip,
73
+ :aliases => [line.strip]
74
+ })
75
+ end
76
+ end
77
+ return users
78
+ end
79
+
80
+ def get_authors_from_shortlog
81
+ return execute("git shortlog -s | cut -c8-", @directory)
82
+ end
83
+
84
+ def get_head_short_hash
85
+ return execute("git rev-parse --short HEAD", @directory).strip
86
+ end
87
+
88
+ def get_rev_list
89
+ date_str = ""
90
+ if @start_date != nil
91
+ date_str += "--max-age=%s " % [@start_date.to_i.to_s]
92
+ end
93
+ if @end_date != nil
94
+ date_str += "--min-age=%s " % [@end_date.to_i.to_s]
95
+ end
96
+ return execute("git rev-list --reverse --pretty=format:\"%%at %%aN <%%aE>\" %s HEAD" % date_str, @directory)
97
+ end
98
+
99
+ def get_diff_tree(commit_hash)
100
+ return execute("git diff-tree %s --numstat" % commit_hash, @directory)
101
+ end
102
+
103
+ def get_file(commit_hash, file_name)
104
+ return execute("git show %s:%s 2>&1" % [commit_hash, file_name], @directory)
105
+ end
106
+
107
+ def parse_diff_tree(commit_hash)
108
+
109
+ total_lines = 0
110
+ total_edits = 0
111
+ file_types = {}
112
+
113
+ diff_tree = get_diff_tree(commit_hash)
114
+
115
+ diff_tree.lines.each do |line|
116
+
117
+ if ( line =~ /^([\d]+)\s([\d]+)(.*[^\w](\w+))$/)
118
+
119
+ insertions = $1.to_i
120
+ deletions = $2.to_i
121
+
122
+ lines = insertions - deletions
123
+ edits = insertions + deletions
124
+
125
+ file_name = $3.strip!
126
+
127
+ extension = $4
128
+
129
+ if (@ignored_directories.any?{ |obj| (file_name.index(obj) == 0) })
130
+ next
131
+ end
132
+
133
+ language = get_language_for_file(file_name, commit_hash)
134
+
135
+ if language == nil
136
+ next
137
+ end
138
+
139
+ if (file_types.key? language.name.to_sym)
140
+ file_types[language.name.to_sym][:lines] += lines
141
+ file_types[language.name.to_sym][:edits] += edits
142
+ else
143
+ file_types[language.name.to_sym] = {
144
+ :lines => lines,
145
+ :edits => edits
146
+ }
147
+ end
148
+
149
+ total_lines += lines
150
+ total_edits += edits
151
+
152
+
153
+ end
154
+ end
155
+
156
+ return {
157
+ :lines => total_lines,
158
+ :edits => total_edits,
159
+ :file_types => file_types
160
+ }
161
+
162
+ end
163
+
164
+ def get_language_for_file(file_name, commit_hash)
165
+ escaped_file_name = file_name.gsub(/([\[\(\)\]\{\}\*\?\\])/, '\\\\\1')
166
+
167
+ full_file_path = File.join(Dir.home, @directory.gsub(/^~/, ""), file_name)
168
+
169
+ if File.file? full_file_path
170
+ language = LanguageSniffer.detect(full_file_path).language;
171
+ else
172
+ language = LanguageSniffer.detect(full_file_path, :content => get_file(commit_hash, escaped_file_name), :path => full_file_path).language;
173
+ end
174
+
175
+ return language
176
+ end
177
+
178
+ def get_commit_details
179
+
180
+ puts "analyzing commits in #{@directory}".color(:yellow)
181
+
182
+ bar = ProgressBar.new(@commits.length, :bar, :percentage, :eta);
183
+
184
+ @commits.each { |commit|
185
+
186
+ bar.increment!
187
+
188
+ diff_tree = parse_diff_tree(commit[:hash])
189
+
190
+ commit.merge!(diff_tree)
191
+ }
192
+
193
+ return @commits
194
+
195
+ end
196
+
197
+ end
@@ -0,0 +1,3 @@
1
+ module GitTeamStats
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_team_stats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Simon Holroyd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-28 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: json
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'
55
+ - !ruby/object:Gem::Dependency
56
+ name: progress_bar
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rainbow
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: language_sniffer
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: gli
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: git_team_stats is a gem that compiles contribution statistics for projects
112
+ that span mulitple repos
113
+ email:
114
+ - sholroyd@gmail.com
115
+ executables:
116
+ - git_team_stats
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - .git_team_stats.json.example
121
+ - .gitignore
122
+ - Gemfile
123
+ - LICENSE.txt
124
+ - README.md
125
+ - Rakefile
126
+ - bin/git_team_stats
127
+ - git_team_stats.gemspec
128
+ - lib/git_team_stats.rb
129
+ - lib/git_team_stats/git_parse.rb
130
+ - lib/git_team_stats/version.rb
131
+ homepage: ''
132
+ licenses:
133
+ - MIT
134
+ metadata: {}
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - '>='
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubyforge_project:
151
+ rubygems_version: 2.0.0
152
+ signing_key:
153
+ specification_version: 4
154
+ summary: git_team_stats is a gem that compiles contribution statistics for projects
155
+ that span mulitple repos
156
+ test_files: []