git_ownership_insights 1.0.3 → 1.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -3
- data/bin/git_ownership_insights +49 -18
- 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: dc9c0c038149e42cd56b515168124dd68d50476169deedd38e98cb8593770106
|
4
|
+
data.tar.gz: bc3e24fb12aac9bf7e94e6649b61b4941d1dfba20a7cc23f4ba56e566631faa1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7638cb2568573d64238ba56438b9bb70e7a7ec6c9d28ac353e79c867d174039c04237103fc424cadd146d169bbce2014a8651445cc660ae2b7a06a7126bdb7cd
|
7
|
+
data.tar.gz: 5941142ba797b288b7a82e5a5b20edf91eb2c00cf754375743eccbb70e0ad31b8ce111f03f1c238746724d096f686b3f0b786c75432d3571e9b290eea7ae1284
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
git_ownership_insights (0.
|
5
|
-
awesome_print
|
4
|
+
git_ownership_insights (1.0.4)
|
6
5
|
date
|
7
6
|
pry
|
8
7
|
|
@@ -10,7 +9,6 @@ GEM
|
|
10
9
|
remote: https://rubygems.org/
|
11
10
|
specs:
|
12
11
|
ast (2.4.2)
|
13
|
-
awesome_print (1.9.2)
|
14
12
|
coderay (1.1.3)
|
15
13
|
date (3.3.4)
|
16
14
|
diff-lcs (1.5.0)
|
data/bin/git_ownership_insights
CHANGED
@@ -10,11 +10,11 @@ options = {}
|
|
10
10
|
OptionParser.new do |opts|
|
11
11
|
opts.banner = 'Usage: git_ownership_insights [options]'
|
12
12
|
|
13
|
-
opts.on('
|
13
|
+
opts.on('--debug', 'Enable debug mode') do
|
14
14
|
options[:debug] = true
|
15
15
|
end
|
16
16
|
|
17
|
-
opts.on('
|
17
|
+
opts.on('--ci', 'Do not print the info messages for better CI text parsing [default: false]') do
|
18
18
|
options[:ci] = true
|
19
19
|
end
|
20
20
|
|
@@ -22,56 +22,56 @@ OptionParser.new do |opts|
|
|
22
22
|
options[:codeowners] = true
|
23
23
|
end
|
24
24
|
|
25
|
-
opts.on('
|
25
|
+
opts.on('--hotspot-files', 'Print the found hotspot files (big files touched by many) [default: false]') do
|
26
26
|
options[:hotspot_files] = true
|
27
27
|
end
|
28
28
|
|
29
|
-
opts.on('
|
29
|
+
opts.on('--excluded-contributors STRING', 'Comma-delimited list of excluded contributors [example: WEB,RAILS,MOBILE]') do |exclusions|
|
30
30
|
options[:exclusions] = exclusions
|
31
31
|
end
|
32
32
|
|
33
|
-
opts.on('
|
33
|
+
opts.on('--excluded-files STRING', 'Comma-delimited list of excluded files [example: ViewController,AppDelegate.swift]') do |excluded_files|
|
34
34
|
options[:excluded_files] = excluded_files
|
35
35
|
end
|
36
36
|
|
37
|
-
opts.on('
|
37
|
+
opts.on('--steps STRING', 'Number of steps the script will go into the past [default: 1]') do |steps|
|
38
38
|
options[:steps] = steps
|
39
39
|
end
|
40
40
|
|
41
|
-
opts.on('
|
41
|
+
opts.on('--duration-in-days STRING',
|
42
42
|
'Number of days to aggregate the changes for [default: 30]') do |duration_in_days|
|
43
43
|
options[:duration_in_days] = duration_in_days
|
44
44
|
end
|
45
45
|
|
46
|
-
opts.on('
|
46
|
+
opts.on('--path STRING', 'Path to the directory or file to calculate the ownership [default: "."]') do |path|
|
47
47
|
options[:path] = path
|
48
48
|
end
|
49
49
|
|
50
|
-
opts.on('
|
50
|
+
opts.on('--team-regex STRING', 'Regex that will identify the team name [default: "[A-Za-z]+"]') do |team_regex|
|
51
51
|
options[:team_regex] = team_regex
|
52
52
|
end
|
53
53
|
|
54
|
-
opts.on('
|
54
|
+
opts.on('--top-contributing-team STRING', 'Limit of top contributed to the directory teams in codeownership data [default: 5]') do |top_contributing_team|
|
55
55
|
options[:top_contributing_team] = top_contributing_team
|
56
56
|
end
|
57
57
|
|
58
|
-
opts.on('
|
58
|
+
opts.on('--top-touched-files STRING', 'Limit of top touched files by individual contributors in codeownership data [default: 5]') do |top_touched_files|
|
59
59
|
options[:top_touched_files] = top_touched_files
|
60
60
|
end
|
61
61
|
|
62
|
-
opts.on('
|
62
|
+
opts.on('--codeowners-path STRING', 'Path to CODEOWNERS file [default: .github/CODEOWNERS]') do |codeowners_path|
|
63
63
|
options[:codeowners_path] = codeowners_path
|
64
64
|
end
|
65
65
|
|
66
|
-
opts.on('
|
66
|
+
opts.on('--big-file-size STRING', 'The amount of lines in the file to be considered big [default: 250]') do |big_file_size|
|
67
67
|
options[:big_file_size] = big_file_size
|
68
68
|
end
|
69
69
|
|
70
|
-
opts.on('
|
70
|
+
opts.on('--default-branch STRING', 'The default branch to pull and run metrics for [default: master]') do |default_branch|
|
71
71
|
options[:default_branch] = default_branch
|
72
72
|
end
|
73
73
|
|
74
|
-
opts.on('
|
74
|
+
opts.on('--code-extensions STRING', 'The file extensions that consider to be code [default: ".kt, .swift"]') do |code_extension|
|
75
75
|
options[:code_extension] = code_extension
|
76
76
|
end
|
77
77
|
|
@@ -145,6 +145,7 @@ def find_owners(file_path, codeowners)
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def count_big_files(directory_path, size: BIG_FILE_SIZE)
|
148
|
+
size = size.to_i
|
148
149
|
# Get a list of all files in the specified directory
|
149
150
|
files = Dir.glob(File.join(directory_path, '**', '*')).select { |file| File.file?(file) }
|
150
151
|
|
@@ -166,12 +167,33 @@ def count_big_files(directory_path, size: BIG_FILE_SIZE)
|
|
166
167
|
end
|
167
168
|
end
|
168
169
|
|
169
|
-
puts " Total number of files longer than #{size} lines: #{count}"
|
170
|
+
puts " Total number of code files longer than #{size} lines: #{count}"
|
171
|
+
end
|
172
|
+
|
173
|
+
def count_hotspot_lines(files)
|
174
|
+
code_files = files.select {|f|
|
175
|
+
extension = File.extname(f)
|
176
|
+
valid_extensions = ['.swift', '.kt']
|
177
|
+
valid_extensions.include?(extension)
|
178
|
+
}
|
179
|
+
|
180
|
+
# Initialize a counter for files that meet the criteria
|
181
|
+
count = 0
|
182
|
+
|
183
|
+
# Iterate through each file and check the line count
|
184
|
+
code_files.each do |file|
|
185
|
+
lines_count = File.foreach(file).reject { |line| line.match(/^\s*(\/\/|\/\*.*\*\/|\s*$)/) }.count
|
186
|
+
|
187
|
+
count += lines_count
|
188
|
+
end
|
189
|
+
|
190
|
+
puts " Total lines of hotspot code: #{count}"
|
170
191
|
end
|
171
192
|
|
172
193
|
def contribution_message(directory_path:, duration_in_days:, begin_time:, debug: nil, steps: nil)
|
173
194
|
duration_in_days = duration_in_days.to_i
|
174
195
|
all_teams = []
|
196
|
+
teams_count = 0
|
175
197
|
files_changed_by_many_teams = 0
|
176
198
|
total_changes = 0
|
177
199
|
start_date = begin_time.to_time.to_i - duration_in_days * 86_400
|
@@ -212,6 +234,7 @@ def contribution_message(directory_path:, duration_in_days:, begin_time:, debug:
|
|
212
234
|
if teams.count > 1
|
213
235
|
files_changed_by_many_teams += 1
|
214
236
|
file_team_map.merge!("#{file}" => [teams, commit_count])
|
237
|
+
teams_count += teams.count
|
215
238
|
end
|
216
239
|
|
217
240
|
puts "\n#{filename} [#{commit_count}]:#{teams}\n" if debug
|
@@ -224,7 +247,14 @@ def contribution_message(directory_path:, duration_in_days:, begin_time:, debug:
|
|
224
247
|
churn_count = file_team_map.values.map { |value| value[1] }.sum
|
225
248
|
hotspot_changes_percentage = (churn_count.to_f / total_changes.to_f)*100
|
226
249
|
|
227
|
-
puts "Timeframe: #{(begin_time - duration_in_days).strftime('%Y-%m-%d')} to #{begin_time.strftime('%Y-%m-%d')}
|
250
|
+
puts "Timeframe: #{(begin_time - duration_in_days).strftime('%Y-%m-%d')} to #{begin_time.strftime('%Y-%m-%d')}"
|
251
|
+
puts " Code files with a single contributor: #{(100 - ((files_changed_by_many_teams.to_f / code_files_with_changes.count.to_f) * 100)).round(2)}%"
|
252
|
+
puts " Hotspot code changes: #{churn_count} (#{hotspot_changes_percentage.round(2)}%)"
|
253
|
+
puts " Total occurrences of cross-squad dependencies over same files: #{teams_count}"
|
254
|
+
puts " Amount of code changes: #{total_changes}"
|
255
|
+
puts " Total files changed: #{code_files_with_changes.count}"
|
256
|
+
puts " Total files in the folder: #{file_count}"
|
257
|
+
puts " Contributors: #{contributors}"
|
228
258
|
|
229
259
|
# Filter files based on extension and size
|
230
260
|
filtered_files = file_team_map.select do |file_path|
|
@@ -236,6 +266,7 @@ def contribution_message(directory_path:, duration_in_days:, begin_time:, debug:
|
|
236
266
|
|
237
267
|
filtered_top_touched_files = filtered_files.sort_by { |element, count| [-count.last, element] }
|
238
268
|
count_big_files(directory_path)
|
269
|
+
count_hotspot_lines(filtered_files.keys)
|
239
270
|
puts " Total files longer than #{BIG_FILE_SIZE} lines with multiple contributors: #{filtered_top_touched_files.count}\n"
|
240
271
|
if HOTSPOT
|
241
272
|
filtered_top_touched_files.each do |line|
|
@@ -313,7 +344,7 @@ unless CI
|
|
313
344
|
end
|
314
345
|
|
315
346
|
system("git checkout #{DEFAULT_BRANCH}", [ :out ] => File::NULL)
|
316
|
-
system("git pull", [ :out ] => File::NULL)
|
347
|
+
system("git pull", [ :out, :err ] => File::NULL)
|
317
348
|
|
318
349
|
contribution_message(duration_in_days: options[:duration_in_days] || 30, directory_path: REPO_PATH,
|
319
350
|
begin_time: DateTime.now, steps: options[:steps].to_i, debug: options[:debug])
|