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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd2582ff1a032bad4e27ef0529ed83df931ffa781a9e9c2ca59b935ec8620deb
4
- data.tar.gz: 931b612913c053acd5207092a0955c4532b301cfa62391f4314a046114e953c2
3
+ metadata.gz: b4d3e1e79a329a849e3dc178cd55be3d0b420738ca81f04e8ac54775f1c92e4c
4
+ data.tar.gz: e609fbeea3149601a2a14d823d4e5fd47b4f09626b651bab2e419261482018f7
5
5
  SHA512:
6
- metadata.gz: f434060566ac717c0b8542a7825d240e85151fccd5a711cce0050a32764435247b147ec6d80fdb69ecc5fee43dab4a99eba1766557197faf8e4d5d933fe7aa10
7
- data.tar.gz: 1ceeafecbbd2146816d8669e75c2d4fd645322b8c88259937520aeeb9ca11ccee3d9388e4eecf65d36777b95481b5c7ecf548d7499c33b169170245cdb274349
6
+ metadata.gz: ba6a269abb17d017b184baf8f68df4f7ed749d9dca1d7a361baa2a1bba3e17de6255cd10379177089e3ac2f2d660ad01ce7862b37f2c67b02a268cac17e8625f
7
+ data.tar.gz: 5ab0ae384a28af25dde05d51853969213fa941f7f4add7edbe7718d71d4c03f08955c316c8ebe753be77c72756aaec6775c67187724eb72d4055664575ba1bf1
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- github_repo_statistics (2.2.13)
4
+ github_repo_statistics (2.2.15)
5
5
  date
6
6
  faraday-retry
7
7
  google-cloud-bigquery
@@ -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 "modularization"
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
- MERGE INTO modularization AS target
262
- USING (SELECT '#{@begin_time}' AS date, '#{@directory_path}' AS platform) AS source
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 = "\n *Hotspot files(#{filtered_top_touched_files.count}):*\n"
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
- hotspot_output += " #{file.gsub(@directory_path,
317
- '')} Contributors: #{contributors} Commits: #{commits} Owner: #{find_owner(file:)}\n"
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
- File.open('hotspot.txt', 'w') do |f|
322
- f.puts hotspot_output
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 hotspot_output
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"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GithubRepoStatistics
4
- VERSION = '2.2.14'
4
+ VERSION = '2.2.16'
5
5
  end
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.14
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-03-15 00:00:00.000000000 Z
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