solidstats 3.0.0.beta.1 → 3.0.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -0
  3. data/app/assets/javascripts/solidstats/application.js +257 -0
  4. data/app/assets/javascripts/solidstats/dashboard.js +179 -0
  5. data/app/assets/stylesheets/solidstats/application.css +6 -1
  6. data/app/controllers/solidstats/dashboard_controller.rb +28 -35
  7. data/app/controllers/solidstats/gem_metadata_controller.rb +12 -0
  8. data/app/controllers/solidstats/logs_controller.rb +12 -12
  9. data/app/controllers/solidstats/performance_controller.rb +2 -2
  10. data/app/controllers/solidstats/productivity_controller.rb +10 -10
  11. data/app/controllers/solidstats/quality_controller.rb +32 -32
  12. data/app/controllers/solidstats/securities_controller.rb +7 -7
  13. data/app/helpers/solidstats/application_helper.rb +10 -10
  14. data/app/helpers/solidstats/performance_helper.rb +32 -32
  15. data/app/helpers/solidstats/productivity_helper.rb +20 -20
  16. data/app/services/solidstats/bundler_audit_service.rb +13 -13
  17. data/app/services/solidstats/coverage_compass_service.rb +59 -59
  18. data/app/services/solidstats/load_lens_service.rb +90 -70
  19. data/app/services/solidstats/log_size_monitor_service.rb +59 -59
  20. data/app/services/solidstats/my_todo_service.rb +68 -68
  21. data/app/services/solidstats/style_patrol_service.rb +44 -44
  22. data/app/views/layouts/solidstats/application.html.erb +1 -1
  23. data/app/views/solidstats/shared/_quick_actions.html.erb +1 -1
  24. data/config/routes.rb +4 -4
  25. data/lib/generators/solidstats/clean/clean_generator.rb +24 -0
  26. data/lib/generators/solidstats/clean/templates/README +8 -0
  27. data/lib/generators/solidstats/install/install_generator.rb +32 -17
  28. data/lib/generators/solidstats/templates/initializer.rb +112 -0
  29. data/lib/solidstats/asset_compatibility.rb +238 -0
  30. data/lib/solidstats/asset_manifest.rb +205 -0
  31. data/lib/solidstats/engine.rb +49 -9
  32. data/lib/solidstats/version.rb +1 -1
  33. data/lib/solidstats.rb +24 -11
  34. data/lib/tasks/solidstats.rake +67 -0
  35. data/lib/tasks/solidstats_performance.rake +6 -29
  36. data/lib/tasks/solidstats_tasks.rake +16 -0
  37. metadata +14 -5
  38. data/lib/tasks/solidstats_install.rake +0 -13
@@ -1,5 +1,5 @@
1
- require 'json'
2
- require 'fileutils'
1
+ require "json"
2
+ require "fileutils"
3
3
 
4
4
  module Solidstats
5
5
  class CoverageCompassService
@@ -12,19 +12,19 @@ module Solidstats
12
12
  end
13
13
 
14
14
  Rails.logger.info "CoverageCompass: Collecting fresh coverage data"
15
-
15
+
16
16
  # Collect fresh coverage data
17
17
  coverage_data = collect_coverage_data
18
-
18
+
19
19
  # Cache the data if it's valid coverage information
20
20
  if coverage_data && !coverage_data[:setup_required] && !coverage_data[:error]
21
21
  cache_coverage_data(coverage_data)
22
22
  Rails.logger.info "CoverageCompass: Data cached successfully"
23
23
  end
24
-
24
+
25
25
  # Always update summary file
26
26
  update_summary_file(coverage_data) if coverage_data
27
-
27
+
28
28
  coverage_data
29
29
  rescue => e
30
30
  Rails.logger.error "Coverage collection failed: #{e.message}"
@@ -40,10 +40,10 @@ module Solidstats
40
40
 
41
41
  def get_resultset_file_path
42
42
  # Only check in the coverage directory
43
- coverage_file = File.join(Rails.root, 'coverage', '.resultset.json')
44
-
43
+ coverage_file = File.join(Rails.root, "coverage", ".resultset.json")
44
+
45
45
  Rails.logger.info "CoverageCompass: Looking for coverage file at: #{coverage_file}"
46
-
46
+
47
47
  if File.exist?(coverage_file)
48
48
  Rails.logger.info "CoverageCompass: Coverage file found - Size: #{File.size(coverage_file)} bytes"
49
49
  coverage_file
@@ -59,27 +59,27 @@ module Solidstats
59
59
 
60
60
  def cache_fresh?
61
61
  return false unless cached_data_exists?
62
-
62
+
63
63
  resultset_path = get_resultset_file_path
64
64
  return false unless resultset_path
65
-
65
+
66
66
  cache_time = File.mtime(cache_file_path)
67
67
  resultset_time = File.mtime(resultset_path)
