solidstats 1.1.0 → 3.0.0.beta.1

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/README.md +27 -0
  4. data/Rakefile +3 -3
  5. data/app/assets/stylesheets/solidstats/dashboard.css +48 -0
  6. data/app/controllers/solidstats/dashboard_controller.rb +82 -60
  7. data/app/controllers/solidstats/logs_controller.rb +72 -0
  8. data/app/controllers/solidstats/performance_controller.rb +25 -0
  9. data/app/controllers/solidstats/productivity_controller.rb +39 -0
  10. data/app/controllers/solidstats/quality_controller.rb +152 -0
  11. data/app/controllers/solidstats/securities_controller.rb +30 -0
  12. data/app/helpers/solidstats/application_helper.rb +155 -0
  13. data/app/helpers/solidstats/performance_helper.rb +87 -0
  14. data/app/helpers/solidstats/productivity_helper.rb +38 -0
  15. data/app/services/solidstats/bundler_audit_service.rb +206 -0
  16. data/app/services/solidstats/coverage_compass_service.rb +335 -0
  17. data/app/services/solidstats/load_lens_service.rb +454 -0
  18. data/app/services/solidstats/log_size_monitor_service.rb +205 -74
  19. data/app/services/solidstats/my_todo_service.rb +242 -0
  20. data/app/services/solidstats/style_patrol_service.rb +319 -0
  21. data/app/views/layouts/solidstats/application.html.erb +9 -2
  22. data/app/views/layouts/solidstats/dashboard.html.erb +84 -0
  23. data/app/views/solidstats/dashboard/dashboard.html.erb +39 -0
  24. data/app/views/solidstats/logs/logs_size.html.erb +409 -0
  25. data/app/views/solidstats/performance/load_lens.html.erb +158 -0
  26. data/app/views/solidstats/productivity/_todo_list.html.erb +49 -0
  27. data/app/views/solidstats/productivity/my_todos.html.erb +84 -0
  28. data/app/views/solidstats/quality/coverage_compass.html.erb +420 -0
  29. data/app/views/solidstats/quality/style_patrol.html.erb +463 -0
  30. data/app/views/solidstats/securities/bundler_audit.html.erb +345 -0
  31. data/app/views/solidstats/shared/_dashboard_card.html.erb +160 -0
  32. data/app/views/solidstats/shared/_quick_actions.html.erb +26 -0
  33. data/config/routes.rb +32 -4
  34. data/lib/generators/solidstats/install/install_generator.rb +28 -2
  35. data/lib/generators/solidstats/install/templates/README +7 -0
  36. data/lib/solidstats/version.rb +1 -1
  37. data/lib/tasks/solidstats_performance.rake +84 -0
  38. metadata +43 -19
  39. data/app/services/solidstats/audit_service.rb +0 -56
  40. data/app/services/solidstats/data_collector_service.rb +0 -83
  41. data/app/services/solidstats/todo_service.rb +0 -114
  42. data/app/views/solidstats/dashboard/_log_monitor.html.erb +0 -759
  43. data/app/views/solidstats/dashboard/_todos.html.erb +0 -151
  44. data/app/views/solidstats/dashboard/audit/_additional_styles.css +0 -22
  45. data/app/views/solidstats/dashboard/audit/_audit_badge.html.erb +0 -5
  46. data/app/views/solidstats/dashboard/audit/_audit_details.html.erb +0 -495
  47. data/app/views/solidstats/dashboard/audit/_audit_summary.html.erb +0 -26
  48. data/app/views/solidstats/dashboard/audit/_no_vulnerabilities.html.erb +0 -3
  49. data/app/views/solidstats/dashboard/audit/_security_audit.html.erb +0 -14
  50. data/app/views/solidstats/dashboard/audit/_vulnerabilities_table.html.erb +0 -1120
  51. data/app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb +0 -63
  52. data/app/views/solidstats/dashboard/index.html.erb +0 -1351
  53. data/lib/tasks/solidstats_tasks.rake +0 -4
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :solidstats do
4
+ namespace :load_lens do
5
+ desc "Parse development log and extract LoadLens performance metrics"
6
+ task parse_logs: :environment do
7
+ result = Solidstats::LoadLensService.parse_log_and_save
8
+
9
+ if result[:success]
10
+ puts "Successfully parsed #{result[:processed]} requests for LoadLens"
11
+ else
12
+ puts "Error parsing logs for LoadLens: #{result[:error]}"
13
+ exit 1
14
+ end
15
+ end
16
+
17
+ desc "Refresh LoadLens performance data cache"
18
+ task refresh: :environment do
19
+ puts "Refreshing LoadLens performance data..."
20
+ Solidstats::LoadLensService.refresh_data
21
+ puts "LoadLens performance data refreshed successfully!"
22
+ end
23
+
24
+ desc "Show LoadLens performance data summary"
25
+ task summary: :environment do
26
+ data = Solidstats::LoadLensService.get_performance_data
27
+ summary = data[:summary]
28
+
29
+ puts "\n=== LoadLens Performance Summary ==="
30
+ puts "Total Requests: #{summary[:total_requests]}"
31
+ puts "Average Response Time: #{summary[:avg_response_time]}ms"
32
+ puts "Average View Time: #{summary[:avg_view_time]}ms"
33
+ puts "Average DB Time: #{summary[:avg_db_time]}ms"
34
+ puts "Slow Requests (>1000ms): #{summary[:slow_requests]}"
35
+ puts "Error Rate: #{summary[:error_rate]}%"
36
+ puts "Status: #{summary[:status]}"
37
+ puts "Last Updated: #{summary[:last_updated]}"
38
+ puts "===================================="
39
+ end
40
+
41
+ desc "Clean old LoadLens performance data files"
42
+ task clean_old_data: :environment do
43
+ data_dir = Rails.root.join('tmp', 'solidstats')
44
+ cutoff_date = 7.days.ago.to_date
45
+ deleted_count = 0
46
+
47
+ Dir.glob(data_dir.join('perf_*.json')).each do |file|
48
+ if match = File.basename(file).match(/perf_(\d{4}-\d{2}-\d{2})\.json/)
49
+ file_date = Date.parse(match[1])
50
+ if file_date < cutoff_date
51
+ File.delete(file)
52
+ deleted_count += 1
53
+ puts "Deleted #{File.basename(file)}"
54
+ end
55
+ end
56
+ end
57
+
58
+ puts "Cleaned #{deleted_count} old LoadLens performance data files"
59
+ end
60
+ end
61
+
62
+ # Keep performance namespace for backward compatibility
63
+ namespace :performance do
64
+ desc "Parse development log and extract performance metrics (alias for load_lens:parse_logs)"
65
+ task parse_logs: :environment do
66
+ Rake::Task["solidstats:load_lens:parse_logs"].invoke
67
+ end
68
+
69
+ desc "Refresh performance data cache (alias for load_lens:refresh)"
70
+ task refresh: :environment do
71
+ Rake::Task["solidstats:load_lens:refresh"].invoke
72
+ end
73
+
74
+ desc "Show performance data summary (alias for load_lens:summary)"
75
+ task summary: :environment do
76
+ Rake::Task["solidstats:load_lens:summary"].invoke
77
+ end
78
+
79
+ desc "Clean old performance data files (alias for load_lens:clean_old_data)"
80
+ task clean_old_data: :environment do
81
+ Rake::Task["solidstats:load_lens:clean_old_data"].invoke
82
+ end
83
+ end
84
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidstats
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 3.0.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - MezbahAlam
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-22 00:00:00.000000000 Z
11
+ date: 2025-06-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: standard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  description: 'View local project health: security dashboard with vulnerability analysis,
42
56
  gem impact assessment, code quality metrics, and project task tracking.'
