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 +4 -4
- data/.rubocop_todo.yml +11 -11
- data/Gemfile.lock +1 -1
- data/lib/git_ownership_insights/git_ownership_insight.rb +77 -62
- data/lib/git_ownership_insights/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb151470ef24ed0e040026ced3fb187e7cc02012ba0564dd062be4611b8219a8
|
4
|
+
data.tar.gz: 64b844eebef335350f0fa9fa939c0d338910b5a711652a8c9ba926a7caec3456
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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:
|
16
|
+
# Offense count: 6
|
17
17
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
18
18
|
Metrics/AbcSize:
|
19
|
-
Max:
|
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:
|
25
|
+
Max: 75
|
26
26
|
|
27
27
|
# Offense count: 1
|
28
28
|
# Configuration parameters: CountComments, CountAsOne.
|
29
29
|
Metrics/ClassLength:
|
30
|
-
Max:
|
30
|
+
Max: 207
|
31
31
|
|
32
|
-
# Offense count:
|
32
|
+
# Offense count: 2
|
33
33
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
34
34
|
Metrics/CyclomaticComplexity:
|
35
|
-
Max:
|
35
|
+
Max: 12
|
36
36
|
|
37
|
-
# Offense count:
|
37
|
+
# Offense count: 6
|
38
38
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
39
39
|
Metrics/MethodLength:
|
40
|
-
Max:
|
40
|
+
Max: 49
|
41
41
|
|
42
42
|
# Offense count: 1
|
43
43
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
44
44
|
Metrics/PerceivedComplexity:
|
45
|
-
Max:
|
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:
|
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
@@ -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
|
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
|
-
|
168
|
-
|
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
|
-
|
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?
|