we-github-stats 0.1.0

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,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: []