git_ownership_insights 2.0.3 → 2.0.4

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: b993d413af1897253069cfd6ef12e1ba1b91228d7b72753d08e3a104e8df172b
4
- data.tar.gz: b9ac3f82ee048d2501541672185f36333820c14cbd0da2ae6bd733509bb307d9
3
+ metadata.gz: eb151470ef24ed0e040026ced3fb187e7cc02012ba0564dd062be4611b8219a8
4
+ data.tar.gz: 64b844eebef335350f0fa9fa939c0d338910b5a711652a8c9ba926a7caec3456
5
5
  SHA512:
6
- metadata.gz: 82bc549f312667ca1e3771e9b7fd0427d7ad7950b0981592ae5954bd8860717dff78540d82caee64a5c82b5460ce4b39f6627a89675bb729b95276c2e1625568
7
- data.tar.gz: 5849484323479c350f1cead67c3ea38673ff51dc386b7e6e48f716ef401c64e66ae1e56fefe7223b59c23e59dc098369d1e725dcef45ae94b42dabd3f33e6082
6
+ metadata.gz: f3ab9fa17feabb5b7774f61911ae34dd36605b412a365d3192fb76ec8585569635aa74121b31fb5fbbe67c77fe1b8e77f3983724839a4ff4261b0212f79ccf4d
7
+ data.tar.gz: 4a176d6a400141e7fda5697d53f54ad4f7d599ab1ec85178798ad70c0188a7145aa49a688be37ad3d7c0e33c20a77ae478211dd6a08718625e87de6f4d33455d
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2024-01-30 15:39:52 UTC using RuboCop version 1.60.0.
3
+ # on 2024-01-30 16:41:47 UTC using RuboCop version 1.60.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -13,36 +13,36 @@ Lint/ConstantDefinitionInBlock:
13
13
  Exclude:
14
14
  - 'spec/git_ownership_insights_spec.rb'
15
15
 
16
- # Offense count: 4
16
+ # Offense count: 6
17
17
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
18
18
  Metrics/AbcSize:
19
- Max: 181
19
+ Max: 92
20
20
 
21
21
  # Offense count: 4
22
22
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
23
23
  # AllowedMethods: refine
24
24
  Metrics/BlockLength:
25
- Max: 76
25
+ Max: 75
26
26
 
27
27
  # Offense count: 1
28
28
  # Configuration parameters: CountComments, CountAsOne.
29
29
  Metrics/ClassLength:
30
- Max: 200
30
+ Max: 207
31
31
 
32
- # Offense count: 1
32
+ # Offense count: 2
33
33
  # Configuration parameters: AllowedMethods, AllowedPatterns.
34
34
  Metrics/CyclomaticComplexity:
35
- Max: 28
35
+ Max: 12
36
36
 
37
- # Offense count: 4
37
+ # Offense count: 6
38
38
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
39
39
  Metrics/MethodLength:
40
- Max: 109
40
+ Max: 49
41
41
 
42
42
  # Offense count: 1
43
43
  # Configuration parameters: AllowedMethods, AllowedPatterns.
44
44
  Metrics/PerceivedComplexity:
45
- Max: 29
45
+ Max: 12
46
46
 
47
47
  # Offense count: 1
48
48
  # Configuration parameters: AllowedConstants.
@@ -57,7 +57,7 @@ Style/MultilineBlockChain:
57
57
  Exclude:
58
58
  - 'lib/git_ownership_insights/git_ownership_insight.rb'
59
59
 
60
- # Offense count: 11
60
+ # Offense count: 12
61
61
  # This cop supports safe autocorrection (--autocorrect).
62
62
  # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
63
63
  # URISchemes: http, https
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- git_ownership_insights (2.0.3)
4
+ git_ownership_insights (2.0.4)
5
5
  date
6
6
  pry
7
7
 
@@ -53,6 +53,55 @@ class GitOwnershipInsights
53
53
  codeowners[best_match].split(' ')
54
54
  end
55
55
 
