github_repo_statistics 2.3.7 → 2.3.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/bin/github_repo_statistics +28 -5
- data/bin/release_merge_report +1 -2
- data/github_repo_statistics.gemspec +2 -2
- data/lib/github_repo_statistics/force_merge_report.rb +46 -48
- data/lib/github_repo_statistics/github_repo_statistics.rb +45 -35
- data/lib/github_repo_statistics/release_merge_report.rb +34 -33
- data/lib/github_repo_statistics/review_report.rb +18 -18
- data/lib/github_repo_statistics/version.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45f9b41fdeece55840918ee51ada62d6c23509620e50c19e5a495df7bea0d0a8
|
4
|
+
data.tar.gz: 1a128c270392e20ed6b0d48db13cac15f3d1dfd41ab5b5f8b0f97d46c263df9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 00c4d3572b32f831af53cec591c415828f1326875794da0df1b1009880ffd90cd1c99c01e8a6cc56b8d40ccd113fae09ecbb65d826ab273e635d1e036d782d29
|
7
|
+
data.tar.gz: ceadd24b9ccc16eedaf41a99e9dc1ef7f7843994b162c0c4a89ba829528197f85715bc29305a0f6a3bbde6436f5aed7ef2ce7a716ff74168f2f72ef79e15554a
|
data/Gemfile.lock
CHANGED
data/bin/github_repo_statistics
CHANGED
@@ -78,6 +78,11 @@ OptionParser.new do |opts|
|
|
78
78
|
options[:code_extension] = code_extension
|
79
79
|
end
|
80
80
|
|
81
|
+
opts.on('--percentile STRING',
|
82
|
+
'The percentile of file changes that are considered to be hotspot [default: "100"]') do |percentile|
|
83
|
+
options[:percentile] = percentile
|
84
|
+
end
|
85
|
+
|
81
86
|
opts.on('--team-to-focus STRING',
|
82
87
|
'The team identifier to focus for the metric collection [default: ""]') do |team_to_focus|
|
83
88
|
options[:team_to_focus] = team_to_focus
|
@@ -93,6 +98,11 @@ OptionParser.new do |opts|
|
|
93
98
|
options[:file_output] = true
|
94
99
|
end
|
95
100
|
|
101
|
+
opts.on('--hotspot-check',
|
102
|
+
'Enables a hotspot check [default:false]') do
|
103
|
+
options[:hotspot_check] = true
|
104
|
+
end
|
105
|
+
|
96
106
|
opts.on('-v', '--version', 'Display the version of the gem') do
|
97
107
|
puts "github_repo_statistics version #{GithubRepoStatistics::VERSION}"
|
98
108
|
exit
|
@@ -124,6 +134,7 @@ EXCLUDED_FILES = options[:excluded_files]
|
|
124
134
|
EXCLUDED_PRS = options[:excluded_prs]
|
125
135
|
TEAM_TO_FOCUS = options[:team_to_focus]
|
126
136
|
CODEOWNER_TO_FOCUS = options[:codeowner_to_focus]
|
137
|
+
PERCENTILE = options[:percentile] || '100'
|
127
138
|
|
128
139
|
unless CI
|
129
140
|
puts "\nDirectory: #{REPO_PATH}\n"
|
@@ -142,8 +153,20 @@ unless CI
|
|
142
153
|
puts "Debug mode is: #{options[:debug] ? 'on' : 'off'}\n\n"
|
143
154
|
end
|
144
155
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
GithubRepoStatistics.new(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH,
|
149
|
-
|
156
|
+
if options[:hotspot_check]
|
157
|
+
feature_branch = `git rev-parse --abbrev-ref HEAD`.chomp
|
158
|
+
changed_files = `git diff --name-only master...#{feature_branch} | grep #{REPO_PATH} | grep '\.swift'`.split
|
159
|
+
branch_hotspot_files = GithubRepoStatistics.new(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH,
|
160
|
+
begin_time: DateTime.now, steps: options[:steps].to_i, debug: options[:debug]).hotspot_check(files: changed_files, branch: feature_branch)
|
161
|
+
system("git checkout #{DEFAULT_BRANCH}", [:out] => File::NULL)
|
162
|
+
system('git pull', %i[out err] => File::NULL)
|
163
|
+
master_hotspot_files = GithubRepoStatistics.new(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH,
|
164
|
+
begin_time: DateTime.now, steps: options[:steps].to_i, debug: options[:debug]).hotspot_check(files: changed_files, branch: DEFAULT_BRANCH)
|
165
|
+
|
166
|
+
raise 'New hotspot was introduced, contact foundation to unblock the PR' if branch_hotspot_files > master_hotspot_files
|
167
|
+
else
|
168
|
+
system("git checkout #{DEFAULT_BRANCH}", [:out] => File::NULL)
|
169
|
+
system('git pull', %i[out err] => File::NULL)
|
170
|
+
GithubRepoStatistics.new(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH,
|
171
|
+
begin_time: DateTime.now, steps: options[:steps].to_i, debug: options[:debug]).contribution_message
|
172
|
+
end
|
data/bin/release_merge_report
CHANGED
@@ -7,7 +7,6 @@ require 'pry'
|
|
7
7
|
require_relative '../lib/github_repo_statistics/version'
|
8
8
|
require_relative '../lib/github_repo_statistics/release_merge_report'
|
9
9
|
|
10
|
-
|
11
10
|
options = {}
|
12
11
|
OptionParser.new do |opts|
|
13
12
|
opts.banner = 'Usage: github_repo_statistics [options]'
|
@@ -54,4 +53,4 @@ raise 'Please provide GitHub token using --github-token flag' if options[:github
|
|
54
53
|
raise 'Please provide GitHub repo name using --github-repo flag' if options[:github_repo].nil?
|
55
54
|
raise 'Please provide default GitHub branch using --default-branch flag' if DEFAULT_BRANCH.nil?
|
56
55
|
|
57
|
-
ReleaseMergeReport.new(token: options[:github_token], repo: options[:github_repo], branch_prefix:
|
56
|
+
ReleaseMergeReport.new(token: options[:github_token], repo: options[:github_repo], branch_prefix: 'release/').report
|
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.require_paths = ['lib']
|
26
26
|
|
27
27
|
spec.add_dependency 'date'
|
28
|
-
spec.add_dependency 'octokit'
|
29
|
-
spec.add_dependency 'pry'
|
30
28
|
spec.add_dependency 'faraday-retry'
|
31
29
|
spec.add_dependency 'google-cloud-bigquery'
|
30
|
+
spec.add_dependency 'octokit'
|
31
|
+
spec.add_dependency 'pry'
|
32
32
|
end
|
@@ -22,9 +22,7 @@ class ForceMergeReport
|
|
22
22
|
# Sort PRs into monthly chunks
|
23
23
|
weekly_pull_requests = pull_requests.group_by { |pr| pr.closed_at.strftime('%Y-%W') }
|
24
24
|
|
25
|
-
if weekly_pull_requests[Time.now.strftime('%Y-%W')].nil?
|
26
|
-
weekly_pull_requests[Time.now.strftime('%Y-%W')] = []
|
27
|
-
end
|
25
|
+
weekly_pull_requests[Time.now.strftime('%Y-%W')] = [] if weekly_pull_requests[Time.now.strftime('%Y-%W')].nil?
|
28
26
|
|
29
27
|
# Initialize a hash to store monthly summaries
|
30
28
|
weekly_summaries = Hash.new { |hash, key| hash[key] = { total: 0, failed: 0, workflows: Hash.new(0) } }
|
@@ -70,15 +68,15 @@ class ForceMergeReport
|
|
70
68
|
# Print details of merged pull requests without meeting the required criteria for the last 6 months
|
71
69
|
next if failed_checks.empty?
|
72
70
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
puts '---'
|
80
|
-
puts
|
71
|
+
next if @ci
|
72
|
+
|
73
|
+
puts "PR ##{pr.number} - Merged at: #{pr.merged_at}"
|
74
|
+
puts 'Failed Checks:'
|
75
|
+
failed_checks.each do |check|
|
76
|
+
puts "- Workflow: #{check.name || check.context}, Conclusion: #{check.conclusion || check.state}"
|
81
77
|
end
|
78
|
+
puts '---'
|
79
|
+
puts
|
82
80
|
end
|
83
81
|
end
|
84
82
|
|
@@ -93,43 +91,43 @@ class ForceMergeReport
|
|
93
91
|
|
94
92
|
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
94
|
+
next unless ENV['BQ_CREDENTIALS']
|
95
|
+
|
96
|
+
require 'google/cloud/bigquery'
|
97
|
+
require 'json'
|
98
|
+
creds = JSON.parse(ENV['BQ_CREDENTIALS'])
|
99
|
+
bigquery = Google::Cloud::Bigquery.new(
|
100
|
+
project_id: 'hellofresh-android',
|
101
|
+
credentials: creds
|
102
|
+
)
|
103
|
+
dataset = bigquery.dataset 'github_data'
|
104
|
+
|
105
|
+
failed_count = summary[:failed]
|
106
|
+
size_check = summary[:workflows]['Mergeable: Size check']
|
107
|
+
sonarqube_check = summary[:workflows]['SonarQube Code Analysis']
|
108
|
+
ui_tests_check = summary[:workflows]['UI Tests']
|
109
|
+
unit_tests_check = summary[:workflows]['Unit Tests']
|
110
|
+
total_prs = summary[:total]
|
111
|
+
|
112
|
+
query = <<~SQL
|
113
|
+
MERGE INTO force_merges AS target
|
114
|
+
USING (SELECT '#{week}' AS calendar_week, '#{@repo}' AS platform) AS source
|
115
|
+
ON target.calendar_week = source.calendar_week AND target.platform = source.platform
|
116
|
+
WHEN MATCHED THEN
|
117
|
+
UPDATE SET
|
118
|
+
target.force_merges_count = #{failed_count},
|
119
|
+
target.ui_tests_count = #{ui_tests_check},
|
120
|
+
target.unit_tests_count = #{unit_tests_check},
|
121
|
+
target.size_check_count = #{size_check},
|
122
|
+
target.sonarqube_count = #{sonarqube_check},
|
123
|
+
target.total_prs = #{total_prs},
|
124
|
+
target.platform = '#{@repo}'
|
125
|
+
WHEN NOT MATCHED THEN
|
126
|
+
INSERT (calendar_week, force_merges_count, ui_tests_count, unit_tests_count, size_check_count, sonarqube_count, total_prs, platform)
|
127
|
+
VALUES ('#{week}', #{failed_count}, #{ui_tests_check}, #{unit_tests_check}, #{size_check}, #{sonarqube_check}, #{total_prs}, '#{@repo}');
|
128
|
+
SQL
|
129
|
+
|
130
|
+
dataset.query(query)
|
133
131
|
end
|
134
132
|
end
|
135
133
|
end
|
@@ -183,23 +183,23 @@ class GithubRepoStatistics
|
|
183
183
|
`git ls-tree -r --name-only $(git rev-list -1 HEAD) -- "#{directory_path}"`
|
184
184
|
end
|
185
185
|
|
186
|
-
def files_with_changes(directory_path:, start_date:, end_date:)
|
187
|
-
`git log origin
|
186
|
+
def files_with_changes(directory_path:, start_date:, end_date:, branch: DEFAULT_BRANCH)
|
187
|
+
`git log origin/#{branch} --name-only --pretty=format:"" --since="#{start_date}" --until="#{end_date}" "#{directory_path}"`
|
188
188
|
end
|
189
189
|
|
190
|
-
def git_commit_count(file:, start_date:, end_date:)
|
191
|
-
`git log origin
|
190
|
+
def git_commit_count(file:, start_date:, end_date:, branch: DEFAULT_BRANCH)
|
191
|
+
`git log origin/#{branch} --since="#{start_date}" --until="#{end_date}" --follow -- "#{file}" | grep -c '^commit'`
|
192
192
|
end
|
193
193
|
|
194
|
-
def git_commit_info(file:, start_date:, end_date:)
|
195
|
-
`git log origin
|
194
|
+
def git_commit_info(file:, start_date:, end_date:, branch: DEFAULT_BRANCH)
|
195
|
+
`git log origin/#{branch} --pretty=format:"%s" --since="#{start_date}" --until="#{end_date}" -- "#{file}"`
|
196
196
|
end
|
197
197
|
|
198
198
|
def new_changes?(file:)
|
199
|
-
git_commit_info(file:, start_date: DateTime.now - 7, end_date: DateTime.now)
|
199
|
+
git_commit_info(file:, start_date: DateTime.now - 7, end_date: DateTime.now) != ''
|
200
200
|
end
|
201
201
|
|
202
|
-
def analyze_changed_files(uniq_code_files_with_changes:, start_date:, end_date:)
|
202
|
+
def analyze_changed_files(uniq_code_files_with_changes:, start_date:, end_date:, branch: DEFAULT_BRANCH)
|
203
203
|
all_teams = []
|
204
204
|
cross_teams_count = 0
|
205
205
|
single_ownership_teams_count = 0
|
@@ -208,8 +208,8 @@ class GithubRepoStatistics
|
|
208
208
|
file_team_map = {}
|
209
209
|
uniq_code_files_with_changes.each do |file|
|
210
210
|
filename = File.basename(file)
|
211
|
-
commit_count = git_commit_count(file:, start_date:, end_date:).to_i
|
212
|
-
git_log = git_commit_info(file:, start_date:, end_date:).split("\n")
|
211
|
+
commit_count = git_commit_count(file:, start_date:, end_date:, branch:).to_i
|
212
|
+
git_log = git_commit_info(file:, start_date:, end_date:, branch:).split("\n")
|
213
213
|
|
214
214
|
if EXCLUDED_PRS
|
215
215
|
excluded_prs = EXCLUDED_PRS.split(',')
|
@@ -218,16 +218,14 @@ class GithubRepoStatistics
|
|
218
218
|
|
219
219
|
prs = git_log.map do |pr|
|
220
220
|
match = pr.match(/#(\d+)/)
|
221
|
-
if match
|
222
|
-
match[0]
|
223
|
-
end
|
221
|
+
match[0] if match
|
224
222
|
end.uniq
|
225
223
|
|
226
224
|
teams = git_log.map do |team|
|
227
225
|
team.match(/#{TEAM_REGEX}/)[0].upcase
|
228
226
|
end.reject { |e| EXCLUSIONS&.include?(e) }
|
229
227
|
|
230
|
-
teams = calculate_percentile(teams,
|
228
|
+
teams = calculate_percentile(teams, PERCENTILE.to_i)
|
231
229
|
|
232
230
|
total_changes += commit_count
|
233
231
|
all_teams << teams
|
@@ -251,7 +249,7 @@ class GithubRepoStatistics
|
|
251
249
|
counts = arr.each_with_object(Hash.new(0)) { |item, hash| hash[item] += 1 }
|
252
250
|
|
253
251
|
# Sort elements by their counts in descending order
|
254
|
-
sorted_counts = counts.sort_by { |
|
252
|
+
sorted_counts = counts.sort_by { |_k, v| -v }.to_h
|
255
253
|
|
256
254
|
# Calculate the cut-off for the percentile
|
257
255
|
total_count = arr.size
|
@@ -295,7 +293,7 @@ class GithubRepoStatistics
|
|
295
293
|
occurrences = all_teams.flatten.compact.tally
|
296
294
|
sorted_occurrences = occurrences.sort_by { |element, count| [-count, element] }
|
297
295
|
contributors = Hash[sorted_occurrences]
|
298
|
-
churn_count = file_team_map.values.map
|
296
|
+
churn_count = file_team_map.values.map(&:last).sum
|
299
297
|
hotspot_changes_percentage = ((churn_count.to_f / total_changes) * 100).round(2)
|
300
298
|
# Filter files based on extension, existence and size
|
301
299
|
filtered_files = filter_files(file_team_map:)
|
@@ -308,14 +306,14 @@ class GithubRepoStatistics
|
|
308
306
|
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
309
307
|
|
310
308
|
if ENV['BQ_CREDENTIALS']
|
311
|
-
require
|
312
|
-
require
|
309
|
+
require 'google/cloud/bigquery'
|
310
|
+
require 'json'
|
313
311
|
creds = JSON.parse(ENV['BQ_CREDENTIALS'])
|
314
312
|
bigquery = Google::Cloud::Bigquery.new(
|
315
|
-
project_id:
|
313
|
+
project_id: 'hellofresh-android',
|
316
314
|
credentials: creds
|
317
315
|
)
|
318
|
-
dataset = bigquery.dataset
|
316
|
+
dataset = bigquery.dataset 'github_data'
|
319
317
|
|
320
318
|
files_with_multiple_contributor = file_team_map.count
|
321
319
|
big_files_with_multiple_contributors = filtered_top_touched_files.count
|
@@ -328,24 +326,24 @@ class GithubRepoStatistics
|
|
328
326
|
end
|
329
327
|
|
330
328
|
query = <<~SQL
|
331
|
-
|
332
|
-
|
329
|
+
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)
|
330
|
+
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});
|
333
331
|
SQL
|
334
332
|
|
335
333
|
dataset.query(query)
|
336
334
|
|
337
|
-
# delete_query = <<~SQL
|
338
|
-
# DELETE FROM modularization
|
339
|
-
# WHERE CONCAT(DATE(date), ' ', TIME(date)) NOT IN (
|
340
|
-
# SELECT CONCAT(DATE(date), ' ', TIME(date))
|
341
|
-
# FROM modularization AS m1
|
342
|
-
# WHERE TIME(date) = (
|
343
|
-
# SELECT MAX(TIME(date))
|
344
|
-
# FROM modularization AS m2
|
345
|
-
# WHERE DATE(m1.date) = DATE(m2.date)
|
346
|
-
# )
|
347
|
-
# );
|
348
|
-
# SQL
|
335
|
+
# delete_query = <<~SQL
|
336
|
+
# DELETE FROM modularization
|
337
|
+
# WHERE CONCAT(DATE(date), ' ', TIME(date)) NOT IN (
|
338
|
+
# SELECT CONCAT(DATE(date), ' ', TIME(date))
|
339
|
+
# FROM modularization AS m1
|
340
|
+
# WHERE TIME(date) = (
|
341
|
+
# SELECT MAX(TIME(date))
|
342
|
+
# FROM modularization AS m2
|
343
|
+
# WHERE DATE(m1.date) = DATE(m2.date)
|
344
|
+
# )
|
345
|
+
# );
|
346
|
+
# SQL
|
349
347
|
|
350
348
|
# dataset.query(delete_query)
|
351
349
|
end
|
@@ -373,7 +371,7 @@ class GithubRepoStatistics
|
|
373
371
|
if HOTSPOT
|
374
372
|
hotspot_output = []
|
375
373
|
|
376
|
-
filter_files(file_team_map
|
374
|
+
filter_files(file_team_map:, size: 0).each do |line|
|
377
375
|
file = line.first
|
378
376
|
contributors = line.last.first
|
379
377
|
lines_of_code = count_lines_of_code(file)
|
@@ -413,4 +411,16 @@ class GithubRepoStatistics
|
|
413
411
|
@begin_time -= duration_in_days
|
414
412
|
contribution_message
|
415
413
|
end
|
414
|
+
|
415
|
+
def hotspot_check(files:, branch:)
|
416
|
+
duration_in_days = @duration_in_days.to_i
|
417
|
+
start_date = @begin_time.to_time.to_i - duration_in_days * 86_400
|
418
|
+
end_date = @begin_time.to_time.to_i
|
419
|
+
|
420
|
+
_, _, _, files_changed_by_many_teams, = analyze_changed_files(
|
421
|
+
uniq_code_files_with_changes: files, start_date:, end_date:, branch:
|
422
|
+
)
|
423
|
+
|
424
|
+
files_changed_by_many_teams
|
425
|
+
end
|
416
426
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'octokit'
|
2
4
|
require 'json'
|
3
5
|
require 'google/cloud/bigquery'
|
@@ -34,7 +36,7 @@ class ReleaseMergeReport
|
|
34
36
|
client.auto_paginate = true
|
35
37
|
|
36
38
|
tags = client.tags(@repo)
|
37
|
-
branch_info = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: []} }
|
39
|
+
branch_info = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: [] } }
|
38
40
|
|
39
41
|
tags.each do |tag|
|
40
42
|
next if !tag.name.match?(/^(v23|v24)\./) && !tag.name.match?(/^(23|24)\./)
|
@@ -47,7 +49,7 @@ class ReleaseMergeReport
|
|
47
49
|
|
48
50
|
# Count merged pull requests associated with the branch
|
49
51
|
pull_requests = client.pull_requests(@repo, state: 'closed', sort: 'updated', direction: 'desc', base: branch_name)
|
50
|
-
.select
|
52
|
+
.select(&:merged_at)
|
51
53
|
|
52
54
|
pull_requests.each do |pr|
|
53
55
|
branch_info[branch_name][:count] += 1
|
@@ -65,8 +67,8 @@ class ReleaseMergeReport
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def group_branch_counts(branch_info)
|
68
|
-
patch_counts = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: []} }
|
69
|
-
hotfix_counts = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: []} }
|
70
|
+
patch_counts = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: [] } }
|
71
|
+
hotfix_counts = Hash.new { |hash, key| hash[key] = { count: 0, teams: [], tribes: [] } }
|
70
72
|
|
71
73
|
branch_info.each do |branch, info|
|
72
74
|
major_minor_version, patch_version = branch.match(/^#{@branch_prefix}(\d+\.\d+)(?:\.(\d+))?/)&.captures
|
@@ -77,8 +79,7 @@ class ReleaseMergeReport
|
|
77
79
|
patch_counts[major_minor_version][:teams] += info[:teams]
|
78
80
|
patch_counts[major_minor_version][:tribes] += info[:tribes]
|
79
81
|
|
80
|
-
|
81
|
-
elsif info[:count] > 0
|
82
|
+
elsif (info[:count]).positive?
|
82
83
|
# Branch is a hotfix version
|
83
84
|
hotfix_counts[major_minor_version][:count] += info[:count]
|
84
85
|
hotfix_counts[major_minor_version][:teams] += info[:teams]
|
@@ -95,14 +96,14 @@ class ReleaseMergeReport
|
|
95
96
|
end
|
96
97
|
|
97
98
|
def export_to_bigquery(branch_counts)
|
98
|
-
require
|
99
|
-
require
|
99
|
+
require 'google/cloud/bigquery'
|
100
|
+
require 'json'
|
100
101
|
creds = JSON.parse(ENV['BQ_CREDENTIALS'])
|
101
102
|
bigquery = Google::Cloud::Bigquery.new(
|
102
|
-
project_id:
|
103
|
+
project_id: 'hellofresh-android',
|
103
104
|
credentials: creds
|
104
105
|
)
|
105
|
-
dataset = bigquery.dataset
|
106
|
+
dataset = bigquery.dataset 'github_data'
|
106
107
|
|
107
108
|
date = DateTime.now
|
108
109
|
|
@@ -113,18 +114,18 @@ class ReleaseMergeReport
|
|
113
114
|
|
114
115
|
# Construct the SQL query
|
115
116
|
query = <<~SQL
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
117
|
+
MERGE INTO release_merges AS target
|
118
|
+
USING (SELECT '#{branch}' AS release, '#{@repo}' AS platform) AS source
|
119
|
+
ON target.release = source.release AND target.platform = source.platform
|
120
|
+
WHEN MATCHED THEN
|
121
|
+
UPDATE SET
|
122
|
+
target.merge_count = #{count[:count]},
|
123
|
+
target.timestamp = '#{date}',
|
124
|
+
target.contributors = ARRAY[#{teams_json}],
|
125
|
+
target.contributors_tribe = ARRAY[#{tribes_json}]
|
126
|
+
WHEN NOT MATCHED THEN
|
127
|
+
INSERT (release, merge_count, platform, timestamp, contributors, contributors_tribe)
|
128
|
+
VALUES ('#{branch}', #{count[:count]}, '#{@repo}', '#{date}', ARRAY[#{teams_json}], ARRAY[#{tribes_json}]);
|
128
129
|
SQL
|
129
130
|
|
130
131
|
# Execute the query
|
@@ -141,17 +142,17 @@ class ReleaseMergeReport
|
|
141
142
|
|
142
143
|
# Construct the SQL query
|
143
144
|
query = <<~SQL
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
145
|
+
MERGE INTO release_merges AS target
|
146
|
+
USING (SELECT '#{branch}' AS release, '#{@repo}' AS platform) AS source
|
147
|
+
ON target.release = source.release AND target.platform = source.platform
|
148
|
+
WHEN MATCHED THEN
|
149
|
+
UPDATE SET
|
150
|
+
target.hotfix_count = #{count[:count]},
|
151
|
+
target.contributors_hotfixes = ARRAY[#{teams_json}],
|
152
|
+
target.contributors_hotfixes_tribe = ARRAY[#{tribes_json}]
|
153
|
+
WHEN NOT MATCHED THEN
|
154
|
+
INSERT (release, hotfix_count, platform, contributors_hotfixes, contributors_hotfixes_tribe )
|
155
|
+
VALUES ('#{branch}', #{count[:count]}, '#{@repo}', ARRAY[#{teams_json}], ARRAY[#{tribes_json}]);
|
155
156
|
SQL
|
156
157
|
|
157
158
|
# Execute the query
|
@@ -90,30 +90,30 @@ class ReviewReport
|
|
90
90
|
# ENV['BQ_CREDENTIALS'] = `cat /Users/serghei.moret/.config/gcloud/application_default_credentials.json`
|
91
91
|
|
92
92
|
if ENV['BQ_CREDENTIALS']
|
93
|
-
require
|
94
|
-
require
|
93
|
+
require 'google/cloud/bigquery'
|
94
|
+
require 'json'
|
95
95
|
creds = JSON.parse(ENV['BQ_CREDENTIALS'])
|
96
96
|
bigquery = Google::Cloud::Bigquery.new(
|
97
|
-
project_id:
|
97
|
+
project_id: 'hellofresh-android',
|
98
98
|
credentials: creds
|
99
99
|
)
|
100
|
-
dataset = bigquery.dataset
|
100
|
+
dataset = bigquery.dataset 'github_data'
|
101
101
|
|
102
102
|
query = <<~SQL
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
103
|
+
MERGE INTO pr_reviews AS target
|
104
|
+
USING (SELECT '#{week}' AS calendar_week, '#{@repo}' AS platform) AS source
|
105
|
+
ON target.calendar_week = source.calendar_week AND target.platform = source.platform
|
106
|
+
WHEN MATCHED THEN
|
107
|
+
UPDATE SET
|
108
|
+
target.change_requested_reviews = #{change_requested_reviews},
|
109
|
+
target.reviews_with_comments = #{reviews_with_comments},
|
110
|
+
target.total_reviews = #{total_reviews},
|
111
|
+
target.average_review_time_hours = #{average_time_hours.round(2)},
|
112
|
+
target.total_prs = #{total_count},
|
113
|
+
target.platform = '#{@repo}'
|
114
|
+
WHEN NOT MATCHED THEN
|
115
|
+
INSERT (calendar_week, total_prs, average_review_time_hours, total_reviews, reviews_with_comments, change_requested_reviews, platform)
|
116
|
+
VALUES ('#{week}', #{total_count}, #{average_time_hours.round(2)}, #{total_reviews}, #{reviews_with_comments}, #{change_requested_reviews}, '#{@repo}');
|
117
117
|
SQL
|
118
118
|
|
119
119
|
dataset.query(query)
|
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.3.
|
4
|
+
version: 2.3.8
|
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-06-
|
11
|
+
date: 2024-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: date
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: faraday-retry
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -39,7 +39,7 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: google-cloud-bigquery
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
@@ -53,7 +53,7 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: octokit
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
@@ -67,7 +67,7 @@ dependencies:
|
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - ">="
|