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…
	
	Add table
		Add a link
		
	
		Reference in a new issue