Class: RailsDoctor::Scorer

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_doctor/scorer.rb

Instance Method Summary collapse

Constructor Details

#initialize(project:, config:, changed_files: []) ⇒ Scorer

Returns a new instance of Scorer.



5
6
7
8
9
# File 'lib/rails_doctor/scorer.rb', line 5

def initialize(project:, config:, changed_files: [])
  @project = project
  @config = config
  @changed_files = changed_files
end

Instance Method Details

#hotspots(findings) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rails_doctor/scorer.rb', line 35

def hotspots(findings)
  churn = @project.churn(window_days: @config.data.fetch("git").fetch("churn_window_days"))
  changed = @changed_files
  by_file = findings.select(&:file).group_by(&:file)

  by_file.map do |file, file_findings|
    severity_score = file_findings.sum { |finding| SEVERITY_WEIGHTS.fetch(finding.severity, 3) }
    churn_score = [churn.fetch(file, 0), 20].min
    changed_bonus = changed.include?(file) ? 10 : 0
    score = severity_score + churn_score + changed_bonus

    Hotspot.new(
      file: file,
      score: score,
      finding_count: file_findings.size,
      churn: churn.fetch(file, 0),
      changed: changed.include?(file),
      categories: file_findings.map(&:category).uniq.sort,
      summary: summarize_hotspot(file, file_findings, changed.include?(file))
    )
  end.sort_by { |hotspot| -hotspot.score }.first(10)
end

#score(result) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rails_doctor/scorer.rb', line 11

def score(result)
  penalties = result.findings.map do |finding|
    weight = SEVERITY_WEIGHTS.fetch(finding.severity, 3)
    confidence_multiplier = confidence_multiplier(finding.confidence)
    penalty = (weight * confidence_multiplier).round(2)
    { id: finding.id, severity: finding.severity, file: finding.file, message: finding.message, penalty: penalty }
  end

  total_penalty = penalties.sum { |item| item[:penalty] }
  changed_penalty = result.findings.select { |finding| @changed_files.include?(finding.file) }
    .sum { |finding| SEVERITY_WEIGHTS.fetch(finding.severity, 3) * confidence_multiplier(finding.confidence) }

  skipped = result.skipped_tools.size
  confidence = [[100 - (skipped * 7), 40].max, 100].min

  Score.new(
    overall: [[100 - total_penalty, 0].max.round, 100].min,
    changed_files: [[100 - changed_penalty, 0].max.round, 100].min,
    confidence: confidence,
    penalties: penalties,
    top_score_movers: penalties.sort_by { |item| -item[:penalty] }.first(5)
  )
end