56
+ def handle_codeowners(file_team_map:)
57
+ puts "\n"
58
+ puts '*Code ownership data:*'
59
+ codeowners = read_codeowners_file
60
+
61
+ owners_data = Hash.new do |hash, key|
62
+ hash[key] = { directories: Hash.new do |h, k|
63
+ h[k] = { files: [] }
64
+ end, churn_count: 0 }
65
+ end
66
+
67
+ file_team_map.each do |file, count|
68
+ owners = find_owners(file, codeowners)
69
+ owners.each do |owner|
70
+ owners_data[owner][:churn_count] += count.last
71
+
72
+ dir_path = File.dirname(file)
73
+ owners_data[owner][:directories][dir_path][:files] << { name: File.basename(file), count: }
74
+ end
75
+ end
76
+
77
+ # Sort owners_data by total count in descending order
78
+ sorted_owners_data = owners_data.sort_by { |_, data| -data[:churn_count] }
79
+
80
+ # Take the last 5 elements
81
+ top_owners_data = sorted_owners_data.last(TOP_CONTRIBUTED_TEAMS.to_i)
82
+
83
+ converted_team_map = file_team_map.transform_keys { |key| File.basename(key) }
84
+
85
+ puts ' Codeownership data:'
86
+ top_owners_data.each do |owner, data|
87
+ puts " #{owner.split('/').last}:\n Total Count: #{data[:churn_count]}"
88
+ data[:directories].each do |dir, dir_data|
89
+ puts " Directory: #{dir}\n Top files:"
90
+ dir_data[:files].each do |file_data|
91
+ next if converted_team_map[File.basename(file_data[:name])].nil?
92
+
93
+ contributors = converted_team_map[file_data[:name]]&.first&.empty? ? ['Excluded contributor'] : converted_team_map[file_data[:name]].first
94
+ puts " #{File.basename(file_data[:name])} - #{file_data[:count].last} #{contributors}}"
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ def find_owner(file:)
101
+ codeowners = read_codeowners_file
102
+ find_owners(file, codeowners)
103
+ end
104
+
56
105
  def count_big_files(directory_path, size: BIG_FILE_SIZE)
57
106
  size = size.to_i
58
107
  # Get a list of all files in the specified directory
@@ -125,21 +174,12 @@ class GitOwnershipInsights
125
174
  `git log --pretty=format:"%s" --since="#{start_date}" --until="#{end_date}" --follow -- "#{file}"`
126
175
  end
127
176
 
128
- def contribution_message
129
- duration_in_days = @duration_in_days.to_i
177
+ def analyze_changed_files(uniq_code_files_with_changes:, start_date:, end_date:)
130
178
  all_teams = []
131
179
  cross_teams_count = 0
132
180
  single_ownership_teams_count = 0
133
181
  files_changed_by_many_teams = 0
134
182
  total_changes = 0
135
- start_date = @begin_time.to_time.to_i - duration_in_days * 86_400 - 30 * 86_400
136
- end_date = @begin_time.to_time.to_i - 30 * 86_400
137
- git_ls = git_files(directory_path: @directory_path)
138
- file_count = filter_existing_code_files(git_ls.split).count
139
- all_files_with_changes = files_with_changes(directory_path: @directory_path, start_date:, end_date:).split.sort
140
- code_files_with_changes = filter_existing_code_files(all_files_with_changes)
141
- uniq_code_files_with_changes = code_files_with_changes.uniq
142
-
143
183
  file_team_map = {}
144
184
  uniq_code_files_with_changes.each do |file|
145
185
  filename = File.basename(file)
@@ -163,22 +203,35 @@ class GitOwnershipInsights
163
203
 
164
204
  puts "\n#{filename} [#{commit_count}]:#{teams}\n" if @debug
165
205
  end
206
+ [all_teams, cross_teams_count, single_ownership_teams_count, files_changed_by_many_teams, total_changes, file_team_map]
207
+ end
166
208
 
167
- occurrences = all_teams.flatten.compact.tally
168
- sorted_occurrences = occurrences.sort_by { |element, count| [-count, element] }
169
- contributors = Hash[sorted_occurrences]
170
-
171
- churn_count = file_team_map.values.map { |value| value[1] }.sum
172
- hotspot_changes_percentage = (churn_count.to_f / total_changes) * 100
173
-
174
- # Filter files based on extension and size
175
- filtered_files = file_team_map.select do |file_path|
209
+ def filter_files(file_team_map:)
210
+ file_team_map.select do |file_path|
176
211
  next unless File.exist?(file_path)
177
212
 
178
213
  # Check if the file size is more than BIG_FILE_SIZE lines (excluding empty and commented lines)
