git_ownership_insights 2.0.2 → 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: dd5244ef2598407471bd2b55728b3c86cd48dfce9d4e6e2956b8b0ba2b0cf7ef
4
- data.tar.gz: 9e21ea07a0455fa4792687ee4b0180c8d3dfee0889801f4846ccec8dec04f33c
3
+ metadata.gz: eb151470ef24ed0e040026ced3fb187e7cc02012ba0564dd062be4611b8219a8
4
+ data.tar.gz: 64b844eebef335350f0fa9fa939c0d338910b5a711652a8c9ba926a7caec3456
5
5
  SHA512:
6
- metadata.gz: e07e63cba3b86fdedb333cf5063f559ac36d545fd04482f5339e3f939b4e207d8d99cbeb59e75832132c9501d74b73f251c5de343f76258ef1cbeadc8b06a2f5
7
- data.tar.gz: 9abb98a4c09c8ad308b8fdd2bd591bbd8a291da716090047b26836c9d801780949fde3389348b17739ecd5fe436726bb6efcaab271bf67edf014def7b0c2b992
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.2)
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
@@ -73,7 +122,7 @@ class GitOwnershipInsights
73
122
  count += 1 if lines_count > size
74
123
  end
75
124
 
76
- puts " *Current(\\*) total number of code files longer than #{size} lines:* #{count}"
125
+ puts " *Current total number of code files longer than #{size} lines:* #{count}"
77
126
  end
78
127
 
79
128
  def count_hotspot_lines(files)
@@ -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 ''
@@ -198,61 +251,22 @@ class GitOwnershipInsights
198
251
  puts " *Total amount of commits to #{CODE_EXTENSIONS} files:* #{total_changes}"
199
252
  puts " *Total #{CODE_EXTENSIONS} files changed:* #{uniq_code_files_with_changes.count}"
200
253
  count_big_files(@directory_path)
201
- puts " *Current(\\*) total of #{CODE_EXTENSIONS} files in the folder:* #{file_count}"
254
+ puts " *Current total of #{CODE_EXTENSIONS} files in the folder:* #{file_count}"
202
255
  puts " *Contributors:* #{contributors}"
203
- puts "* means that it the current(instant) repository value, all the other metrics are done over #{duration_in_days} days period"
204
256
 
205
257
  if HOTSPOT
206
258
  puts "\n"
207
259
  puts ' *Hotspot changes:*'
208
260
  filtered_top_touched_files.each do |line|
209
- 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:)}"
210
265
  end
211
266
  end
212
267
 
213
- if CODEOWNERS
214
- puts "\n"
215
- puts '*Code ownership data:*'
216
- codeowners = read_codeowners_file
217
-
218
- owners_data = Hash.new do |hash, key|
219
- hash[key] = { directories: Hash.new do |h, k|
220
- h[k] = { files: [] }
221
- end, churn_count: 0 }
222
- end
223
-
224
- file_team_map.each do |file, count|
225
- owners = find_owners(file, codeowners)
226
- owners.each do |owner|
227
- owners_data[owner][:churn_count] += count.last
228
-
229
- dir_path = File.dirname(file)
230
- owners_data[owner][:directories][dir_path][:files] << { name: File.basename(file), count: }
231
- end
232
- end
233
-
234
- # Sort owners_data by total count in descending order
235
- sorted_owners_data = owners_data.sort_by { |_, data| -data[:churn_count] }
236
-
237
- # Take the last 5 elements
238
- top_owners_data = sorted_owners_data.last(TOP_CONTRIBUTED_TEAMS.to_i)
239
-
240
- converted_team_map = file_team_map.transform_keys { |key| File.basename(key) }
268
+ handle_codeowners(file_team_map:) if CODEOWNERS
241
269
 
242
- puts ' Codeownership data:'
243
- top_owners_data.each do |owner, data|
244
- puts " #{owner.split('/').last}:\n Total Count: #{data[:churn_count]}"
245
- data[:directories].each do |dir, dir_data|
246
- puts " Directory: #{dir}\n Top files:"
247
- dir_data[:files].each do |file_data|
248
- next if converted_team_map[File.basename(file_data[:name])].nil?
249
-
250
- contributors = converted_team_map[file_data[:name]]&.first&.empty? ? ['Excluded contributor'] : converted_team_map[file_data[:name]].first
251
- puts " #{File.basename(file_data[:name])} - #{file_data[:count].last} #{contributors}}"
252
- end
253
- end
254
- end
255
- end
256
270
  @steps -= 1
257
271
 
258
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.2'
4
+ VERSION = '2.0.4'
5
5
  end
@@ -52,15 +52,14 @@ RSpec.describe GitOwnershipInsights do
52
52
  *[".swift", ".kt"] files exceeding 250 lines with multiple contributors:* 1
53
53
  *Total amount of commits to [".swift", ".kt"] files:* 7
54
54
  *Total [".swift", ".kt"] files changed:* 3
55
- *Current(\\*) total number of code files longer than 250 lines:* 2
56
- *Current(\\*) total of [".swift", ".kt"] files in the folder:* 4
55
+ *Current total number of code files longer than 250 lines:* 2
56
+ *Current total of [".swift", ".kt"] files in the folder:* 4
57
57
  *Contributors:* {"FIOS"=>5, "FAND"=>2}
58
- * means that it the current(instant) repository value, all the other metrics are done over 7 days period
59
58
 
60
- Hotspot changes:
59
+ *Hotspot changes:*
61
60
  /file1.swift Contributors: ["FIOS", "FAND"] Commits: 3
62
61
 
63
- Code ownership data:
62
+ *Code ownership data:*
64
63
  Codeownership data:
65
64
  FIOS:
66
65
  Total Count: 3
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.2
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Serghei Moret