Class: Audition::Report

Inherits:
Object
  • Object
show all
Defined in:
lib/audition/report.rb

Overview

Aggregates static findings and dynamic results into a verdict and renders them as npm-CLI-style text or JSON.

Defined Under Namespace

Classes: Style, Text

Constant Summary collapse

VERDICTS =
{
  not_ready: "not ractor-ready",
  blocked: "own code is ractor-ready; blocked by dependencies",
  risky: "risky: warnings only, no hard errors",
  ready: "ractor-ready as far as audition can tell"
}.freeze
GITHUB_LEVELS =
{
  error: "error", warning: "warning", info: "notice"
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target_type:, target_root:, findings:, dynamic_results: [], unsafe_fixes: 0, baselined: 0) ⇒ Report

Returns a new instance of Report.

Parameters:

  • target_type (Symbol)
  • target_root (String)
  • findings (Array<Finding>)

    static plus dynamic findings

  • dynamic_results (Array<Dynamic::Result>) (defaults to: [])
  • unsafe_fixes (Integer) (defaults to: 0)

    shown as the --fix-unsafe hint

  • baselined (Integer) (defaults to: 0)

    findings hidden by the baseline



89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/audition/report.rb', line 89

def initialize(target_type:, target_root:, findings:,
  dynamic_results: [], unsafe_fixes: 0,
  baselined: 0)
  @target_type = target_type
  @target_root = target_root
  @findings = findings.sort_by do |f|
    [f.path, f.line || 0, -f.severity_rank]
  end
  @dynamic_results = dynamic_results
  @unsafe_fixes = unsafe_fixes
  @baselined = baselined
end

Instance Attribute Details

#baselinedObject (readonly)

Returns the value of attribute baselined.



80
81
82
# File 'lib/audition/report.rb', line 80

def baselined
  @baselined
end

#dynamic_resultsObject (readonly)

Returns the value of attribute dynamic_results.



80
81
82
# File 'lib/audition/report.rb', line 80

def dynamic_results
  @dynamic_results
end

#findingsObject (readonly)

Returns the value of attribute findings.



80
81
82
# File 'lib/audition/report.rb', line 80

def findings
  @findings
end

#target_rootObject (readonly)

Returns the value of attribute target_root.



80
81
82
# File 'lib/audition/report.rb', line 80

def target_root
  @target_root
end

#target_typeObject (readonly)

Returns the value of attribute target_type.



80
81
82
# File 'lib/audition/report.rb', line 80

def target_type
  @target_type
end

#unsafe_fixesObject (readonly)

Returns the value of attribute unsafe_fixes.



80
81
82
# File 'lib/audition/report.rb', line 80

def unsafe_fixes
  @unsafe_fixes
end

Instance Method Details

#countsObject



127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/audition/report.rb', line 127

def counts
  @counts ||= begin
    base = {error: 0, dep_error: 0, warning: 0, info: 0,
            fixable: 0}
    findings.each_with_object(base) do |f, acc|
      if f.error? && f.dependency?
        acc[:dep_error] += 1
      else
        acc[f.severity] += 1
      end
      acc[:fixable] += 1 if f.fixable?
    end
  end
end

#dependency_errors?Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/audition/report.rb', line 123

def dependency_errors?
  counts[:dep_error].positive?
end

#own_errors?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/audition/report.rb', line 119

def own_errors?
  counts[:error].positive?
end

#to_githubString

GitHub Actions workflow commands: findings become inline PR annotations when this runs in CI.

Returns:

  • (String)

    one ::error/::warning/::notice line per finding plus a verdict line



157
158
159
160
161
162
163
164
165
166
167
# File 'lib/audition/report.rb', line 157

def to_github
  lines = findings.map do |f|
    level = GITHUB_LEVELS.fetch(f.severity)
    location = f.line ? ",line=#{f.line}" : ""
    body = workflow_escape("#{f.message}. #{f.why}")
    "::#{level} file=#{f.path}#{location}," \
    "title=audition #{f.check}::#{body}"
  end
  lines << "audition verdict: #{VERDICTS.fetch(verdict)}"
  lines.join("\n")
end

#to_jsonObject



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/audition/report.rb', line 169

def to_json(*)
  JSON.pretty_generate(
    "audition" => VERSION,
    "ruby" => RUBY_VERSION,
    "target" => {"type" => target_type.to_s,
                 "root" => target_root},
    "verdict" => verdict.to_s,
    "summary" => {
      "errors" => counts[:error],
      "dependency_errors" => counts[:dep_error],
      "warnings" => counts[:warning],
      "infos" => counts[:info],
      "fixable" => counts[:fixable]
    },
    "findings" => findings.map do |f|
      {
        "check" => f.check,
        "severity" => f.severity.to_s,
        "message" => f.message,
        "why" => f.why,
        "fix" => f.fix,
        "path" => f.path,
        "line" => f.line,
        "source" => f.source,
        "fixable" => f.fixable?,
        "dependency" => f.dependency?
      }
    end,
    "dynamic" => dynamic_results.map do |r|
      {"mode" => r.mode.to_s, "passed" => r.passed,
       "raw" => r.raw}
    end
  )
end

#to_text(style: Style.detect) ⇒ String

Returns the human-facing terminal report.

Parameters:

  • style (Style) (defaults to: Style.detect)

    rendering style (auto-detected default)

Returns:

  • (String)

    the human-facing terminal report



144
145
146
# File 'lib/audition/report.rb', line 144

def to_text(style: Style.detect)
  Text.new(self, style).render
end

#verdictSymbol

Policy: own errors condemn the target outright; dependency errors (or a failed probe with clean own findings) mean the target is fine but cannot run here yet; anything softer is merely risky.

Returns:

  • (Symbol)

    :not_ready, :blocked, :risky, or :ready



109
110
111
112
113
114
115
116
117
# File 'lib/audition/report.rb', line 109

def verdict
  return :not_ready if own_errors?
  return :blocked if dependency_errors? ||
    dynamic_results.any? { |r| !r.passed }
  return :risky if counts[:warning].positive? ||
    counts[:info].positive?

  :ready
end