git_ownership_insights 2.0.2 → 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 +79 -65
- data/lib/git_ownership_insights/version.rb +1 -1
- data/spec/git_ownership_insights_spec.rb +4 -5
- 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
|
@@ -73,7 +122,7 @@ class GitOwnershipInsights
|
|
73
122
|
count += 1 if lines_count > size
|
74
123
|
end
|
75
124
|
|
76
|
-
puts " *Current
|
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
|
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 ''
|
@@ -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
|
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
|
-
|
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?
|
@@ -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
|
56
|
-
*Current
|
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
|