git_ownership_insights 2.0.3 → 2.0.4

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: 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