we-github-stats 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +64 -0
- data/bin/github_stats +8 -0
- data/lib/we/github_stats.rb +4 -0
- data/lib/we/github_stats/cli.rb +152 -0
- data/lib/we/github_stats/organization.rb +22 -0
- data/lib/we/github_stats/repository.rb +66 -0
- data/lib/we/github_stats/version.rb +5 -0
- data/we-github-stats.gemspec +27 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8128f46c7ff0afc6df17f658a42d1fb8bceb26fc
|
4
|
+
data.tar.gz: cdfc79c21477edc2b9e32d745d87fa3253d91adb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 831c440c12cb77d1f0b281aca0bd7291d18396f148e7f0e8ea924b0580d95e87b3222fb7de520b9c816a8d66aa98d8ce912491e03958f96192052d053f662a4f
|
7
|
+
data.tar.gz: 792975e154c901fc8b44897539831f61c85cf376ccd15173a6060626ed116755ca7a0580bf630d5c5729ce22428bbe0f58ca48947b7e53d44f65510db3ab3508
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.3.1
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
we-github-stats (0.1.0)
|
5
|
+
faraday-http-cache
|
6
|
+
octokit (~> 4.0)
|
7
|
+
terminal-table
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.5.0)
|
13
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
14
|
+
byebug (9.0.5)
|
15
|
+
coderay (1.1.1)
|
16
|
+
diff-lcs (1.2.5)
|
17
|
+
faraday (0.10.0)
|
18
|
+
multipart-post (>= 1.2, < 3)
|
19
|
+
faraday-http-cache (2.0.0)
|
20
|
+
faraday (~> 0.8)
|
21
|
+
method_source (0.8.2)
|
22
|
+
multipart-post (2.0.0)
|
23
|
+
octokit (4.6.2)
|
24
|
+
sawyer (~> 0.8.0, >= 0.5.3)
|
25
|
+
pry (0.10.4)
|
26
|
+
coderay (~> 1.1.0)
|
27
|
+
method_source (~> 0.8.1)
|
28
|
+
slop (~> 3.4)
|
29
|
+
pry-byebug (3.4.0)
|
30
|
+
byebug (~> 9.0)
|
31
|
+
pry (~> 0.10)
|
32
|
+
public_suffix (2.0.4)
|
33
|
+
rspec (3.5.0)
|
34
|
+
rspec-core (~> 3.5.0)
|
35
|
+
rspec-expectations (~> 3.5.0)
|
36
|
+
rspec-mocks (~> 3.5.0)
|
37
|
+
rspec-core (3.5.4)
|
38
|
+
rspec-support (~> 3.5.0)
|
39
|
+
rspec-expectations (3.5.0)
|
40
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
+
rspec-support (~> 3.5.0)
|
42
|
+
rspec-mocks (3.5.0)
|
43
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
44
|
+
rspec-support (~> 3.5.0)
|
45
|
+
rspec-support (3.5.0)
|
46
|
+
sawyer (0.8.1)
|
47
|
+
addressable (>= 2.3.5, < 2.6)
|
48
|
+
faraday (~> 0.8, < 1.0)
|
49
|
+
slop (3.6.0)
|
50
|
+
terminal-table (1.7.3)
|
51
|
+
unicode-display_width (~> 1.1.1)
|
52
|
+
unicode-display_width (1.1.2)
|
53
|
+
|
54
|
+
PLATFORMS
|
55
|
+
ruby
|
56
|
+
|
57
|
+
DEPENDENCIES
|
58
|
+
bundler (~> 1.12)
|
59
|
+
pry-byebug
|
60
|
+
rspec (~> 3.0)
|
61
|
+
we-github-stats!
|
62
|
+
|
63
|
+
BUNDLED WITH
|
64
|
+
1.13.6
|
data/bin/github_stats
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'optparse'
|
3
|
+
require 'octokit'
|
4
|
+
require 'faraday-http-cache'
|
5
|
+
require 'terminal-table'
|
6
|
+
|
7
|
+
module We
|
8
|
+
module GitHubStats
|
9
|
+
class Cli
|
10
|
+
OK = 1
|
11
|
+
NOPE = 0
|
12
|
+
|
13
|
+
class ScriptOptions
|
14
|
+
attr_accessor :access_token, :organization, :format
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@format = 'console'
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_options(parser)
|
21
|
+
parser.banner = "Usage: github_stats [options]"
|
22
|
+
parser.separator ""
|
23
|
+
parser.separator "Specific options:"
|
24
|
+
|
25
|
+
parser.on(
|
26
|
+
"-o", "--organization wework",
|
27
|
+
"GitHub organization to troll for stats"
|
28
|
+
) do |o|
|
29
|
+
@organization = o
|
30
|
+
end
|
31
|
+
|
32
|
+
parser.on(
|
33
|
+
"-t", "--token ABC123",
|
34
|
+
"GitHub Access Token with read permissions for the organization"
|
35
|
+
) do |t|
|
36
|
+
@access_token = t
|
37
|
+
end
|
38
|
+
|
39
|
+
parser.on(
|
40
|
+
"-f", "--format console",
|
41
|
+
"How should it be output? Supported: console,csv"
|
42
|
+
) do |f|
|
43
|
+
@format = f
|
44
|
+
end
|
45
|
+
|
46
|
+
parser.on_tail("-h", "--help", "Show this message") do
|
47
|
+
puts parser
|
48
|
+
exit
|
49
|
+
end
|
50
|
+
|
51
|
+
parser.on_tail("--version", "Show version") do
|
52
|
+
puts VERSION
|
53
|
+
exit
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
attr_reader :parser, :options
|
58
|
+
end
|
59
|
+
|
60
|
+
def client(access_token)
|
61
|
+
Octokit.auto_paginate = true
|
62
|
+
stack = Faraday::RackBuilder.new do |builder|
|
63
|
+
builder.use Faraday::HttpCache, serializer: Marshal, shared_cache: false
|
64
|
+
builder.use Octokit::Response::RaiseError
|
65
|
+
builder.adapter Faraday.default_adapter
|
66
|
+
end
|
67
|
+
Octokit.middleware = stack
|
68
|
+
|
69
|
+
Octokit::Client.new(access_token: access_token)
|
70
|
+
end
|
71
|
+
|
72
|
+
#
|
73
|
+
# Return a structure describing the options.
|
74
|
+
#
|
75
|
+
def parse(args)
|
76
|
+
@options = ScriptOptions.new
|
77
|
+
@args = OptionParser.new do |parser|
|
78
|
+
@options.define_options(parser)
|
79
|
+
parser.parse!(args)
|
80
|
+
end
|
81
|
+
@options
|
82
|
+
end
|
83
|
+
|
84
|
+
def error(msg)
|
85
|
+
puts msg
|
86
|
+
return NOPE
|
87
|
+
end
|
88
|
+
|
89
|
+
def run
|
90
|
+
return error("Missing --token option") if @options.access_token.nil?
|
91
|
+
return error("Missing --organization option") if @options.organization.nil?
|
92
|
+
|
93
|
+
organization = Organization.new(
|
94
|
+
name: @options.organization,
|
95
|
+
client: client(@options.access_token)
|
96
|
+
)
|
97
|
+
|
98
|
+
incomplete = []
|
99
|
+
|
100
|
+
subtotals = organization.repos.map do |repo|
|
101
|
+
begin
|
102
|
+
repo_stats = {
|
103
|
+
name: repo.name,
|
104
|
+
num_commits: repo.num_commits,
|
105
|
+
num_lines_added: repo.num_lines_added,
|
106
|
+
num_lines_removed: repo.num_lines_removed,
|
107
|
+
}
|
108
|
+
|
109
|
+
rescue Repository::InProgressError
|
110
|
+
incomplete << repo.name
|
111
|
+
end
|
112
|
+
repo_stats
|
113
|
+
end.compact
|
114
|
+
|
115
|
+
if incomplete != []
|
116
|
+
puts "ERROR! The following stats are not ready on the GitHub API:"
|
117
|
+
incomplete.each { |repo_name| puts "\t- #{repo_name}" }
|
118
|
+
puts "Please wait a few minutes and try again. In the meantime, the stats for other repos is..."
|
119
|
+
end
|
120
|
+
|
121
|
+
if @options.format == 'console'
|
122
|
+
|
123
|
+
puts "==== Repositories ===="
|
124
|
+
|
125
|
+
rows = subtotals.map { |r| [r[:name], r[:num_commits].to_i, r[:num_lines_added].to_i, r[:num_lines_removed].to_i] }
|
126
|
+
|
127
|
+
puts Terminal::Table.new(
|
128
|
+
headings: ['Name', 'Commits', 'Lines Added', 'Lines Removed'],
|
129
|
+
rows: rows
|
130
|
+
)
|
131
|
+
|
132
|
+
total_commits = subtotals.map { |r| r[:num_commits].to_i }.reduce(:+)
|
133
|
+
total_lines_added = subtotals.map { |r| r[:num_lines_added].to_i }.reduce(:+)
|
134
|
+
total_lines_removed = subtotals.map { |r| r[:num_lines_removed].to_i }.reduce(:+)
|
135
|
+
|
136
|
+
puts "==== Total ===="
|
137
|
+
puts "Commits: #{total_commits}"
|
138
|
+
puts "Lines Added: #{total_lines_added}"
|
139
|
+
puts "Lines Removed: #{total_lines_removed}"
|
140
|
+
return OK
|
141
|
+
|
142
|
+
elsif @options.format == 'csv'
|
143
|
+
puts 'Name, Commits, Lines Added, Lines Removed'
|
144
|
+
subtotals.each { |s| puts "#{s[:name]},#{s[:num_commits]},#{s[:num_lines_added]},#{s[:num_lines_removed]}" }
|
145
|
+
return OK
|
146
|
+
end
|
147
|
+
|
148
|
+
return error("Unknown output format selected")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module We
|
2
|
+
module GitHubStats
|
3
|
+
class Organization
|
4
|
+
def initialize(client:, name:)
|
5
|
+
@client = client
|
6
|
+
@name = name
|
7
|
+
end
|
8
|
+
|
9
|
+
def repos
|
10
|
+
@repos ||= begin
|
11
|
+
client.org_repos(name).compact.reject(&:fork).map do |repo|
|
12
|
+
Repository.new(client: client, name: repo.name, full_name: repo.full_name)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :client, :name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module We
|
2
|
+
module GitHubStats
|
3
|
+
class Repository
|
4
|
+
class InProgressError < StandardError; end
|
5
|
+
|
6
|
+
def initialize(client:, name:, full_name:)
|
7
|
+
@client = client
|
8
|
+
@full_name = full_name
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :name, :full_name
|
13
|
+
|
14
|
+
def num_commits
|
15
|
+
fetch_commit_activity && fetch_commit_activity.map(&:total).inject(:+)
|
16
|
+
end
|
17
|
+
|
18
|
+
def num_lines_added
|
19
|
+
fetch_code_frequency && fetch_code_frequency.map { |week| week[1] }.inject(:+)
|
20
|
+
end
|
21
|
+
|
22
|
+
def num_lines_removed
|
23
|
+
fetch_code_frequency && fetch_code_frequency.map { |week| week[2] }.inject(:+)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
attr_reader :client
|
29
|
+
|
30
|
+
def fetch_commit_activity
|
31
|
+
@fetch_commit_activity ||= begin
|
32
|
+
client.commit_activity_stats(full_name).tap do
|
33
|
+
raise InProgressError if stats_building?
|
34
|
+
raise "PANIC!" if error?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def fetch_code_frequency
|
40
|
+
@fetch_code_frequency ||= begin
|
41
|
+
data = client.code_frequency_stats(full_name)
|
42
|
+
|
43
|
+
raise InProgressError if stats_building?
|
44
|
+
raise "PANIC!" if error?
|
45
|
+
|
46
|
+
return nil if data.nil?
|
47
|
+
|
48
|
+
current_date = DateTime.now
|
49
|
+
|
50
|
+
data.reject do |week|
|
51
|
+
days_ago = (current_date - Time.at(week[0]).to_datetime).to_i
|
52
|
+
days_ago > 365
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def stats_building?
|
58
|
+
client.last_response.status == 202
|
59
|
+
end
|
60
|
+
|
61
|
+
def error?
|
62
|
+
client.last_response.status >= 400
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
|
2
|
+
# coding: utf-8
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'we/github_stats/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'we-github-stats'
|
9
|
+
spec.version = We::GitHubStats::VERSION
|
10
|
+
spec.authors = ['Phil Sturgeon']
|
11
|
+
spec.email = ['phil.sturgeon@wework.com']
|
12
|
+
spec.summary = %q{What did your organization get up to this year}
|
13
|
+
spec.description = %q{Pull basic statistics on the last years worth of commits}
|
14
|
+
spec.homepage = 'https://github.com/wework/we-github-stats'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'bin'
|
18
|
+
spec.executables = ['github_stats']
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
22
|
+
# spec.add_development_dependency 'rspec', '~> 3.0'
|
23
|
+
spec.add_development_dependency 'pry-byebug'
|
24
|
+
spec.add_runtime_dependency 'octokit', '~> 4.0'
|
25
|
+
spec.add_runtime_dependency 'terminal-table'
|
26
|
+
spec.add_runtime_dependency 'faraday-http-cache'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: we-github-stats
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phil Sturgeon
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-29 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.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry-byebug
|
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: octokit
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: terminal-table
|
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: faraday-http-cache
|
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
|
+
description: Pull basic statistics on the last years worth of commits
|
84
|
+
email:
|
85
|
+
- phil.sturgeon@wework.com
|
86
|
+
executables:
|
87
|
+
- github_stats
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".ruby-version"
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- bin/github_stats
|
95
|
+
- lib/we/github_stats.rb
|
96
|
+
- lib/we/github_stats/cli.rb
|
97
|
+
- lib/we/github_stats/organization.rb
|
98
|
+
- lib/we/github_stats/repository.rb
|
99
|
+
- lib/we/github_stats/version.rb
|
100
|
+
- we-github-stats.gemspec
|
101
|
+
homepage: https://github.com/wework/we-github-stats
|
102
|
+
licenses: []
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubyforge_project:
|
120
|
+
rubygems_version: 2.5.1
|
121
|
+
signing_key:
|
122
|
+
specification_version: 4
|
123
|
+
summary: What did your organization get up to this year
|
124
|
+
test_files: []
|