179
214
  File.foreach(file_path).reject { |line| line.match(%r{^\s*(//|/\*.*\*/|\s*$)}) }.count > BIG_FILE_SIZE.to_i
180
215
  end
216
+ end
181
217
 
218
+ def contribution_message
219
+ duration_in_days = @duration_in_days.to_i
220
+ start_date = @begin_time.to_time.to_i - duration_in_days * 86_400 - 30 * 86_400
221
+ end_date = @begin_time.to_time.to_i - 30 * 86_400
222
+ git_ls = git_files(directory_path: @directory_path)
223
+ file_count = filter_existing_code_files(git_ls.split).count
224
+ all_files_with_changes = files_with_changes(directory_path: @directory_path, start_date:, end_date:).split.sort
225
+ code_files_with_changes = filter_existing_code_files(all_files_with_changes)
226
+ uniq_code_files_with_changes = code_files_with_changes.uniq
227
+ all_teams, cross_teams_count, single_ownership_teams_count, files_changed_by_many_teams, total_changes, file_team_map = analyze_changed_files(uniq_code_files_with_changes:, start_date:, end_date:)
228
+ occurrences = all_teams.flatten.compact.tally
229
+ sorted_occurrences = occurrences.sort_by { |element, count| [-count, element] }
230
+ contributors = Hash[sorted_occurrences]
231
+ churn_count = file_team_map.values.map { |value| value[1] }.sum
232
+ hotspot_changes_percentage = (churn_count.to_f / total_changes) * 100
233
+ # Filter files based on extension, existence and size
234
+ filtered_files = filter_files(file_team_map:)
182
235
  filtered_top_touched_files = filtered_files.sort_by { |element, count| [-count.last, element] }
183
236
 
184
237
  puts ''
@@ -205,53 +258,15 @@ class GitOwnershipInsights
205
258
  puts "\n"
206
259
  puts ' *Hotspot changes:*'
207
260
  filtered_top_touched_files.each do |line|
208
- puts " #{line.first.gsub(@directory_path, '')} Contributors: #{line.last.first} Commits: #{line.last.last}"
261
+ file = line.first
262
+ contributors = line.last.first
263
+ commits = line.last.last
264
+ puts " #{file.gsub(@directory_path, '')} Contributors: #{contributors} Commits: #{commits} Owner: #{find_owner(file:)}"
209
265
  end
210
266
  end
211
267
 
212
- if CODEOWNERS
213
- puts "\n"
214
- puts '*Code ownership data:*'
215
- codeowners = read_codeowners_file
216
-
217
- owners_data = Hash.new do |hash, key|
218
- hash[key] = { directories: Hash.new do |h, k|
219
- h[k] = { files: [] }
220
- end, churn_count: 0 }
221
- end
222
-
223
- file_team_map.each do |file, count|
224
- owners = find_owners(file, codeowners)
225
- owners.each do |owner|
226
- owners_data[owner][:churn_count] += count.last
227
-
228
- dir_path = File.dirname(file)
229
- owners_data[owner][:directories][dir_path][:files] << { name: File.basename(file), count: }
230
- end
231
- end
232
-
233
- # Sort owners_data by total count in descending order
234
- sorted_owners_data = owners_data.sort_by { |_, data| -data[:churn_count] }
235
-
236
- # Take the last 5 elements
237
- top_owners_data = sorted_owners_data.last(TOP_CONTRIBUTED_TEAMS.to_i)
238
-
239
- converted_team_map = file_team_map.transform_keys { |key| File.basename(key) }
268
+ handle_codeowners(file_team_map:) if CODEOWNERS
240
269
 
241
- puts ' Codeownership data:'
242
- top_owners_data.each do |owner, data|
243
- puts " #{owner.split('/').last}:\n Total Count: #{data[:churn_count]}"
244
- data[:directories].each do |dir, dir_data|
245
- puts " Directory: #{dir}\n Top files:"
246
- dir_data[:files].each do |file_data|
247
- next if converted_team_map[File.basename(file_data[:name])].nil?
248
-
249
- contributors = converted_team_map[file_data[:name]]&.first&.empty? ? ['Excluded contributor'] : converted_team_map[file_data[:name]].first
250
- puts " #{File.basename(file_data[:name])} - #{file_data[:count].last} #{contributors}}"
251
- end
252
- end
253
- end
254
- end
255
270
  @steps -= 1
256
271
 
257
272
  return unless @steps.positive?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class GitOwnershipInsights
4
- VERSION = '2.0.3'
4
+ VERSION = '2.0.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_ownership_insights
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serghei Moret