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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +27 -0
- data/Rakefile +3 -3
- data/app/assets/stylesheets/solidstats/dashboard.css +48 -0
- data/app/controllers/solidstats/dashboard_controller.rb +82 -60
- data/app/controllers/solidstats/logs_controller.rb +72 -0
- data/app/controllers/solidstats/performance_controller.rb +25 -0
- data/app/controllers/solidstats/productivity_controller.rb +39 -0
- data/app/controllers/solidstats/quality_controller.rb +152 -0
- data/app/controllers/solidstats/securities_controller.rb +30 -0
- data/app/helpers/solidstats/application_helper.rb +155 -0
- data/app/helpers/solidstats/performance_helper.rb +87 -0
- data/app/helpers/solidstats/productivity_helper.rb +38 -0
- data/app/services/solidstats/bundler_audit_service.rb +206 -0
- data/app/services/solidstats/coverage_compass_service.rb +335 -0
- data/app/services/solidstats/load_lens_service.rb +454 -0
- data/app/services/solidstats/log_size_monitor_service.rb +205 -74
- data/app/services/solidstats/my_todo_service.rb +242 -0
- data/app/services/solidstats/style_patrol_service.rb +319 -0
- data/app/views/layouts/solidstats/application.html.erb +9 -2
- data/app/views/layouts/solidstats/dashboard.html.erb +84 -0
- data/app/views/solidstats/dashboard/dashboard.html.erb +39 -0
- data/app/views/solidstats/logs/logs_size.html.erb +409 -0
- data/app/views/solidstats/performance/load_lens.html.erb +158 -0
- data/app/views/solidstats/productivity/_todo_list.html.erb +49 -0
- data/app/views/solidstats/productivity/my_todos.html.erb +84 -0
- data/app/views/solidstats/quality/coverage_compass.html.erb +420 -0
- data/app/views/solidstats/quality/style_patrol.html.erb +463 -0
- data/app/views/solidstats/securities/bundler_audit.html.erb +345 -0
- data/app/views/solidstats/shared/_dashboard_card.html.erb +160 -0
- data/app/views/solidstats/shared/_quick_actions.html.erb +26 -0
- data/config/routes.rb +32 -4
- data/lib/generators/solidstats/install/install_generator.rb +28 -2
- data/lib/generators/solidstats/install/templates/README +7 -0
- data/lib/solidstats/version.rb +1 -1
- data/lib/tasks/solidstats_performance.rake +84 -0
- metadata +43 -19
- data/app/services/solidstats/audit_service.rb +0 -56
- data/app/services/solidstats/data_collector_service.rb +0 -83
- data/app/services/solidstats/todo_service.rb +0 -114
- data/app/views/solidstats/dashboard/_log_monitor.html.erb +0 -759
- data/app/views/solidstats/dashboard/_todos.html.erb +0 -151
- data/app/views/solidstats/dashboard/audit/_additional_styles.css +0 -22
- data/app/views/solidstats/dashboard/audit/_audit_badge.html.erb +0 -5
- data/app/views/solidstats/dashboard/audit/_audit_details.html.erb +0 -495
- data/app/views/solidstats/dashboard/audit/_audit_summary.html.erb +0 -26
- data/app/views/solidstats/dashboard/audit/_no_vulnerabilities.html.erb +0 -3
- data/app/views/solidstats/dashboard/audit/_security_audit.html.erb +0 -14
- data/app/views/solidstats/dashboard/audit/_vulnerabilities_table.html.erb +0 -1120
- data/app/views/solidstats/dashboard/audit/_vulnerability_details.html.erb +0 -63
- data/app/views/solidstats/dashboard/index.html.erb +0 -1351
- 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:
|
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-
|
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/
|
61
|
-
- app/services/solidstats/
|
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/
|
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
|
66
|
-
- app/views/solidstats/dashboard/
|
67
|
-
- app/views/solidstats/
|
68
|
-
- app/views/solidstats/
|
69
|
-
- app/views/solidstats/
|
70
|
-
- app/views/solidstats/
|
71
|
-
- app/views/solidstats/
|
72
|
-
- app/views/solidstats/
|
73
|
-
- app/views/solidstats/
|
74
|
-
- app/views/solidstats/
|
75
|
-
- app/views/solidstats/
|
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:
|
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
|