43
57
  email:
@@ -51,28 +65,38 @@ files:
51
65
  - README.md
52
66
  - Rakefile
53
67
  - app/assets/stylesheets/solidstats/application.css
68
+ - app/assets/stylesheets/solidstats/dashboard.css
54
69
  - app/controllers/solidstats/application_controller.rb
55
70
  - app/controllers/solidstats/dashboard_controller.rb
71
+ - app/controllers/solidstats/logs_controller.rb
72
+ - app/controllers/solidstats/performance_controller.rb
73
+ - app/controllers/solidstats/productivity_controller.rb
74
+ - app/controllers/solidstats/quality_controller.rb
75
+ - app/controllers/solidstats/securities_controller.rb
56
76
  - app/helpers/solidstats/application_helper.rb
77
+ - app/helpers/solidstats/performance_helper.rb
78
+ - app/helpers/solidstats/productivity_helper.rb
57
79
  - app/jobs/solidstats/application_job.rb
58
80
  - app/mailers/solidstats/application_mailer.rb
59
81
  - app/models/solidstats/application_record.rb
60
- - app/services/solidstats/audit_service.rb
61
- - app/services/solidstats/data_collector_service.rb
82
+ - app/services/solidstats/bundler_audit_service.rb
83
+ - app/services/solidstats/coverage_compass_service.rb
84
+ - app/services/solidstats/load_lens_service.rb
62
85
  - app/services/solidstats/log_size_monitor_service.rb
