eager_eye 1.0.7 → 1.0.9

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: f19a4d72ee31d2ea100782d4fd9da6594db5f9ec78e9290723461441f58e264d
4
- data.tar.gz: d8b347ecb77010db7ebff3db74610de1516c653991d7264321f302d2b3eaf0ea
3
+ metadata.gz: 44b2f46a77bcc0bb742c6d169cebb7be6b9a8b722b64044b153397fcf7686872
4
+ data.tar.gz: 25a589c3401fe25248b6fe429e0255e5d2d9ada9b50bd7bbf467ada161e0ca95
5
5
  SHA512:
6
- metadata.gz: 6e676774f31b89d5a6948dda61c18e6c08a522f83c224d796a16dc954f3ae2fd6ef63e91bb1d4e9afe652ab4447538af5e521875bc2544833cabf429549582ff
7
- data.tar.gz: a6bde55b11a3cb95f2550ddd5592b855e2ed6accd36abf3e1fb33f00ba34343291e0eab1a17253de95990c876a9119d15ef1b9e2548cc706e7dea0c6c446a510
6
+ metadata.gz: 2ea1baa8c98a5362527e991d3712c0a3c0d821307a99e1b8b1a9a0ac76fbff5d4adcf4f4cd512990971956fcc3bd61ef97fb8c047d0b44609e4bd55ca385bfb4
7
+ data.tar.gz: 8d1590b243420e3ea3534290f15725a0aa70f3ea537aa7da05cd4648521fe284718965d27e4b00ac77ea277d4ca400107e49a18a7759780dd532c560ef1b91b3
data/CHANGELOG.md CHANGED
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.0.9] - 2025-12-26
11
+
12
+ ### Added
13
+
14
+ - **Inline Suppression Comments** - Suppress specific warnings with RuboCop-style inline comments
15
+ - `# eager_eye:disable-next-line` - Suppress next line
16
+ - `# eager_eye:disable CallbackQuery` - Suppress specific detector inline
17
+ - `# eager_eye:disable-block` / `# eager_eye:enable-block` - Suppress block of code
18
+ - `# eager_eye:disable-file DetectorName` - Suppress entire file
19
+ - Supports both CamelCase and snake_case detector names
20
+ - Can disable all detectors with `all` keyword
21
+
22
+ ### Improved
23
+
24
+ - Enhanced README with table of contents and better organization
25
+ - Improved code readability and documentation structure
26
+ - Updated version badge to v1.0.9
27
+
28
+ ## [1.0.8] - 2025-12-25
29
+
30
+ ### Added
31
+
32
+ - **Severity Levels** - error/warning/info with `--min-severity` filtering
33
+ - Defaults: `loop_association`=error, `missing_counter_cache`=info, others=warning
34
+ - Configurable via `.eager_eye.yml` (`severity_levels`, `min_severity`)
35
+
10
36
  ## [1.0.7] - 2025-12-24
11
37
 
12
38
  ### Fixed
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  <p align="center">
12
12
  <a href="https://github.com/hamzagedikkaya/eager_eye/actions/workflows/main.yml"><img src="https://github.com/hamzagedikkaya/eager_eye/actions/workflows/main.yml/badge.svg" alt="CI"></a>
13
- <a href="https://rubygems.org/gems/eager_eye"><img src="https://img.shields.io/badge/gem-v1.0.7-red.svg" alt="Gem Version"></a>
13
+ <a href="https://rubygems.org/gems/eager_eye"><img src="https://img.shields.io/badge/gem-v1.0.9-red.svg" alt="Gem Version"></a>
14
14
  <a href="https://github.com/hamzagedikkaya/eager_eye"><img src="https://img.shields.io/badge/coverage-95%25-brightgreen.svg" alt="Coverage"></a>
15
15
  <a href="https://www.ruby-lang.org/"><img src="https://img.shields.io/badge/ruby-%3E%3D%203.1-ruby.svg" alt="Ruby"></a>
16
16
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
@@ -23,6 +23,24 @@
23
23
 
24
24
  ---
25
25
 