68
-
68
+
69
69
  # Cache is fresh if it's newer than the resultset file
70
70
  cache_time >= resultset_time
71
71
  end
72
72
 
73
73
  def load_cached_data
74
74
  cached_data = JSON.parse(File.read(cache_file_path)).deep_symbolize_keys
75
-
75
+
76
76
  # Convert string timestamps back to Time objects
77
- [:collected_at, :analyzed_at, :data_timestamp].each do |time_field|
77
+ [ :collected_at, :analyzed_at, :data_timestamp ].each do |time_field|
78
78
  if cached_data[time_field].is_a?(String)
79
79
  cached_data[time_field] = Time.parse(cached_data[time_field])
80
80
  end
81
81
  end
82
-
82
+
83
83
  cached_data
84
84
  rescue => e
85
85
  Rails.logger.error "Failed to load cached coverage data: #{e.message}"
@@ -88,80 +88,80 @@ module Solidstats
88
88
 
89
89
  def collect_coverage_data
90
90
  resultset_path = get_resultset_file_path
91
-
91
+
92
92
  unless resultset_path
93
93
  return setup_instructions_data
94
94
  end
95
-
95
+
96
96
  # Check if coverage data is stale (older than 24 hours)
97
97
  if File.mtime(resultset_path) < 24.hours.ago
98
98
  return stale_coverage_data(resultset_path)
99
99
  end
100
-
100
+
101
101
  parse_resultset_file(resultset_path)
102
102
  end
103
103
 
104
104
  def parse_resultset_file(file_path)
105
105
  Rails.logger.info "CoverageCompass: Parsing file #{file_path}"
106
106
  resultset_data = JSON.parse(File.read(file_path)).deep_symbolize_keys
107
-
107
+
108
108
  Rails.logger.info "CoverageCompass: Found test suites: #{resultset_data.keys}"
109
-
109
+
110
110
  # Extract coverage data from SimpleCov resultset format
111
111
  coverage_results = {}
112
112
  total_lines = 0
113
113
  covered_lines = 0
114
-
114
+
115
115
  resultset_data.each do |test_suite, suite_data|
116
116
  Rails.logger.info "CoverageCompass: Processing suite '#{test_suite}'"
117
-
117
+
118
118
  unless suite_data[:coverage]
119
119
  Rails.logger.warn "CoverageCompass: No coverage data in suite '#{test_suite}'"
120
120
  next
121
121
  end
122
-
122
+
123
123
  Rails.logger.info "CoverageCompass: Found #{suite_data[:coverage].keys.size} files in '#{test_suite}'"
124
-
124
+
125
125
  suite_data[:coverage].each do |file_path, file_coverage|
126
126
  # Convert file_path to string in case it's a symbol
127
127
  file_path_str = file_path.to_s
128
- next if file_path_str.include?('vendor/') || file_path_str.include?('spec/') || file_path_str.include?('test/')
129
-
128
+ next if file_path_str.include?("vendor/") || file_path_str.include?("spec/") || file_path_str.include?("test/")
129
+
130
130
  # Handle different SimpleCov formats - newer versions use "lines" key
131
131
  line_coverage = file_coverage.is_a?(Hash) ? file_coverage[:lines] : file_coverage
132
-
132
+
133
133
  unless line_coverage.is_a?(Array)
134
134
  Rails.logger.warn "CoverageCompass: Invalid line coverage format for #{file_path_str}"
135
135
  next
136
136
  end
137
-
138
- relative_path = file_path_str.sub("#{Rails.root}/", '')
137
+
138
+ relative_path = file_path_str.sub("#{Rails.root}/", "")
139
139
  line_count = line_coverage.compact.size
140
140
  covered_count = line_coverage.compact.count { |hits| hits > 0 }
141
-
141
+
142
142
  # Find uncovered lines (lines that are trackable but have 0 hits)
143
143
  missed_lines = []
144
144
  line_coverage.each_with_index do |hits, index|
145
145
  next if hits.nil? # Skip non-trackable lines
146
146
  missed_lines << (index + 1) if hits == 0 # Line numbers are 1-based
147
147
  end
148
-
148
+
149
149
  coverage_results[relative_path] = {
150
150
  total_lines: line_count,
151
151
  covered_lines: covered_count,
152
152
  missed_lines: missed_lines,
153
153
  coverage_percentage: line_count > 0 ? (covered_count.to_f / line_count * 100).round(2) : 0
154
154
  }
155
-
155
+
156
156
  total_lines += line_count
157
157
  covered_lines += covered_count
158
158
  end
159
159
  end
160
-
160
+
161
161
  overall_percentage = total_lines > 0 ? (covered_lines.to_f / total_lines * 100).round(2) : 0
162
-
162
+
163
163
  Rails.logger.info "CoverageCompass: Processed #{coverage_results.size} files, #{overall_percentage}% coverage"
