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: 7a07de43c9627bdeceeedc7e06d1028645a3b374f26203063e1bc23ed3024611
4
- data.tar.gz: b7ea15dc22b92a8742278ff835612f180125240af9531e2ec764c7b19a80e5c9
3
+ metadata.gz: 6d884a43cd70caba8943ba59a6ce05d46631cb6927ed0eefa74a1dccbc2d66f8
4
+ data.tar.gz: 180007096b00a2978d8e6d6440c9214b1f8d59e41c841e665392db2c955fecd8
5
5
  SHA512:
6
- metadata.gz: f828c59098fb64d0017ac93a0fe15894ea8c92a08a5f6a2145d84ff7e88f38c089311cb5d177257169a9d88e8d0948c592f85c12f8a1209135e4442c223b0795
7
- data.tar.gz: eb8302ef0f5a93679411c77c243dfece43e0d902a129325d4319d739f103fbf5c2ed29f225d9c3c705466525aaef7238964fd557176fbb87036e97355119967e
6
+ metadata.gz: 27a2bc913215ffb0cee443be41b1a91128edc31998d0f3841ad0ac02fd03393529f41825c55645cfc007f0a0d478a439834568334e2bf81c89929d3eeb396f37
7
+ data.tar.gz: e8d564d1734b023321027464ff86aea38463085681ef579297b69fc8f4bfd034b558d064e754bc0b142bf1a18171f4e959dd9c1af0d2a2ac34a375f01f5cbb88
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- git_ownership_insights (1.0.6)
4
+ git_ownership_insights (1.2.0)
5
5
  date
6
6
  pry
7
7
 
@@ -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 files [example: ViewController,AppDelegate.swift]') do |excluded_files|
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 patterns: #{EXCLUDED_FILES.split(',')}\n" if EXCLUDED_FILES
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.6.0'
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 " *Total number of code files longer than #{size} lines:* #{count}"
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.filter_code_files(files)
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
- file_count = `git ls-tree -r --name-only $(git rev-list -1 --since="#{start_date}" --until="#{end_date}" HEAD) -- "#{directory_path}" | wc -l`.to_i
104
- all_files_with_changes = `git log --name-only --pretty=format:"" --since="#{start_date}" --until="#{end_date}" "#{directory_path}"`.split.sort
105
- excluded_patterns = EXCLUDED_FILES.split(',') if EXCLUDED_FILES
106
-
107
- code_files_with_changes = filter_code_files(all_files_with_changes)
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
- code_files_with_changes = code_files_with_changes.reject do |file|
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 = `git log --since="#{start_date}" --until="#{end_date}" --follow -- "#{file}" | grep -c '^commit'`.to_i
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 if File.exist?(file)
146
+ cross_teams_count += teams.count
135
147
  else
136
- single_ownership_teams_count += 1 if File.exist?(file)
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 " *Hotspot Code Changes:* #{churn_count} (#{hotspot_changes_percentage.round(2)}%)"
162
- puts " *Cross-Squad Dependency:*"
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 " *Files exceeding #{BIG_FILE_SIZE} lines with multiple contributors:* #{filtered_top_touched_files.count}"
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 " *Code files with a single contributor:* #{(100 - ((files_changed_by_many_teams.to_f / code_files_with_changes.count) * 100)).round(2)}%"
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: 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: duration_in_days, directory_path: directory_path,
232
- begin_time: begin_time - duration_in_days, steps: steps, debug: debug)
249
+ contribution_message(duration_in_days:, directory_path:,
250
+ begin_time: begin_time - duration_in_days, steps:, debug:)
233
251
  end
234
252
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GitOwnershipInsights
4
- VERSION = '1.1.1'
4
+ VERSION = '1.2.0'
5
5
  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.1.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-29 00:00:00.000000000 Z
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.6.0
84
+ version: '3.2'
85
85
  required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="