26
+ ## Table of Contents
27
+ - [Why EagerEye?](#why-eagereye)
28
+ - [Features](#features)
29
+ - [Installation](#installation)
30
+ - [Quick Start](#quick-start)
31
+ - [Detected Issues](#detected-issues)
32
+ - [Inline Suppression](#inline-suppression)
33
+ - [Auto-fix](#auto-fix-experimental)
34
+ - [RSpec Integration](#rspec-integration)
35
+ - [Configuration](#configuration)
36
+ - [CI Integration](#ci-integration)
37
+ - [CLI Reference](#cli-reference)
38
+ - [Output Formats](#output-formats)
39
+ - [Limitations](#limitations)
40
+ - [VS Code Extension](#vs-code-extension)
41
+ - [Development](#development)
42
+ - [Contributing](#contributing)
43
+
26
44
  ## Why EagerEye?
27
45
 
28
46
  Unlike runtime tools like Bullet, EagerEye:
@@ -41,6 +59,28 @@ Unlike runtime tools like Bullet, EagerEye:
41
59
  | CI integration | Native | Requires tests |
42
60
  | False positive rate | Higher | Lower |
43
61
 
62
+ ## Features
63
+
64
+ ✨ **Detects 7 types of N+1 problems:**
65
+ - Loop associations (queries in iterations)
66
+ - Serializer nesting issues
67
+ - Missing counter caches
68
+ - Custom method queries (invisible to Bullet)
69
+ - Count in iteration patterns
70
+ - Callback query N+1s
71
+ - Pluck to array misuse
72
+
73
+ 🔧 **Developer-friendly:**
74
+ - Inline suppression (like RuboCop)
75
+ - Auto-fix support (experimental)
76
+ - JSON/Console output formats
77
+ - RSpec integration
78
+
79
+ 🚀 **CI-ready:**
80
+ - No test suite required
81
+ - GitHub Actions examples included
82
+ - Severity levels and filtering
83
+
44
84
  ## Installation
45
85
 
46
86
  Add to your Gemfile:
@@ -457,6 +497,19 @@ enabled_detectors:
457
497
  - callback_query
458
498
  - pluck_to_array
459
499
 
500
+ # Severity levels per detector (error, warning, info)
501
+ severity_levels:
502
+ loop_association: error # Definite N+1
503
+ serializer_nesting: warning
504
+ custom_method_query: warning
505
+ count_in_iteration: warning
506
+ callback_query: warning
507
+ pluck_to_array: warning # Optimization
508
+ missing_counter_cache: info # Suggestion
509
+
510
+ # Minimum severity to report (default: info)
511
+ min_severity: warning
512
+
460
513
  # Base path to analyze (default: app)
461
514
  app_path: app
462
515
 
@@ -470,6 +523,8 @@ fail_on_issues: true
470
523
  EagerEye.configure do |config|
471
524
  config.excluded_paths = ["app/legacy/**"]
472
525
  config.enabled_detectors = [:loop_association, :serializer_nesting]
526
+ config.severity_levels = { loop_association: :error, missing_counter_cache: :info }
527
+ config.min_severity = :warning
473
528
  config.app_path = "app"
474
529
  config.fail_on_issues = true
475
530
  end
@@ -512,6 +567,7 @@ Options:
512
567
  -f, --format FORMAT Output format: console, json (default: console)
513
568
  -e, --exclude PATTERN Exclude files matching pattern (can be used multiple times)
514
569
  -o, --only DETECTORS Run only specified detectors (comma-separated)
570
+ -s, --min-severity LEVEL Minimum severity to report (info, warning, error)
515
571
  --no-fail Exit with 0 even when issues are found
516
572
  --no-color Disable colored output
517
573
  -v, --version Show version
@@ -68,6 +68,10 @@ module EagerEye
68
68
  comment_parser.disabled_at?(issue.line_number, issue.detector)
69
69
  end
70
70
 
71
+ # Filter by minimum severity
72
+ min_severity = EagerEye.configuration.min_severity
73
+ file_issues.select! { |issue| issue.meets_minimum_severity?(min_severity) }
74
+
71
75
  @issues.concat(file_issues)
72
76
  end
73
77
  rescue Errno::ENOENT, Errno::EACCES => e
data/lib/eager_eye/cli.rb CHANGED
@@ -41,6 +41,7 @@ module EagerEye
41
41
  format: :console,
42
42
  exclude: [],
43
43
  only: [],
44
+ min_severity: nil,
44
45
  fail_on_issues: true,
45
46
  colorize: $stdout.tty?,
46
47
  help: false,
@@ -92,6 +93,11 @@ module EagerEye
92
93
  opts.on("-o", "--only DETECTORS", "Run only specified detectors (comma-separated)") do |detectors|
93
94
  options[:only] = detectors.split(",").map(&:strip).map(&:to_sym)
94
95
  end
96
+
97
+ opts.on("-s", "--min-severity LEVEL", %i[info warning error],
98
+ "Minimum severity to report (info, warning, error)") do |level|
99
+ options[:min_severity] = level
100
+ end
95
101
  end
96
102
 
97
103
  def add_behavior_options(opts)
@@ -140,6 +146,7 @@ module EagerEye
140
146
  EagerEye.configure do |config|
141
147
  config.excluded_paths += options[:exclude]
142
148
  config.enabled_detectors = options[:only] unless options[:only].empty?
149
+ config.min_severity = options[:min_severity] if options[:min_severity]
143
150
  end
144
151
  end
145
152
 
@@ -2,12 +2,12 @@
2
2
 
3
3
  module EagerEye
4
4
  class CommentParser
5
- DISABLE_PATTERN = /eager_eye:disable(?:-next-line|-file)?\s+(.+?)(?:\s+--|$)/i
6
- ENABLE_PATTERN = /eager_eye:enable\s+(.+?)(?:\s+--|$)/i
7
- INLINE_DISABLE_PATTERN = /eager_eye:disable\s+(.+?)(?:\s+--|$)/i
8
5
  FILE_DISABLE_PATTERN = /eager_eye:disable-file\s+(.+?)(?:\s+--|$)/i
9
- NEXT_LINE_PATTERN = /eager_eye:disable-next-line\s+(.+?)(?:\s+--|$)/i
10
- BLOCK_DISABLE_PATTERN = /eager_eye:disable\s+(.+?)(?:\s+--|$)/i
6
+ NEXT_LINE_PATTERN = /eager_eye:disable-next-line(?:\s+(.+?))?(?:\s+--|$)/i
7
+ BLOCK_START_PATTERN = /eager_eye:disable-block(?:\s+(.+?))?(?:\s+--|$)/i
8
+ BLOCK_END_PATTERN = /eager_eye:enable-block(?:\s+(.+?))?(?:\s+--|$)/i
9
+ INLINE_DISABLE_PATTERN = /eager_eye:disable\s+(.+?)(?:\s+--|$)/i
10
+ ENABLE_PATTERN = /eager_eye:enable(?:\s+(.+?))?(?:\s+--|$)/i
11
11
 
12
12
  def initialize(source_code)
13
13
  @source_code = source_code.encode("UTF-8", invalid: :replace, undef: :replace)
@@ -46,39 +46,50 @@ module EagerEye
46
46
  def detect_directive(line, line_num)
47
47
  detect_file_directive(line, line_num) ||
48
48
  detect_next_line_directive(line) ||
49
- detect_block_directive(line) ||
50
- detect_enable_directive(line) ||
51
- detect_inline_directive(line)
49
+ detect_block_end_directive(line) ||
50
+ detect_block_or_inline_directive(line)
52
51
  end
53
52
 
54
53
  def detect_file_directive(line, line_num)
55
54
  return unless line_num <= 5 && line =~ FILE_DISABLE_PATTERN
56
55
 
57
- { type: :file, detectors: parse_detector_names(::Regexp.last_match(1)) }
56
+ detectors = parse_detector_names(::Regexp.last_match(1) || "all")
57
+ { type: :file, detectors: detectors }
58
58
  end
59
59
 
60
60
  def detect_next_line_directive(line)
61
61
  return unless line =~ NEXT_LINE_PATTERN
62
62
 
63
- { type: :next_line, detectors: parse_detector_names(::Regexp.last_match(1)) }
63
+ detectors = parse_detector_names(::Regexp.last_match(1) || "all")
64
+ { type: :next_line, detectors: detectors }
64
65
  end
65
66
 
66
- def detect_block_directive(line)
67
- return unless line =~ BLOCK_DISABLE_PATTERN && !inline_disable?(line)
68
-
69
- { type: :block_start, detectors: parse_detector_names(::Regexp.last_match(1)) }
70
- end
71
-
72
- def detect_enable_directive(line)
67
+ def detect_block_end_directive(line)
73
68
  return unless line =~ ENABLE_PATTERN
74
69
 
75
- { type: :block_end, detectors: parse_detector_names(::Regexp.last_match(1)) }
70
+ detectors = parse_detector_names(::Regexp.last_match(1) || "all")
71
+ { type: :block_end, detectors: detectors }
76
72
  end
77
73
 
78
- def detect_inline_directive(line)
74
+ def detect_block_or_inline_directive(line)
75
+ # Check for eager_eye:disable-block explicitly
76
+ if line =~ BLOCK_START_PATTERN && !code_before_comment?(line)
77
+ detectors = parse_detector_names(::Regexp.last_match(1) || "all")
78
+ return { type: :block_start, detectors: detectors }
79
+ end
80
+
81
+ # Check for eager_eye:disable (either inline or block start)
79
82
  return unless line =~ INLINE_DISABLE_PATTERN
80
83
 
81
- { type: :inline, detectors: parse_detector_names(::Regexp.last_match(1)) }
84
+ detectors = parse_detector_names(::Regexp.last_match(1) || "all")
85
+
86
+ # If there's code before the comment, it's inline (same line only)
87
+ if code_before_comment?(line)
88
+ { type: :inline, detectors: detectors }
89
+ else
90
+ # No code before comment, so it's a block start
91
+ { type: :block_start, detectors: detectors }
92
+ end
82
93
  end
83
94
 
84
95
  def apply_directive(directive, line_num)
@@ -129,7 +140,14 @@ module EagerEye
129
140
  code_part && !code_part.strip.empty?
130
141
  end
131
142
 
143
+ def code_before_comment?(line)
144
+ code_part = line.split("#").first
145
+ code_part && !code_part.strip.empty?
146
+ end
147
+
132
148
  def parse_detector_names(str)
149
+ return ["all"] if str.nil? || str.strip.empty?
150
+
133
151
  str.split(/[,\s]+/).map(&:strip).reject(&:empty?).map do |name|
134
152
  normalize_detector_name(name)
135
153
  end
@@ -2,7 +2,8 @@
2
2
 
3
3
  module EagerEye
4
4
  class Configuration
5
- attr_accessor :excluded_paths, :enabled_detectors, :app_path, :fail_on_issues
5
+ attr_accessor :excluded_paths, :enabled_detectors, :app_path, :fail_on_issues,
6
+ :severity_levels, :min_severity
6
7
 
7
8
  DEFAULT_DETECTORS = %i[
8
9
  loop_association serializer_nesting missing_counter_cache
@@ -10,11 +11,33 @@ module EagerEye
10
11
  pluck_to_array
11
12
  ].freeze
12
13
 
14
+ DEFAULT_SEVERITY_LEVELS = {
15
+ loop_association: :error,
16
+ serializer_nesting: :warning,
17
+ missing_counter_cache: :info,
18
+ custom_method_query: :warning,
19
+ count_in_iteration: :warning,
20
+ callback_query: :warning,
21
+ pluck_to_array: :warning
22
+ }.freeze
23
+
24
+ VALID_SEVERITIES = %i[info warning error].freeze
25
+
13
26
  def initialize
14
27
  @excluded_paths = []
15
28
  @enabled_detectors = DEFAULT_DETECTORS.dup
16
29
  @app_path = "app"
17
30
  @fail_on_issues = true
31
+ @severity_levels = DEFAULT_SEVERITY_LEVELS.dup
32
+ @min_severity = :info
33
+ end
34
+
35
+ def severity_for(detector_name)
36
+ severity_levels.fetch(detector_name.to_sym, :warning)
37
+ end
38
+
39
+ def valid_severity?(severity)
40
+ VALID_SEVERITIES.include?(severity.to_sym)
18
41
  end
19
42
  end
20
43
  end
@@ -9,6 +9,10 @@ module EagerEye
9
9
  def detector_name
10
10
  raise NotImplementedError, "Subclasses must implement .detector_name"
11
11
  end
12
+
13
+ def default_severity
14
+ :warning
15
+ end
12
16
  end
13
17
 
14
18
  def detect(_ast, _file_path)
@@ -17,17 +21,22 @@ module EagerEye
17
21
 
18
22
  protected
19
23
 
20
- def create_issue(file_path:, line_number:, message:, severity: :warning, suggestion: nil)
24
+ def create_issue(file_path:, line_number:, message:, severity: nil, suggestion: nil)
25
+ resolved_severity = severity || configured_severity
21
26
  Issue.new(
22
27
  detector: self.class.detector_name,
23
28
  file_path: file_path,
24
29
  line_number: line_number,
25
30
  message: message,
26
- severity: severity,
31
+ severity: resolved_severity,
27
32
  suggestion: suggestion
28
33
  )
29
34
  end
30
35
 
36
+ def configured_severity
37
+ EagerEye.configuration.severity_for(self.class.detector_name)
38
+ end
39
+
31
40
  def traverse_ast(node, &block)
32
41
  return unless node.is_a?(Parser::AST::Node)
33
42
 
@@ -128,7 +128,6 @@ module EagerEye
128
128
  file_path: @file_path,
129
129
  line_number: node.loc.line,
130
130
  message: "`.count` called on `#{receiver_chain}` inside iteration always executes a COUNT query",
131
- severity: :warning,
132
131
  suggestion: "Use `.size` instead (uses loaded collection) or add `counter_cache: true`"
133
132
  )
134
133
  end
@@ -165,7 +165,6 @@ module EagerEye
165
165
  file_path: @file_path,
166
166
  line_number: node.loc.line,
167
167
  message: "Query method `.#{method_name}` called on `#{association_chain}` inside iteration",
168
- severity: :warning,
169
168
  suggestion: "This query executes on each iteration. Consider preloading data or restructuring the query."
170
169
  )
171
170
  end
@@ -140,7 +140,6 @@ module EagerEye
140
140
  file_path: @file_path,
141
141
  line_number: node.loc.line,
142
142
  message: "Using plucked/mapped array in `where` causes two queries and holds IDs in memory",
143
- severity: :warning,
144
143
  suggestion: "Use `.select(:id)` subquery: `Model.where(col: OtherModel.condition.select(:id))`"
145
144
  )
146
145
  end
@@ -4,7 +4,8 @@ module EagerEye
4
4
  class Issue
5
5
  attr_reader :detector, :file_path, :line_number, :message, :severity, :suggestion
6
6
 
7
- VALID_SEVERITIES = %i[warning error].freeze
7
+ VALID_SEVERITIES = %i[info warning error].freeze
8
+ SEVERITY_ORDER = { info: 0, warning: 1, error: 2 }.freeze
8
9
 
9
10
  def initialize(detector:, file_path:, line_number:, message:, severity: :warning, suggestion: nil)
10
11
  @detector = detector
@@ -15,6 +16,14 @@ module EagerEye
15
16
  @suggestion = suggestion
16
17
  end
17
18
 
19
+ def severity_level
20
+ SEVERITY_ORDER[severity]
21
+ end
22
+
23
+ def meets_minimum_severity?(min_severity)
24
+ severity_level >= SEVERITY_ORDER.fetch(min_severity, 0)
25
+ end
26
+
18
27
  def to_h
19
28
  {
20
29
  detector: detector,
@@ -19,6 +19,10 @@ module EagerEye
19
19
  issues.group_by(&:file_path)
20
20
  end
21
21
 
22
+ def info_count
23
+ issues.count { |i| i.severity == :info }
24
+ end
25
+
22
26
  def warning_count
23
27
  issues.count { |i| i.severity == :warning }
24
28
  end
@@ -61,7 +61,7 @@ module EagerEye
61
61
 
62
62
  def format_issue(issue)
63
63
  detector_label = format_detector(issue.detector)
64
- severity_color = issue.severity == :error ? :red : :yellow
64
+ severity_color = severity_to_color(issue.severity)
65
65
 
66
66
  line = " Line #{issue.line_number}: "
67
67
  line += colorize("[#{detector_label}]", severity_color)
@@ -72,18 +72,24 @@ module EagerEye
72
72
  line
73
73
  end
74
74
 
75
+ def severity_to_color(severity)
76
+ { error: :red, warning: :yellow, info: :cyan }.fetch(severity, :yellow)
77
+ end
78
+
75
79
  def format_detector(detector)
76
80
  detector.to_s.split("_").map(&:capitalize).join
77
81
  end
78
82
 
79
83
  def summary
80
84
  total = issues.size
81
- warnings = warning_count
82
85
  errors = error_count
86
+ warnings = warning_count
87
+ infos = info_count
83
88
 
84
89
  "Total: #{total} issue#{"s" unless total == 1} " \
85
- "(#{warnings} warning#{"s" unless warnings == 1}, " \
86
- "#{errors} error#{"s" unless errors == 1})"
90
+ "(#{errors} error#{"s" unless errors == 1}, " \
91
+ "#{warnings} warning#{"s" unless warnings == 1}, " \
92
+ "#{infos} info)"
87
93
  end
88
94
 
89
95
  def colorize(text, color)
@@ -24,8 +24,9 @@ module EagerEye
24
24
  def summary_hash
25
25
  {
26
26
  total: issues.size,
27
- warnings: warning_count,
28
27
  errors: error_count,
28
+ warnings: warning_count,
29
+ infos: info_count,
29
30
  files_affected: issues_by_file.keys.size
30
31
  }
31
32
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EagerEye
4
- VERSION = "1.0.7"
4
+ VERSION = "1.0.9"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: eager_eye
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.7
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - hamzagedikkaya
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-12-24 00:00:00.000000000 Z
11
+ date: 2025-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ast
@@ -56,9 +56,7 @@ files:
56
56
  - README.md
57
57
  - Rakefile
58
58
  - SECURITY.md
59
- - examples/github_action.yml
60
59
  - exe/eager_eye
61
- - images/icon.png
62
60
  - lib/eager_eye.rb
63
61
  - lib/eager_eye/analyzer.rb
64
62
  - lib/eager_eye/auto_fixer.rb
@@ -1,75 +0,0 @@
1
- # Example GitHub Action workflow for using EagerEye in your Rails project
2
- # Copy this file to .github/workflows/eager_eye.yml in your repository
3
-
4
- name: EagerEye N+1 Analysis
5
-
6
- on:
7
- pull_request:
8
- paths:
9
- - "app/**/*.rb"
10
- - "lib/**/*.rb"
11
-
12
- jobs:
13
- analyze:
14
- runs-on: ubuntu-latest
15
- name: N+1 Query Detection
16
-
17
- steps:
18
- - name: Checkout code
19
- uses: actions/checkout@v4
20
-
21
- - name: Set up Ruby
22
- uses: ruby/setup-ruby@v1
23
- with:
24
- ruby-version: "3.3"
25
-
26
- - name: Install EagerEye
27
- run: gem install eager_eye
28
-
29
- - name: Run EagerEye analysis
30
- run: eager_eye app/ --format json > eager_eye_report.json
31
- continue-on-error: true
32
-
33
- - name: Upload report artifact
34
- uses: actions/upload-artifact@v4
35
- with:
36
- name: eager-eye-report
37
- path: eager_eye_report.json
38
-
39
- - name: Check for N+1 issues
40
- run: |
41
- if [ -f eager_eye_report.json ]; then
42
- issues=$(cat eager_eye_report.json | ruby -rjson -e 'puts JSON.parse(STDIN.read)["summary"]["total_issues"]')
43
- if [ "$issues" -gt 0 ]; then
44
- echo "::warning::EagerEye detected $issues potential N+1 query issue(s)"
45
- cat eager_eye_report.json | ruby -rjson -e '
46
- data = JSON.parse(STDIN.read)
47
- data["issues"].each do |issue|
48
- puts "::warning file=#{issue["file_path"]},line=#{issue["line_number"]}::#{issue["message"]}"
49
- end
50
- '
51
- else
52
- echo "No N+1 query issues detected!"
53
- fi
54
- fi
55
-
56
- # Alternative: Strict mode that fails the build on issues
57
- analyze-strict:
58
- runs-on: ubuntu-latest
59
- name: N+1 Query Detection (Strict)
60
- if: false # Set to true to enable strict mode
61
-
62
- steps:
63
- - name: Checkout code
64
- uses: actions/checkout@v4
65
-
66
- - name: Set up Ruby
67
- uses: ruby/setup-ruby@v1
68
- with:
69
- ruby-version: "3.3"
70
-
71
- - name: Install EagerEye
72
- run: gem install eager_eye
73
-
74
- - name: Run EagerEye analysis (strict)
75
- run: eager_eye app/ --no-color
data/images/icon.png DELETED
Binary file