164
-
164
+
165
165
  {
166
166
  overall_coverage: overall_percentage,
167
167
  file_coverage: coverage_results,
@@ -217,10 +217,10 @@ module Solidstats
217
217
  def stale_coverage_data(resultset_path)
218
218
  data_age = Time.current - File.mtime(resultset_path)
219
219
  hours_old = (data_age / 1.hour).round(1)
220
-
220
+
221
221
  # Get the last coverage data even if it's stale
222
222
  last_coverage_data = parse_resultset_file(resultset_path)
223
-
223
+
224
224
  {
225
225
  stale_data: true,
226
226
  message: "Coverage data is #{hours_old} hours old. Consider running tests to get fresh data.",
@@ -245,28 +245,28 @@ module Solidstats
245
245
  end
246
246
 
247
247
  def update_summary_file(coverage_data)
248
- summary_file_path = Rails.root.join('solidstats', 'summary.json')
249
-
248
+ summary_file_path = Rails.root.join("solidstats", "summary.json")
249
+
250
250
  # Ensure directory exists
251
251
  FileUtils.mkdir_p(File.dirname(summary_file_path))
252
-
252
+
253
253
  # Read existing summary or create new one
254
254
  begin
255
255
  existing_summary = File.exist?(summary_file_path) ? JSON.parse(File.read(summary_file_path)) : {}
256
256
  rescue JSON::ParserError
257
257
  existing_summary = {}
258
258
  end
259
-
259
+
260
260
  # Calculate coverage metrics
261
261
  overall_coverage = coverage_data[:overall_coverage] || 0
262
262
  total_files = coverage_data[:file_coverage]&.size || 0
263
263
  status = determine_status(coverage_data)
264
-
264
+
265
265
  # Create badges based on coverage metrics
266
266
  badges = []
267
267
  badges << { "text" => "#{overall_coverage.round(1)}% Coverage", "color" => coverage_badge_color(overall_coverage) }
268
268
  badges << { "text" => "#{total_files} Files", "color" => "info" }
269
-
269
+
270
270
  # Update the Coverage Compass entry
271
271
  existing_summary["Coverage Compass"] = {
272
272
  "icon" => "target",
@@ -276,7 +276,7 @@ module Solidstats
276
276
  "url" => "/solidstats/quality/coverage_compass",
277
277
  "badges" => badges
278
278
  }
279
-
279
+
280
280
  # Write updated summary
281
281
  File.write(summary_file_path, JSON.pretty_generate(existing_summary))
282
282
  Rails.logger.info("Updated summary.json with Coverage Compass data")
@@ -285,15 +285,15 @@ module Solidstats
285
285
  end
286
286
 
287
287
  def determine_status(coverage_data)
288
- return 'danger' if coverage_data[:setup_required] || coverage_data[:error]
289
- return 'warning' if coverage_data[:stale_data]
290
-
288
+ return "danger" if coverage_data[:setup_required] || coverage_data[:error]
289
+ return "warning" if coverage_data[:stale_data]
290
+
291
291
  coverage = coverage_data[:overall_coverage] || 0
292
292
  case coverage
293
- when 0...50 then 'danger'
294
- when 50...80 then 'warning'
295
- when 80...95 then 'info'
296
- else 'success'
293
+ when 0...50 then "danger"
294
+ when 50...80 then "warning"
295
+ when 80...95 then "info"
296
+ else "success"
297
297
  end
298
298
  end
299
299
 
@@ -301,30 +301,30 @@ module Solidstats
301
301
  return "Setup required" if coverage_data[:setup_required]
302
302
  return "Analysis error" if coverage_data[:error]
303
303
  return "Stale data" if coverage_data[:stale_data]
304
-
304
+
305
305
  coverage = coverage_data[:overall_coverage] || 0
306
306
  "#{coverage.round(1)}% coverage"
307
307
  end
308
308
 
309
309
  def coverage_badge_color(coverage)
310
310
  case coverage
311
- when 0...50 then 'error'
312
- when 50...80 then 'warning'
313
- when 80...95 then 'info'
314
- else 'success'
311
+ when 0...50 then "error"
312
+ when 50...80 then "warning"
313
+ when 80...95 then "info"
314
+ else "success"
315
315
  end
316
316
  end
317
317
 
318
318
  def cache_file_path
319
- File.join(solidstats_directory, 'coverage_cache.json')
319
+ File.join(solidstats_directory, "coverage_cache.json")
320
320
  end
321
321
 
322
322
  def summary_file_path
323
- File.join(solidstats_directory, 'summary.json')
323
+ File.join(solidstats_directory, "summary.json")
324
324
  end
325
325
 
326
326
  def solidstats_directory
327
- File.join(Rails.root, 'solidstats')
327
+ File.join(Rails.root, "solidstats")
328
328
  end
329
329
 
330
330
  def ensure_solidstats_directory