63
- - app/services/solidstats/todo_service.rb
86
+ - app/services/solidstats/my_todo_service.rb
87
+ - app/services/solidstats/style_patrol_service.rb
64
88
  - app/views/layouts/solidstats/application.html.erb
65
- - app/views/solidstats/dashboard/_log_monitor.html.erb
66
- - app/views/solidstats/dashboard/_todos.html.erb
67
- - app/views/solidstats/dashboard/audit/_additional_styles.css
68
- - app/views/solidstats/dashboard/audit/_audit_badge.html.erb
69
- - app/views/solidstats/dashboard/audit/_audit_details.html.erb
70
- - app/views/solidstats/dashboard/audit/_audit_summary.html.erb
71
- - app/views/solidstats/dashboard/audit/_no_vulnerabilities.html.erb
72
- - app/views/solidstats/dashboard/audit/_security_audit.html.erb
73
- - app/views/solidstats/dashboard/audit/_vulnerabilities_table.html.erb
74
- - app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb
75
- - app/views/solidstats/dashboard/index.html.erb
89
+ - app/views/layouts/solidstats/dashboard.html.erb
90
+ - app/views/solidstats/dashboard/dashboard.html.erb
91
+ - app/views/solidstats/logs/logs_size.html.erb
92
+ - app/views/solidstats/performance/load_lens.html.erb
93
+ - app/views/solidstats/productivity/_todo_list.html.erb
94
+ - app/views/solidstats/productivity/my_todos.html.erb
95
+ - app/views/solidstats/quality/coverage_compass.html.erb
96
+ - app/views/solidstats/quality/style_patrol.html.erb
97
+ - app/views/solidstats/securities/bundler_audit.html.erb
98
+ - app/views/solidstats/shared/_dashboard_card.html.erb
99
+ - app/views/solidstats/shared/_quick_actions.html.erb
76
100
  - config/routes.rb
77
101
  - lib/generators/solidstats/install/install_generator.rb
78
102
  - lib/generators/solidstats/install/templates/README
@@ -80,8 +104,8 @@ files:
80
104
  - lib/solidstats/engine.rb
81
105
  - lib/solidstats/version.rb
82
106
  - lib/tasks/solidstats_install.rake
107
+ - lib/tasks/solidstats_performance.rake
83
108
  - lib/tasks/solidstats_release.rake
84
- - lib/tasks/solidstats_tasks.rake
85
109
  homepage: https://solidstats.infolily.com
86
110
  licenses:
87
111
  - MIT
@@ -97,9 +121,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
97
121
  version: 2.7.0
98
122
  required_rubygems_version: !ruby/object:Gem::Requirement
99
123
  requirements:
100
- - - ">="
124
+ - - ">"
101
125
  - !ruby/object:Gem::Version
102
- version: '0'
126
+ version: 1.3.1
103
127
  requirements: []
104
128
  rubygems_version: 3.4.19
