github_repo_statistics 2.2.14 → 2.2.16
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/release_merge_report +57 -0
- data/lib/github_repo_statistics/force_merge_report.rb +2 -2
- data/lib/github_repo_statistics/github_repo_statistics.rb +46 -31
- data/lib/github_repo_statistics/release_merge_report.rb +112 -0
- data/lib/github_repo_statistics/review_report.rb +2 -0
- data/lib/github_repo_statistics/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b4d3e1e79a329a849e3dc178cd55be3d0b420738ca81f04e8ac54775f1c92e4c
|
4
|
+
data.tar.gz: e609fbeea3149601a2a14d823d4e5fd47b4f09626b651bab2e419261482018f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba6a269abb17d017b184baf8f68df4f7ed749d9dca1d7a361baa2a1bba3e17de6255cd10379177089e3ac2f2d660ad01ce7862b37f2c67b02a268cac17e8625f
|
7
|
+
data.tar.gz: 5ab0ae384a28af25dde05d51853969213fa941f7f4add7edbe7718d71d4c03f08955c316c8ebe753be77c72756aaec6775c67187724eb72d4055664575ba1bf1
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'date'
|
5
|
+
require 'optparse'
|
6
|
+
require 'pry'
|
7
|
+
require_relative '../lib/github_repo_statistics/version'
|
8
|
+
require_relative '../lib/github_repo_statistics/release_merge_report'
|
9
|
+
|
10
|
+
|
11
|
+
options = {}
|
12
|
+
OptionParser.new do |opts|
|
13
|
+
opts.banner = 'Usage: github_repo_statistics [options]'
|
14
|
+
|
15
|
+
opts.on('--duration-in-days STRING',
|
16
|
+
'Number of days to aggregate the changes for [default: 90]') do |duration_in_days|
|
17
|
+
options[:duration_in_days] = duration_in_days.to_i
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on('--default-branch STRING',
|
21
|
+
'The default branch to pull and run metrics for [default: master]') do |default_branch|
|
22
|
+
options[:default_branch] = default_branch
|
23
|
+
end
|
24
|
+
|
25
|
+
opts.on('--github-token STRING',
|
26
|
+
'GitHub API token [default: ""]') do |github_token|
|
27
|
+
options[:github_token] = github_token
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on('--github-repo STRING',
|
31
|
+
'GitHub repository name and owner (e.g. octokit/octokit) [default: ""]') do |github_repo|
|
32
|
+
options[:github_repo] = github_repo
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on('-v', '--version', 'Display the version of the gem') do
|
36
|
+
puts "github_repo_statistics version #{GithubRepoStatistics::VERSION}"
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on('-h', '--help', 'Display this help message') do
|
41
|
+
puts opts
|
42
|
+
puts <<~EXAMPLES
|
43
|
+
|
44
|
+
Examples:
|
45
|
+
review_report --github-token ghp_bKasj29ndkfdksf3rjt2ngi43j --github-repo octokit/octokit
|
46
|
+
EXAMPLES
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
end.parse!
|
50
|
+
|
51
|
+
DEFAULT_BRANCH = options[:default_branch] || 'master'
|
52
|
+
|
53
|
+
raise 'Please provide GitHub token using --github-token flag' if options[:github_token].nil?
|
54
|
+
raise 'Please provide GitHub repo name using --github-repo flag' if options[:github_repo].nil?
|
55
|
+
raise 'Please provide default GitHub branch using --default-branch flag' if DEFAULT_BRANCH.nil?
|
56
|
+
|
57
|
+
ReleaseMergeReport.new(token: options[:github_token], repo: options[:github_repo], branch_prefix: "release/").report
|
@@ -30,8 +30,6 @@ class ForceMergeReport
|
|
30
30
|
weekly_summaries = Hash.new { |hash, key| hash[key] = { total: 0, failed: 0, workflows: Hash.new(0) } }
|
31
31
|
|
32
32
|
weeks = @duration_in_days / 7
|
33
|
-
require 'pry'
|
34
|
-
binding.pry
|
35
33
|
|
36
34
|
(weekly_pull_requests.keys.sort[-weeks..] || []).each do |month|
|
37
35
|
pull_requests_for_month = weekly_pull_requests[month]
|
@@ -93,6 +91,8 @@ class ForceMergeReport
|
|
93
91
|
puts " - #{workflow}: #{count}"
|
94
92
|
end
|
95
93
|
|
94
|
+
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
95
|
+
|
96
96
|
if ENV['BQ_CREDENTIALS']
|
97
97
|
require "google/cloud/bigquery"
|
98
98
|
require "json"
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'pry'
|
4
4
|
require 'date'
|
5
|
+
require 'csv'
|
5
6
|
|
6
7
|
class GithubRepoStatistics
|
7
8
|
def initialize(directory_path:, duration_in_days:, begin_time:, debug: nil, steps: 1)
|
@@ -145,6 +146,10 @@ class GithubRepoStatistics
|
|
145
146
|
count
|
146
147
|
end
|
147
148
|
|
149
|
+
def count_lines_of_code(file)
|
150
|
+
File.foreach(file).reject { |line| line.match(%r{^\s*(//|/\*.*\*/|\s*$)}) }.count
|
151
|
+
end
|
152
|
+
|
148
153
|
def filter_existing_code_files(files)
|
149
154
|
files.select do |f|
|
150
155
|
next unless File.exist?(f)
|
@@ -242,7 +247,9 @@ class GithubRepoStatistics
|
|
242
247
|
files_with_single_contributor_percentage = (100 - ((files_changed_by_many_teams.to_f / file_count) * 100)).round(2)
|
243
248
|
hotspot_lines = count_hotspot_lines(filtered_files.keys)
|
244
249
|
big_files_count = count_big_files(@directory_path)
|
245
|
-
|
250
|
+
|
251
|
+
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
252
|
+
|
246
253
|
if ENV['BQ_CREDENTIALS']
|
247
254
|
require "google/cloud/bigquery"
|
248
255
|
require "json"
|
@@ -251,38 +258,39 @@ class GithubRepoStatistics
|
|
251
258
|
project_id: "hellofresh-android",
|
252
259
|
credentials: creds
|
253
260
|
)
|
254
|
-
dataset = bigquery.dataset "
|
261
|
+
dataset = bigquery.dataset "github_data"
|
255
262
|
|
256
263
|
files_with_multiple_contributor = file_team_map.count
|
257
264
|
big_files_with_multiple_contributors = filtered_top_touched_files.count
|
258
265
|
total_files_changed = uniq_code_files_with_changes.count
|
259
266
|
|
267
|
+
platform = if @directory_path == 'HelloFresh/HelloFresh/'
|
268
|
+
'ios'
|
269
|
+
elsif @directory_path == 'features/legacy/'
|
270
|
+
'android'
|
271
|
+
end
|
272
|
+
|
260
273
|
query = <<~SQL
|
261
|
-
|
262
|
-
|
263
|
-
ON target.date = source.date AND target.platform = source.platform
|
264
|
-
WHEN MATCHED THEN
|
265
|
-
UPDATE SET
|
266
|
-
target.platform = '#{@directory_path}',
|
267
|
-
target.single_contributor_percentage = #{files_with_single_contributor_percentage},
|
268
|
-
target.files_changed_by_many_teams = #{files_changed_by_many_teams},
|
269
|
-
target.file_count = #{file_count},
|
270
|
-
target.cross_teams_count = #{cross_teams_count},
|
271
|
-
target.single_ownership_teams_count = #{single_ownership_teams_count},
|
272
|
-
target.hotspot_changes_percentage = #{hotspot_changes_percentage},
|
273
|
-
target.churn_count = #{churn_count},
|
274
|
-
target.total_changes = #{total_changes},
|
275
|
-
target.files_with_multiple_contributor = #{files_with_multiple_contributor},
|
276
|
-
target.big_files_with_multiple_contributors = #{big_files_with_multiple_contributors},
|
277
|
-
target.total_files_changed = #{total_files_changed},
|
278
|
-
target.hotspot_lines = #{hotspot_lines},
|
279
|
-
target.big_files_count = #{big_files_count}
|
280
|
-
WHEN NOT MATCHED THEN
|
281
|
-
INSERT (date,platform,single_contributor_percentage,files_changed_by_many_teams,file_count,cross_teams_count,single_ownership_teams_count,hotspot_changes_percentage,churn_count,total_changes,files_with_multiple_contributor,big_files_with_multiple_contributors,total_files_changed,hotspot_lines,big_files_count)
|
282
|
-
VALUES (#{@begin_time}, #{@directory_path}, #{files_with_single_contributor_percentage}, #{files_changed_by_many_teams}, #{file_count}, ##{cross_teams_count}, #{single_ownership_teams_count}, #{hotspot_changes_percentage}, #{churn_count}, #{total_changes}, #{files_with_multiple_contributor}, #{big_files_with_multiple_contributors}, #{total_files_changed}, #{hotspot_lines}, #{big_files_count});
|
274
|
+
INSERT INTO modularization (date, platform, single_contributor_percentage, files_changed_by_many_teams, file_count, cross_teams_count, single_ownership_teams_count, hotspot_changes_percentage, churn_count, total_changes, files_with_multiple_contributor, big_files_with_multiple_contributors, total_files_changed, hotspot_lines, big_files_count)
|
275
|
+
VALUES ('#{@begin_time}', '#{platform}', #{files_with_single_contributor_percentage}, #{files_changed_by_many_teams}, #{file_count}, #{cross_teams_count}, #{single_ownership_teams_count}, #{hotspot_changes_percentage}, #{churn_count}, #{total_changes}, #{files_with_multiple_contributor}, #{big_files_with_multiple_contributors}, #{total_files_changed}, #{hotspot_lines}, #{big_files_count});
|
283
276
|
SQL
|
284
277
|
|
285
278
|
dataset.query(query)
|
279
|
+
|
280
|
+
# delete_query = <<~SQL
|
281
|
+
# DELETE FROM modularization
|
282
|
+
# WHERE CONCAT(DATE(date), ' ', TIME(date)) NOT IN (
|
283
|
+
# SELECT CONCAT(DATE(date), ' ', TIME(date))
|
284
|
+
# FROM modularization AS m1
|
285
|
+
# WHERE TIME(date) = (
|
286
|
+
# SELECT MAX(TIME(date))
|
287
|
+
# FROM modularization AS m2
|
288
|
+
# WHERE DATE(m1.date) = DATE(m2.date)
|
289
|
+
# )
|
290
|
+
# );
|
291
|
+
# SQL
|
292
|
+
|
293
|
+
# dataset.query(delete_query)
|
286
294
|
end
|
287
295
|
|
288
296
|
puts ''
|
@@ -306,23 +314,30 @@ class GithubRepoStatistics
|
|
306
314
|
puts " *Contributors:* #{contributors}"
|
307
315
|
|
308
316
|
if HOTSPOT
|
309
|
-
hotspot_output =
|
317
|
+
hotspot_output = []
|
310
318
|
|
311
319
|
filtered_top_touched_files.each do |line|
|
312
|
-
hotspot_output += "\n"
|
313
320
|
file = line.first
|
314
321
|
contributors = line.last.first
|
322
|
+
lines_of_code = count_lines_of_code(file)
|
315
323
|
commits = line.last.last
|
316
|
-
|
317
|
-
|
324
|
+
owner = find_owner(file:)
|
325
|
+
|
326
|
+
hotspot_output << [file.gsub(@directory_path, ''), contributors, lines_of_code, commits, owner]
|
318
327
|
end
|
319
328
|
|
320
329
|
if FILE_OUTPUT
|
321
|
-
|
322
|
-
|
330
|
+
CSV.open('hotspot.csv', 'w') do |csv|
|
331
|
+
csv << ['File', 'Contributors', 'Lines', 'Commits', 'Owner']
|
332
|
+
hotspot_output.each do |row|
|
333
|
+
csv << row
|
334
|
+
end
|
323
335
|
end
|
324
336
|
else
|
325
|
-
puts
|
337
|
+
puts "\n *Hotspot files(#{filtered_top_touched_files.count}):*\n"
|
338
|
+
hotspot_output.each do |row|
|
339
|
+
puts " #{row[0]} Contributors: #{row[1]} Lines: #{row[2]} Commits: #{row[3]} Owner: #{row[4]}"
|
340
|
+
end
|
326
341
|
end
|
327
342
|
end
|
328
343
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'octokit'
|
2
|
+
require 'json'
|
3
|
+
require 'google/cloud/bigquery'
|
4
|
+
|
5
|
+
class ReleaseMergeReport
|
6
|
+
def initialize(token:, repo:, branch_prefix:)
|
7
|
+
@token = token
|
8
|
+
@repo = repo
|
9
|
+
@branch_prefix = branch_prefix
|
10
|
+
end
|
11
|
+
|
12
|
+
def report
|
13
|
+
branch_counts = count_merged_pull_requests_per_branch
|
14
|
+
grouped_branch_counts = group_branch_counts(branch_counts)
|
15
|
+
require 'pry'
|
16
|
+
binding.pry
|
17
|
+
|
18
|
+
# Print the grouped branch counts
|
19
|
+
puts 'Branches with Merged Pull Requests:'
|
20
|
+
grouped_branch_counts.each do |branch, count|
|
21
|
+
puts "#{branch}: #{count}"
|
22
|
+
end
|
23
|
+
|
24
|
+
ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
25
|
+
|
26
|
+
export_to_bigquery(grouped_branch_counts) if ENV['BQ_CREDENTIALS']
|
27
|
+
|
28
|
+
grouped_branch_counts
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def count_merged_pull_requests_per_branch
|
34
|
+
client = Octokit::Client.new(access_token: @token)
|
35
|
+
client.auto_paginate = true
|
36
|
+
|
37
|
+
tags = client.tags(@repo)
|
38
|
+
branch_counts = Hash.new(0)
|
39
|
+
|
40
|
+
tags.each do |tag|
|
41
|
+
next if !tag.name.match?(/^(v23|v24)\./) && !tag.name.match?(/^(23|24)\./)
|
42
|
+
|
43
|
+
# Extract release version from the tag name
|
44
|
+
release_version = tag.name.gsub('v', '')
|
45
|
+
|
46
|
+
# Construct branch name with the specified prefix
|
47
|
+
branch_name = "#{@branch_prefix}#{release_version}"
|
48
|
+
|
49
|
+
# Count merged pull requests associated with the branch
|
50
|
+
pull_requests = client.pull_requests(@repo, state: 'closed', sort: 'updated', direction: 'desc', base: branch_name)
|
51
|
+
.select { |pr| pr.merged_at }
|
52
|
+
|
53
|
+
branch_counts[branch_name] = pull_requests.size
|
54
|
+
end
|
55
|
+
|
56
|
+
branch_counts
|
57
|
+
end
|
58
|
+
|
59
|
+
def group_branch_counts(branch_counts)
|
60
|
+
patch_counts = Hash.new(0)
|
61
|
+
hotfix_counts = Hash.new { |hash, key| hash[key] = Hash.new(0) }
|
62
|
+
|
63
|
+
branch_counts.each do |branch, count|
|
64
|
+
major_minor_version, patch_version = branch.match(/^#{@branch_prefix}(\d+\.\d+)(?:\.(\d+))?/)&.captures
|
65
|
+
|
66
|
+
if patch_version.nil?
|
67
|
+
# Branch is a patch version
|
68
|
+
patch_counts[major_minor_version] += count
|
69
|
+
elsif count > 0
|
70
|
+
# Branch is a hotfix version
|
71
|
+
hotfix_counts[major_minor_version][patch_version] += count
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sum up the counts for hotfix versions within the same major and minor version
|
76
|
+
hotfix_counts.each do |major_minor_version, hotfixes|
|
77
|
+
hotfix_counts[major_minor_version] = hotfixes.values.sum
|
78
|
+
end
|
79
|
+
|
80
|
+
{ patch_versions: patch_counts, hotfix_versions: hotfix_counts }
|
81
|
+
end
|
82
|
+
|
83
|
+
def export_to_bigquery(branch_counts)
|
84
|
+
require "google/cloud/bigquery"
|
85
|
+
require "json"
|
86
|
+
creds = JSON.parse(ENV['BQ_CREDENTIALS'])
|
87
|
+
bigquery = Google::Cloud::Bigquery.new(
|
88
|
+
project_id: "hellofresh-android",
|
89
|
+
credentials: creds
|
90
|
+
)
|
91
|
+
dataset = bigquery.dataset "github_data"
|
92
|
+
|
93
|
+
date = DateTime.now
|
94
|
+
|
95
|
+
branch_counts.each do |branch, count|
|
96
|
+
query = <<~SQL
|
97
|
+
MERGE INTO release_merges AS target
|
98
|
+
USING (SELECT '#{branch}' AS release, '#{@repo}' AS platform) AS source
|
99
|
+
ON target.release = source.release AND target.platform = source.platform
|
100
|
+
WHEN MATCHED THEN
|
101
|
+
UPDATE SET
|
102
|
+
target.merge_count = #{count},
|
103
|
+
target.timestamp = '#{date}'
|
104
|
+
WHEN NOT MATCHED THEN
|
105
|
+
INSERT (release, merge_count, platform, timestamp)
|
106
|
+
VALUES ('#{branch}', #{count}, '#{@repo}', '#{date}');
|
107
|
+
SQL
|
108
|
+
date -= 7
|
109
|
+
dataset.query(query)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -87,6 +87,8 @@ class ReviewReport
|
|
87
87
|
puts " Reviews with comments: #{reviews_with_comments}"
|
88
88
|
puts " Change requested reviews: #{change_requested_reviews}"
|
89
89
|
|
90
|
+
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
91
|
+
|
90
92
|
if ENV['BQ_CREDENTIALS']
|
91
93
|
require "google/cloud/bigquery"
|
92
94
|
require "json"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github_repo_statistics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Serghei Moret
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: date
|
@@ -87,6 +87,7 @@ executables:
|
|
87
87
|
- console
|
88
88
|
- force_merge_report
|
89
89
|
- github_repo_statistics
|
90
|
+
- release_merge_report
|
90
91
|
- review_report
|
91
92
|
- setup
|
92
93
|
extensions: []
|
@@ -108,12 +109,14 @@ files:
|
|
108
109
|
- bin/console
|
109
110
|
- bin/force_merge_report
|
110
111
|
- bin/github_repo_statistics
|
112
|
+
- bin/release_merge_report
|
111
113
|
- bin/review_report
|
112
114
|
- bin/setup
|
113
115
|
- github_repo_statistics.gemspec
|
114
116
|
- lib/github_repo_statistics.rb
|
115
117
|
- lib/github_repo_statistics/force_merge_report.rb
|
116
118
|
- lib/github_repo_statistics/github_repo_statistics.rb
|
119
|
+
- lib/github_repo_statistics/release_merge_report.rb
|
117
120
|
- lib/github_repo_statistics/review_report.rb
|
118
121
|
- lib/github_repo_statistics/version.rb
|
119
122
|
- sig/github_repo_statistics.rbs
|