we-github-stats 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1 @@
1
+ 2.3.1
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "we/github_stats"
5
+
6
+ cli = We::GitHubStats::Cli.new
7
+ cli.parse(ARGV)
8
+ exit cli.run
@@ -0,0 +1,4 @@
1
+ require "we/github_stats/cli"
2
+ require "we/github_stats/organization"
3
+ require "we/github_stats/repository"
4
+ require "we/github_stats/version"
@@ -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,5 @@
1
+ module We
2
+ module GitHubStats
3
+ VERSION = "0.1.0"
4
+ end
5
+ 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: []