105
129
  signing_key:
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Solidstats
4
- # Service to collect and process security audit data
5
- class AuditService < DataCollectorService
6
- # Initialize with default cache settings for audits
7
- def initialize
8
- super(Rails.root.join("tmp", "solidstats_audit.json"))
9
- end
10
-
11
- # Generate a summary for the dashboard display
12
- # @return [Hash] Summary information with status, count, and message
13
- def summary
14
- data = fetch
15
- vuln_count = data["vulnerabilities"]&.count || 0
16
-
17
- {
18
- count: vuln_count,
19
- status: determine_status(vuln_count),
20
- message: generate_message(vuln_count)
21
- }
22
- end
23
-
24
- private
25
-
26
- # Determine the status indicator based on vulnerability count
27
- # @param count [Integer] Number of vulnerabilities
28
- # @return [String] Status indicator (success, warning, or danger)
29
- def determine_status(count)
30
- case count
31
- when 0 then "success"
32
- when 1..2 then "warning"
33
- else "danger"
34
- end
35
- end
36
-
37
- # Generate a status message based on vulnerability count
38
- # @param count [Integer] Number of vulnerabilities
39
- # @return [String] Human-readable status message
40
- def generate_message(count)
41
- case count
42
- when 0 then "No vulnerabilities found"
43
- when 1 then "1 vulnerability found"
44
- else "#{count} vulnerabilities found"
45
- end
46
- end
47
-
48
- # Collect fresh audit data by running bundle-audit
49
- # @return [Hash] Parsed audit data
50
- def collect_data
51
- raw_output = `bundle audit check --update --format json`
52
- json_part = raw_output[/\{.*\}/m] # extract JSON starting from first '{'
53
- JSON.parse(json_part) rescue { "error" => "Failed to parse JSON", "vulnerabilities" => [] }
54
- end
55
- end
56
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Solidstats
4
- # Base service class for all data collectors
5
- # This class handles caching logic and provides a common interface
6
- # for all data collection services in SolidStats
7
- class DataCollectorService
8
- attr_reader :cache_file, :cache_duration
9
-
10
- # Initialize the data collector with cache configuration
11
- # @param cache_file [String] Path to the cache file
12
- # @param cache_duration [ActiveSupport::Duration] Duration to keep the cache valid
13
- def initialize(cache_file, cache_duration = 12.hours)
14
- @cache_file = cache_file
15
- @cache_duration = cache_duration
16
- end
17
-
18
- # Fetch data with caching
19
- # Returns cached data if available and not expired,
20
- # otherwise collects fresh data
21
- # @param force_refresh [Boolean] Whether to force a refresh regardless of cache state
22
- # @return [Hash] The collected data
23
- def fetch(force_refresh = false)
24
- return cached_data if fresh_cache? && !force_refresh
25
-
26
- data = collect_data
27
- save_to_cache(data)
28
- data
29
- end
30
-
31
- # Get a summary of the data for dashboard display
32
- # @return [Hash] Summary information
33
- def summary
34
- raise NotImplementedError, "Subclasses must implement summary"
35
- end
36
-
37
- private
38
-
39
- # Get data from the cache file
40
- # @return [Hash, nil] Cached data or nil if cache invalid
41
- def cached_data
42
- JSON.parse(File.read(cache_file))["output"]
43
- rescue StandardError => e
44
- Rails.logger.error "Error reading cache: #{e.message}"
45
- nil
46
- end
47
-
48
- # Check if the cache is fresh (exists and not expired)
49
- # @return [Boolean] True if cache is valid and not expired
50
- def fresh_cache?
51
- return false unless File.exist?(cache_file)
52
-
53
- begin
54
- cached_data = JSON.parse(File.read(cache_file))
55
- last_run_time = Time.parse(cached_data["timestamp"])
56
- Time.now - last_run_time < cache_duration
57
- rescue StandardError => e
58
- Rails.logger.error "Error checking cache freshness: #{e.message}"
59
- false
60
- end
61
- end
62
-
63
- # Save data to the cache file
64
- # @param data [Hash] Data to save to cache
65
- def save_to_cache(data)
66
- cache_data = {
67
- "output" => data,
68
- "timestamp" => Time.now.iso8601
69
- }
70
-
71
- FileUtils.mkdir_p(File.dirname(cache_file))
72
- File.write(cache_file, JSON.generate(cache_data))
73
- rescue StandardError => e
74
- Rails.logger.error "Error saving to cache: #{e.message}"
75
- end
76
-
77
- # Collect fresh data - to be implemented by subclasses
78
- # @return [Hash] The collected data
79
- def collect_data
80
- raise NotImplementedError, "Subclasses must implement collect_data"
81
- end
82
- end
83
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Solidstats
4
- # Service to collect and process TODO items from codebase
5
- class TodoService < DataCollectorService
6
- # Initialize with default cache settings for TODO items
7
- def initialize
8
- super(Rails.root.join("tmp", "solidstats_todos.json"))
9
- end
10
-
11
- # Generate a summary for the dashboard display
12
- # @return [Hash] Summary information with counts and status
13
- def summary
14
- todos = fetch
15
- return { count: 0, status: "success", message: "No TODO items found" } if todos.nil? || todos.empty?
16
-
17
- stats = calculate_stats(todos)
18
-
19
- {
20
- count: todos.count,
21
- status: determine_status(todos),
22
- message: generate_message(todos.count),
23
- by_type: stats[:by_type],
24
- hotspots: stats[:hotspots]
25
- }
26
- end
27
-
28
- private
29
-
30
- # Calculate statistics for the TODO items
31
- # @param todos [Array] List of TODO items
32
- # @return [Hash] Statistics about the TODO items
33
- def calculate_stats(todos)
34
- stats = {
35
- by_type: {
36
- "TODO" => todos.count { |t| (t[:type] || t["type"]) == "TODO" },
37
- "FIXME" => todos.count { |t| (t[:type] || t["type"]) == "FIXME" },
38
- "HACK" => todos.count { |t| (t[:type] || t["type"]) == "HACK" }
39
- },
40
- by_file: {}
41
- }
42
-
43
- # Group by file path
44
- todos.each do |todo|
45
- file_path = todo[:file] || todo["file"]
46
- stats[:by_file][file_path] ||= 0
47
- stats[:by_file][file_path] += 1
48
- end
49
-
50
- # Find files with most TODOs (top 5)
51
- stats[:hotspots] = stats[:by_file].sort_by { |_, count| -count }
52
- .first(5)
53
- .to_h
54
-
55
- stats
56
- end
57
-
58
- # Determine the status indicator based on TODO items
59
- # @param todos [Array] List of TODO items
60
- # @return [String] Status indicator (success, warning, or danger)
61
- def determine_status(todos)
62
- fixme_count = todos.count { |t| t[:type] == "FIXME" }
63
- hack_count = todos.count { |t| t[:type] == "HACK" }
64
-
65
- if hack_count > 0
66
- "danger"
67
- elsif fixme_count > 0
68
- "warning"
69
- elsif todos.count > 10
70
- "warning"
71
- else
72
- "success"
73
- end
74
- end
75
-
76
- # Generate a status message based on TODO count
77
- # @param count [Integer] Number of TODOs
78
- # @return [String] Human-readable status message
79
- def generate_message(count)
80
- "#{count} #{count == 1 ? 'item' : 'items'} found"
81
- end
82
-
83
- # Collect fresh TODO data by scanning the codebase
84
- # @return [Array] List of TODO items found
85
- def collect_data
86
- todos = []
87
- raw_output = `grep -r -n -E "(TODO|FIXME|HACK|todo|fixme|hack)" app lib`.split("\n")
88
-
89
- raw_output.each do |line|
90
- if line =~ /^(.+):(\d+):(.+)$/
91
- file = $1
92
- line_num = $2
93
- content = $3
94
-
95
- # Match only exact lowercase or uppercase variants
96
- type_match = content.match(/(TODO|FIXME|HACK|todo|fixme|hack)/)
97
- if type_match
98
- # Convert to uppercase for consistency
99
- type = type_match.to_s.upcase
100
-
101
- todos << {
102
- file: file,
103
- line: line_num.to_i,
104
- content: content.strip,
105
- type: type
106
- }
107
- end
108
- end
109
- end
110
-
111
- todos
112
- end
113
- end
114
- end