github_repo_statistics 2.2.14 → 2.2.16

Sign up to get free protection for your applications and to get access to all the features.
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