mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
TODO formatter
This commit is contained in:
parent
bc552d0730
commit
a1854c0aa3
5 changed files with 122 additions and 28 deletions
44
spec/ameba/formatter/todo_formatter_spec.cr
Normal file
44
spec/ameba/formatter/todo_formatter_spec.cr
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
require "../../spec_helper"
|
||||||
|
|
||||||
|
module Ameba
|
||||||
|
private def create_todo(formatter)
|
||||||
|
s = Source.new "a = 1"
|
||||||
|
s.error DummyRule.new, s.location(1, 2), "message"
|
||||||
|
formatter.finished [s]
|
||||||
|
end
|
||||||
|
|
||||||
|
describe Formatter::TODOFormatter do
|
||||||
|
file = IO::Memory.new
|
||||||
|
subject = Formatter::TODOFormatter.new IO::Memory.new, file
|
||||||
|
|
||||||
|
context "problems not reported" do
|
||||||
|
it "does not create todo" do
|
||||||
|
subject.finished [Source.new ""]
|
||||||
|
file.to_s.empty?.should be_true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "problems reported" do
|
||||||
|
it "creates a todo with header" do
|
||||||
|
create_todo subject
|
||||||
|
file.to_s.should contain "# This configuration file was generated by"
|
||||||
|
file.to_s.should contain "Ameba version #{VERSION}"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a todo with rule name" do
|
||||||
|
create_todo subject
|
||||||
|
file.to_s.should contain "DummyRule"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a todo with problems count" do
|
||||||
|
create_todo subject
|
||||||
|
file.to_s.should contain "Problems found: 1"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates a valid YAML document" do
|
||||||
|
create_todo subject
|
||||||
|
YAML.parse(file.to_s).should_not be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -46,13 +46,11 @@ module Ameba::Cli
|
||||||
def run_ameba(opts)
|
def run_ameba(opts)
|
||||||
config = Ameba::Config.load opts.config
|
config = Ameba::Config.load opts.config
|
||||||
config.files = opts.files
|
config.files = opts.files
|
||||||
config.formatter = Ameba::Formatter::BaseFormatter.new if opts.silent
|
|
||||||
|
|
||||||
|
configure_formatter(config, opts)
|
||||||
configure_rules(config, opts)
|
configure_rules(config, opts)
|
||||||
|
|
||||||
runner = Ameba.run(config)
|
exit 1 unless Ameba.run(config).success?
|
||||||
generate_config_file(config, runner, opts) if opts.generate
|
|
||||||
exit 1 unless runner.success?
|
|
||||||
rescue e
|
rescue e
|
||||||
puts "Error: #{e.message}"
|
puts "Error: #{e.message}"
|
||||||
exit 255
|
exit 255
|
||||||
|
@ -71,14 +69,14 @@ module Ameba::Cli
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def generate_config_file(config, runner, opts)
|
private def configure_formatter(config, opts)
|
||||||
failed_rules =
|
if opts.silent
|
||||||
runner.sources
|
config.formatter = Ameba::Formatter::BaseFormatter.new
|
||||||
.map { |s| s.errors.map &.rule.name }
|
elsif opts.generate
|
||||||
.flatten
|
config.formatter = Ameba::Formatter::TODOFormatter.new
|
||||||
.uniq!
|
else
|
||||||
failed_rules.each { |rule| config.update_rule rule, enabled: false }
|
config.formatter = Ameba::Formatter::DotFormatter.new
|
||||||
File.write(opts.config, config.to_yaml)
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def print_version
|
private def print_version
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Ameba::Config
|
||||||
# Creates a new instance of `Ameba::Config` based on YAML parameters.
|
# Creates a new instance of `Ameba::Config` based on YAML parameters.
|
||||||
#
|
#
|
||||||
# `Config.load` uses this constructor to instantiate new config by YAML file.
|
# `Config.load` uses this constructor to instantiate new config by YAML file.
|
||||||
protected def initialize(@config : Hash(YAML::Type, YAML::Type))
|
protected def initialize(@config : YAML::Any)
|
||||||
@rules = Rule.rules.map &.new(config)
|
@rules = Rule.rules.map &.new(config)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -31,9 +31,9 @@ class Ameba::Config
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
def self.load(path = PATH)
|
def self.load(path = PATH)
|
||||||
content = File.exists?(path) ? File.read path : "{}"
|
content = File.exists?(path) ? File.read path : ""
|
||||||
Config.new YAML.parse(content).as_h
|
Config.new YAML.parse(content)
|
||||||
rescue e
|
rescue
|
||||||
raise "Config file is invalid"
|
raise "Config file is invalid"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -80,15 +80,6 @@ class Ameba::Config
|
||||||
@rules[index] = rule
|
@rules[index] = rule
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_yaml(yaml : YAML::Builder)
|
|
||||||
yaml.mapping do
|
|
||||||
rules.each do |rule|
|
|
||||||
rule.name.to_yaml(yaml)
|
|
||||||
rule.to_yaml(yaml)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private def default_files
|
private def default_files
|
||||||
Dir["**/*.cr"].reject(&.starts_with? "lib/")
|
Dir["**/*.cr"].reject(&.starts_with? "lib/")
|
||||||
end
|
end
|
||||||
|
@ -158,8 +149,10 @@ class Ameba::Config
|
||||||
properties {}
|
properties {}
|
||||||
|
|
||||||
def self.new(config = nil)
|
def self.new(config = nil)
|
||||||
yaml = config.try &.[class_name]?.try &.to_yaml || "{}"
|
if (raw = config.try &.raw).is_a? Hash
|
||||||
from_yaml yaml
|
yaml = raw[class_name]?.try &.to_yaml
|
||||||
|
end
|
||||||
|
from_yaml yaml || "{}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,7 +21,7 @@ module Ameba::Formatter
|
||||||
# Reports a message when inspection is finished.
|
# Reports a message when inspection is finished.
|
||||||
def finished(sources)
|
def finished(sources)
|
||||||
output << "\n\n"
|
output << "\n\n"
|
||||||
failed_sources = sources.reject { |s| s.valid? }
|
failed_sources = sources.reject &.valid?
|
||||||
|
|
||||||
failed_sources.each do |source|
|
failed_sources.each do |source|
|
||||||
source.errors.each do |error|
|
source.errors.each do |error|
|
||||||
|
|
59
src/ameba/formatter/todo_formatter.cr
Normal file
59
src/ameba/formatter/todo_formatter.cr
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
module Ameba::Formatter
|
||||||
|
# A formatter that creates a todo config.
|
||||||
|
# Basically, it takes all errors reported and disables corresponding rules
|
||||||
|
# or excludes failed sources from these rules.
|
||||||
|
class TODOFormatter < DotFormatter
|
||||||
|
@io : IO::FileDescriptor | IO::Memory
|
||||||
|
|
||||||
|
def initialize(@output = STDOUT, @io = File.new(Config::PATH, mode: "w"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def finished(sources)
|
||||||
|
super
|
||||||
|
errors = sources.map(&.errors).flatten
|
||||||
|
generate_todo_config errors if errors.any?
|
||||||
|
if (io = @io).is_a?(File)
|
||||||
|
@output << "Created #{io.path}\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def generate_todo_config(errors)
|
||||||
|
@io << header
|
||||||
|
rule_errors_map(errors).each do |rule, rule_errors|
|
||||||
|
@io << "\n# Problems found: #{rule_errors.size}"
|
||||||
|
@io << rule_todo(rule, rule_errors).gsub("---", "")
|
||||||
|
end
|
||||||
|
ensure
|
||||||
|
@io.flush
|
||||||
|
end
|
||||||
|
|
||||||
|
private def rule_errors_map(errors)
|
||||||
|
Hash(Rule::Base, Array(Source::Error)).new.tap do |h|
|
||||||
|
errors.each do |error|
|
||||||
|
h[error.rule] ||= Array(Source::Error).new
|
||||||
|
h[error.rule] << error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private def header
|
||||||
|
<<-HEADER
|
||||||
|
# This configuration file was generated by `ameba --gen-config`
|
||||||
|
# on #{Time.now} using Ameba version #{VERSION}.
|
||||||
|
# The point is for the user to remove these configuration records
|
||||||
|
# one by one as the reported problems are removed from the code base.
|
||||||
|
|
||||||
|
HEADER
|
||||||
|
end
|
||||||
|
|
||||||
|
private def rule_todo(rule, errors)
|
||||||
|
rule.enabled = false
|
||||||
|
YAML.build do |yaml|
|
||||||
|
yaml.mapping do
|
||||||
|
rule.name.to_yaml(yaml)
|
||||||
|
rule.to_yaml(yaml)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue