git_ownership_insights 1.1.1 → 1.2.0
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d884a43cd70caba8943ba59a6ce05d46631cb6927ed0eefa74a1dccbc2d66f8
|
4
|
+
data.tar.gz: 180007096b00a2978d8e6d6440c9214b1f8d59e41c841e665392db2c955fecd8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27a2bc913215ffb0cee443be41b1a91128edc31998d0f3841ad0ac02fd03393529f41825c55645cfc007f0a0d478a439834568334e2bf81c89929d3eeb396f37
|
7
|
+
data.tar.gz: e8d564d1734b023321027464ff86aea38463085681ef579297b69fc8f4bfd034b558d064e754bc0b142bf1a18171f4e959dd9c1af0d2a2ac34a375f01f5cbb88
|
data/Gemfile.lock
CHANGED
data/bin/git_ownership_insights
CHANGED
@@ -33,7 +33,7 @@ OptionParser.new do |opts|
|
|
33
33
|
end
|
34
34
|
|
35
35
|
opts.on('--excluded-files STRING',
|
36
|
-
'Comma-delimited list of excluded
|
36
|
+
'Comma-delimited list of excluded keywords [example: ViewController,AppDelegate.swift]') do |excluded_files|
|
37
37
|
options[:excluded_files] = excluded_files
|
38
38
|
end
|
39
39
|
|
@@ -121,7 +121,7 @@ unless CI
|
|
121
121
|
puts "Code extensions: #{CODE_EXTENSIONS}"
|
122
122
|
puts "Regex to detect the teams identifiers: #{TEAM_REGEX}"
|
123
123
|
puts "Excluded contributors: #{EXCLUSIONS}\n" if EXCLUSIONS
|
124
|
-
puts "Excluded file
|
124
|
+
puts "Excluded file keywords: #{EXCLUDED_FILES.split(',')}\n" if EXCLUDED_FILES
|
125
125
|
puts "Lines of code limit (big files) for the hotspot calculation: #{BIG_FILE_SIZE}"
|
126
126
|
puts "Hotspot detailed output is: #{options[:hotspot_files] ? 'on' : 'off'}\n"
|
127
127
|
puts "CODEOWNERS output is: #{options[:codeowners] ? 'on' : 'off'}\n"
|
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = 'This gem prints git ownership insights'
|
13
13
|
spec.homepage = 'https://rubygems.org'
|
14
14
|
spec.license = 'MIT'
|
15
|
-
spec.required_ruby_version = '>= 2
|
15
|
+
spec.required_ruby_version = '>= 3.2'
|
16
16
|
|
17
17
|
spec.metadata['homepage_uri'] = spec.homepage
|
18
18
|
spec.metadata['source_code_uri'] = 'https://rubygems.org'
|
@@ -62,7 +62,7 @@ module GitOwnershipInsights
|
|
62
62
|
count += 1 if lines_count > size
|
63
63
|
end
|
64
64
|
|
65
|
-
puts " *
|
65
|
+
puts " *Current(*) total number of code files longer than #{size} lines:* #{count}"
|
66
66
|
end
|
67
67
|
|
68
68
|
def self.count_hotspot_lines(files)
|
@@ -83,14 +83,28 @@ module GitOwnershipInsights
|
|
83
83
|
puts " *Total lines of hotspot code:* #{count}"
|
84
84
|
end
|
85
85
|
|
86
|
-
def self.
|
86
|
+
def self.filter_existing_code_files(files)
|
87
87
|
files.select do |f|
|
88
|
+
next unless File.exist?(f)
|
89
|
+
|
88
90
|
extension = File.extname(f)
|
89
91
|
valid_extensions = CODE_EXTENSIONS
|
90
92
|
valid_extensions.include?(extension)
|
91
93
|
end
|
92
94
|
end
|
93
95
|
|
96
|
+
def self.git_files(directory_path:)
|
97
|
+
`git ls-tree -r --name-only $(git rev-list -1 HEAD) -- "#{directory_path}"`
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.files_with_changes(directory_path:, start_date:, end_date:)
|
101
|
+
`git log --name-only --pretty=format:"" --since="#{start_date}" --until="#{end_date}" "#{directory_path}"`
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.git_commit_count(file:, start_date:, end_date:)
|
105
|
+
`git log --since="#{start_date}" --until="#{end_date}" --follow -- "#{file}" | grep -c '^commit'`
|
106
|
+
end
|
107
|
+
|
94
108
|
def self.contribution_message(directory_path:, duration_in_days:, begin_time:, debug: nil, steps: nil)
|
95
109
|
duration_in_days = duration_in_days.to_i
|
96
110
|
all_teams = []
|
@@ -98,27 +112,25 @@ module GitOwnershipInsights
|
|
98
112
|
single_ownership_teams_count = 0
|
99
113
|
files_changed_by_many_teams = 0
|
100
114
|
total_changes = 0
|
101
|
-
start_date = begin_time.to_time.to_i - duration_in_days * 86_400
|
102
|
-
end_date = begin_time.to_time.to_i
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
115
|
+
start_date = begin_time.to_time.to_i - duration_in_days * 86_400 - 30 * 86_400
|
116
|
+
end_date = begin_time.to_time.to_i - 30 * 86_400
|
117
|
+
git_ls = git_files(directory_path:)
|
118
|
+
file_count = filter_existing_code_files(git_ls.split).count
|
119
|
+
all_files_with_changes = files_with_changes(directory_path:, start_date:, end_date:).split.sort
|
120
|
+
code_files_with_changes = filter_existing_code_files(all_files_with_changes)
|
121
|
+
uniq_code_files_with_changes = code_files_with_changes.uniq
|
108
122
|
|
109
123
|
if EXCLUDED_FILES
|
110
|
-
|
124
|
+
excluded_patterns = EXCLUDED_FILES.split(',')
|
125
|
+
uniq_code_files_with_changes = uniq_code_files_with_changes.reject do |file|
|
111
126
|
excluded_patterns.any? { |pattern| file.include?(pattern) }
|
112
127
|
end
|
113
128
|
end
|
114
129
|
|
115
|
-
uniq_code_files_with_changes = code_files_with_changes.uniq
|
116
|
-
|
117
130
|
file_team_map = {}
|
118
131
|
uniq_code_files_with_changes.each do |file|
|
119
132
|
filename = File.basename(file)
|
120
|
-
commit_count =
|
121
|
-
# Get the log of the file in the given duration
|
133
|
+
commit_count = git_commit_count(file:, start_date:, end_date:).to_i
|
122
134
|
git_log = `git log --pretty=format:"%s" --since="#{start_date}" --until="#{end_date}" --follow -- "#{file}"`.split("\n")
|
123
135
|
teams = git_log.map do |team|
|
124
136
|
team.match(/#{TEAM_REGEX}/)[0].upcase
|
@@ -131,9 +143,9 @@ module GitOwnershipInsights
|
|
131
143
|
if teams.count > 1
|
132
144
|
files_changed_by_many_teams += 1
|
133
145
|
file_team_map.merge!(file.to_s => [teams, commit_count])
|
134
|
-
cross_teams_count += teams.count
|
146
|
+
cross_teams_count += teams.count
|
135
147
|
else
|
136
|
-
single_ownership_teams_count += 1
|
148
|
+
single_ownership_teams_count += 1
|
137
149
|
end
|
138
150
|
|
139
151
|
puts "\n#{filename} [#{commit_count}]:#{teams}\n" if debug
|
@@ -156,20 +168,26 @@ module GitOwnershipInsights
|
|
156
168
|
|
157
169
|
filtered_top_touched_files = filtered_files.sort_by { |element, count| [-count.last, element] }
|
158
170
|
|
159
|
-
puts
|
171
|
+
puts ''
|
160
172
|
puts "*Timeframe:* #{(begin_time - duration_in_days).strftime('%Y-%m-%d')} to #{begin_time.strftime('%Y-%m-%d')}"
|
161
|
-
puts " *
|
162
|
-
puts "
|
173
|
+
puts " *Code files with a single contributor:* #{(100 - ((files_changed_by_many_teams.to_f / file_count) * 100)).round(2)}%"
|
174
|
+
puts " *Existing files changed by many teams:* #{files_changed_by_many_teams}"
|
175
|
+
puts " *Current existing #{CODE_EXTENSIONS} files:* #{file_count}"
|
176
|
+
puts ' *Cross-Squad Dependency:*'
|
163
177
|
puts " *Contributions by multiple squads to the same files:* #{cross_teams_count}"
|
164
178
|
puts " *Contributions by single squads contributing to single files:* #{single_ownership_teams_count}"
|
165
|
-
puts " *
|
179
|
+
puts " *Hotspot Code Changes:* #{hotspot_changes_percentage.round(2)}%"
|
180
|
+
puts " *Churn count(commits to files by multiple teams):* #{churn_count}"
|
181
|
+
puts " *Total amount of commits:* #{total_changes}"
|
166
182
|
count_hotspot_lines(filtered_files.keys)
|
183
|
+
puts " *#{CODE_EXTENSIONS} files with multiple contributors:* #{file_team_map.count}"
|
184
|
+
puts " *#{CODE_EXTENSIONS} files exceeding #{BIG_FILE_SIZE} lines with multiple contributors:* #{filtered_top_touched_files.count}"
|
185
|
+
puts " *Total amount of commits to #{CODE_EXTENSIONS} files:* #{total_changes}"
|
186
|
+
puts " *Total #{CODE_EXTENSIONS} files changed:* #{uniq_code_files_with_changes.count}"
|
167
187
|
count_big_files(directory_path)
|
168
|
-
puts " *
|
169
|
-
puts " *Total amount of code changes:* #{total_changes}"
|
170
|
-
puts " *Total files changed:* #{code_files_with_changes.count}"
|
171
|
-
puts " *Total files in the folder:* #{file_count}"
|
188
|
+
puts " *Current(*) total of #{CODE_EXTENSIONS} files in the folder:* #{file_count}"
|
172
189
|
puts " *Contributors:* #{contributors}"
|
190
|
+
puts "* means that it the current(instant) repository value, all the other metrics are done over #{duration_in_days} days period"
|
173
191
|
|
174
192
|
if HOTSPOT
|
175
193
|
puts "\n"
|
@@ -196,7 +214,7 @@ module GitOwnershipInsights
|
|
196
214
|
owners_data[owner][:churn_count] += count.last
|
197
215
|
|
198
216
|
dir_path = File.dirname(file)
|
199
|
-
owners_data[owner][:directories][dir_path][:files] << { name: File.basename(file), count:
|
217
|
+
owners_data[owner][:directories][dir_path][:files] << { name: File.basename(file), count: }
|
200
218
|
end
|
201
219
|
end
|
202
220
|
|
@@ -228,7 +246,7 @@ module GitOwnershipInsights
|
|
228
246
|
|
229
247
|
system("git checkout `git rev-list -1 --before='#{(begin_time - duration_in_days).strftime('%B %d %Y')}' HEAD`",
|
230
248
|
%i[out err] => File::NULL)
|
231
|
-
contribution_message(duration_in_days
|
232
|
-
begin_time: begin_time - duration_in_days, steps
|
249
|
+
contribution_message(duration_in_days:, directory_path:,
|
250
|
+
begin_time: begin_time - duration_in_days, steps:, debug:)
|
233
251
|
end
|
234
252
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git_ownership_insights
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Serghei Moret
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-01-
|
11
|
+
date: 2024-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: date
|
@@ -81,7 +81,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
81
81
|
requirements:
|
82
82
|
- - ">="
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: 2
|
84
|
+
version: '3.2'
|
85
85
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - ">="
|