mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Merge pull request #125 from crystal-ameba/config-globs
Ability to configure globs and globally excluded paths
This commit is contained in:
commit
6a913be980
4 changed files with 193 additions and 48 deletions
46
README.md
46
README.md
|
@ -24,8 +24,9 @@
|
|||
* [Docker](#docker)
|
||||
* [From sources](#from-sources)
|
||||
- [Configuration](#configuration)
|
||||
* [Only/Except](#onlyexcept)
|
||||
* [Explanation](#explanation)
|
||||
* [Sources](#sources)
|
||||
* [Rules](#rules)
|
||||
* [Explain issues](#explain-issues)
|
||||
* [Inline disabling](#inline-disabling)
|
||||
- [Editors & integrations](#editors--integrations)
|
||||
- [Credits & inspirations](#credits--inspirations)
|
||||
|
@ -150,7 +151,37 @@ It allows to configure rule properties, disable specific rules and exclude sourc
|
|||
|
||||
Generate new file by running `ameba --gen-config`.
|
||||
|
||||
### Only/Except
|
||||
### Sources
|
||||
|
||||
**List of sources to run Ameba on can be configured globally via:**
|
||||
|
||||
- `Globs` section - an array of wildcards (or paths) to include to the
|
||||
inspection. Defaults to `%w(**/*.cr !lib)`, meaning it includes all project
|
||||
files with `*.cr` extension except those which exist in `lib` folder.
|
||||
- `Excluded` section - an array of wildcards (or paths) to exclude from the
|
||||
source list defined by `Globs`. Defaults to an empty array.
|
||||
|
||||
In this example we define default globs and exclude `src/compiler` folder:
|
||||
|
||||
``` yaml
|
||||
Globs:
|
||||
- **/*.cr
|
||||
- !lib
|
||||
|
||||
Excluded:
|
||||
- src/compiler
|
||||
```
|
||||
|
||||
**Specific sources can be excluded at rule level**:
|
||||
|
||||
``` yaml
|
||||
Style/RedundantBegin:
|
||||
Excluded:
|
||||
- src/server/processor.cr
|
||||
- src/server/api.cr
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
One or more rules, or a one or more group of rules can be included or excluded
|
||||
via command line arguments:
|
||||
|
@ -162,7 +193,14 @@ $ ameba --except Lint/Syntax # runs all rules except Lint/Syntax
|
|||
$ ameba --except Style,Lint # runs all rules except rules in Style and Lint groups
|
||||
```
|
||||
|
||||
### Explanation
|
||||
Or through the configuration file:
|
||||
|
||||
``` yaml
|
||||
Style/RedundantBegin:
|
||||
Enabled: false
|
||||
```
|
||||
|
||||
### Explain issues
|
||||
|
||||
Ameba allows you to dig deeper into an issue, by showing you details about the issue
|
||||
and the reasoning by it being reported.
|
||||
|
|
|
@ -8,6 +8,70 @@ module Ameba
|
|||
Config::AVAILABLE_FORMATTERS.should_not be_nil
|
||||
end
|
||||
|
||||
describe ".new" do
|
||||
it "loads default globs when config is empty" do
|
||||
yml = YAML.parse "{}"
|
||||
config = Config.new(yml)
|
||||
config.globs.should eq Config::DEFAULT_GLOBS
|
||||
end
|
||||
|
||||
it "initializes globs as string" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Globs: src/*.cr
|
||||
CONFIG
|
||||
config = Config.new(yml)
|
||||
config.globs.should eq %w(src/*.cr)
|
||||
end
|
||||
|
||||
it "initializes globs as array" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Globs:
|
||||
- "src/*.cr"
|
||||
- "!spec"
|
||||
CONFIG
|
||||
config = Config.new(yml)
|
||||
config.globs.should eq %w(src/*.cr !spec)
|
||||
end
|
||||
|
||||
it "raises if Globs has a wrong type" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Globs: 100
|
||||
CONFIG
|
||||
expect_raises(Exception, "incorrect 'Globs' section in a config file") { Config.new(yml) }
|
||||
end
|
||||
|
||||
it "initializes excluded as string" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Excluded: spec
|
||||
CONFIG
|
||||
config = Config.new(yml)
|
||||
config.excluded.should eq %w(spec)
|
||||
end
|
||||
|
||||
it "initializes excluded as array" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Excluded:
|
||||
- spec
|
||||
- lib/*.cr
|
||||
CONFIG
|
||||
config = Config.new(yml)
|
||||
config.excluded.should eq %w(spec lib/*.cr)
|
||||
end
|
||||
|
||||
it "raises if Excluded has a wrong type" do
|
||||
yml = YAML.parse <<-CONFIG
|
||||
---
|
||||
Excluded: true
|
||||
CONFIG
|
||||
expect_raises(Exception, "incorrect 'Excluded' section in a config file") { Config.new(yml) }
|
||||
end
|
||||
end
|
||||
|
||||
describe ".load" do
|
||||
it "loads custom config" do
|
||||
config = Config.load config_sample
|
||||
|
@ -28,7 +92,7 @@ module Ameba
|
|||
config = Config.load config_sample
|
||||
|
||||
it "holds source globs" do
|
||||
config.globs.should contain "spec/ameba/config_spec.cr"
|
||||
config.globs.should eq Config::DEFAULT_GLOBS
|
||||
end
|
||||
|
||||
it "allows to set globs" do
|
||||
|
@ -37,12 +101,36 @@ module Ameba
|
|||
end
|
||||
end
|
||||
|
||||
describe "#excluded, #excluded=" do
|
||||
config = Config.load config_sample
|
||||
|
||||
it "defaults to empty array" do
|
||||
config.excluded.should be_empty
|
||||
end
|
||||
|
||||
it "allows to set excluded" do
|
||||
config.excluded = ["spec"]
|
||||
config.excluded.should eq ["spec"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#sources" do
|
||||
config = Config.load config_sample
|
||||
|
||||
it "returns list of sources" do
|
||||
config.sources.size.should be > 0
|
||||
config.sources.first.should be_a Source
|
||||
config.sources.any? { |s| s.fullpath == __FILE__ }.should be_true
|
||||
end
|
||||
|
||||
it "returns a list of sources mathing globs" do
|
||||
config.globs = %w(**/config_spec.cr)
|
||||
config.sources.size.should eq(1)
|
||||
end
|
||||
|
||||
it "returns a lisf of sources excluding 'Excluded'" do
|
||||
config.excluded = %w(**/config_spec.cr)
|
||||
config.sources.any? { |s| s.fullpath == __FILE__ }.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ module Ameba::Cli
|
|||
def run(args = ARGV)
|
||||
opts = parse_args args
|
||||
config = Config.load opts.config, opts.colors?
|
||||
config.globs = opts.globs
|
||||
config.globs = opts.globs.not_nil! if opts.globs
|
||||
config.severity = opts.fail_level.not_nil! if opts.fail_level
|
||||
|
||||
configure_formatter(config, opts)
|
||||
|
|
|
@ -25,43 +25,16 @@ class Ameba::Config
|
|||
}
|
||||
|
||||
PATH = ".ameba.yml"
|
||||
|
||||
DEFAULT_GLOBS = %w(
|
||||
**/*.cr
|
||||
!lib
|
||||
)
|
||||
|
||||
setter formatter : Formatter::BaseFormatter?
|
||||
setter globs : Array(String)?
|
||||
getter rules : Array(Rule::Base)
|
||||
property severity = Severity::Convention
|
||||
|
||||
@rule_groups : Hash(String, Array(Rule::Base))
|
||||
|
||||
# Creates a new instance of `Ameba::Config` based on YAML parameters.
|
||||
#
|
||||
# `Config.load` uses this constructor to instantiate new config by YAML file.
|
||||
protected def initialize(@config : YAML::Any)
|
||||
@rules = Rule.rules.map &.new(config).as(Rule::Base)
|
||||
@rule_groups = @rules.group_by &.group
|
||||
|
||||
if @config.as_h? && (name = @config["Formatter"]?.try &.["Name"]?)
|
||||
self.formatter = name.to_s
|
||||
end
|
||||
end
|
||||
|
||||
# Loads YAML configuration file by `path`.
|
||||
#
|
||||
# ```
|
||||
# config = Ameba::Config.load
|
||||
# ```
|
||||
#
|
||||
def self.load(path = PATH, colors = true)
|
||||
Colorize.enabled = colors
|
||||
content = File.exists?(path) ? File.read path : ""
|
||||
Config.new YAML.parse(content)
|
||||
rescue e
|
||||
raise "Config file is invalid: #{e.message}"
|
||||
end
|
||||
|
||||
def self.formatter_names
|
||||
AVAILABLE_FORMATTERS.keys.join("|")
|
||||
end
|
||||
|
||||
# Returns a list of paths (with wildcards) to files.
|
||||
# Represents a list of sources to be inspected.
|
||||
# If globs are not set, it will return default list of files.
|
||||
|
@ -71,22 +44,61 @@ class Ameba::Config
|
|||
# config.globs = ["**/*.cr"]
|
||||
# config.globs
|
||||
# ```
|
||||
property globs : Array(String)
|
||||
|
||||
# Represents a list of paths to exclude from globs.
|
||||
# Can have wildcards.
|
||||
#
|
||||
def globs
|
||||
@globs ||= default_files
|
||||
# ```
|
||||
# config = Ameba::Config.load
|
||||
# config.excluded = ["spec", "src/server/*.cr"]
|
||||
# ```
|
||||
property excluded : Array(String)
|
||||
|
||||
@rule_groups : Hash(String, Array(Rule::Base))
|
||||
|
||||
# Creates a new instance of `Ameba::Config` based on YAML parameters.
|
||||
#
|
||||
# `Config.load` uses this constructor to instantiate new config by YAML file.
|
||||
protected def initialize(config : YAML::Any)
|
||||
@rules = Rule.rules.map &.new(config).as(Rule::Base)
|
||||
@rule_groups = @rules.group_by &.group
|
||||
@excluded = load_array_section(config, "Excluded")
|
||||
@globs = load_array_section(config, "Globs", DEFAULT_GLOBS)
|
||||
|
||||
self.formatter = load_formatter_name(config)
|
||||
end
|
||||
|
||||
# Returns a list of sources.
|
||||
# Loads YAML configuration file by `path`.
|
||||
#
|
||||
# ```
|
||||
# config = Ameba::Config.load
|
||||
# ```
|
||||
#
|
||||
def self.load(path = PATH, colors = true)
|
||||
Colorize.enabled = colors
|
||||
content = File.exists?(path) ? File.read path : "{}"
|
||||
Config.new YAML.parse(content)
|
||||
rescue e
|
||||
raise "Config file is invalid: #{e.message}"
|
||||
end
|
||||
|
||||
def self.formatter_names
|
||||
AVAILABLE_FORMATTERS.keys.join("|")
|
||||
end
|
||||
|
||||
# Returns a list of sources matching globs and excluded sections.
|
||||
#
|
||||
# ```
|
||||
# config = Ameba::Config.load
|
||||
# config.sources # => list of default sources
|
||||
# config.globs = ["**/*.cr"]
|
||||
# config.excluded = ["spec"]
|
||||
# config.sources # => list of sources pointing to files found by the wildcards
|
||||
# ```
|
||||
#
|
||||
def sources
|
||||
find_files_by_globs(globs)
|
||||
(find_files_by_globs(globs) - find_files_by_globs(excluded))
|
||||
.map { |path| Source.new File.read(path), path }
|
||||
end
|
||||
|
||||
|
@ -100,7 +112,7 @@ class Ameba::Config
|
|||
# ```
|
||||
#
|
||||
def formatter
|
||||
@formatter ||= default_formatter
|
||||
@formatter ||= Formatter::DotFormatter.new
|
||||
end
|
||||
|
||||
# Sets formatter by name.
|
||||
|
@ -158,12 +170,19 @@ class Ameba::Config
|
|||
end
|
||||
end
|
||||
|
||||
private def default_files
|
||||
Dir["**/*.cr"].reject(&.starts_with? "lib/")
|
||||
private def load_formatter_name(config)
|
||||
name = config["Formatter"]?.try &.["Name"]?
|
||||
name ? name.to_s : nil
|
||||
end
|
||||
|
||||
private def default_formatter
|
||||
Formatter::DotFormatter.new
|
||||
private def load_array_section(config, section_name, default = [] of String)
|
||||
case value = config[section_name]?
|
||||
when .nil? then default
|
||||
when .as_s? then [value.to_s]
|
||||
when .as_a? then value.as_a.map(&.as_s)
|
||||
else
|
||||
raise "incorrect '#{section_name}' section in a config files"
|
||||
end
|
||||
end
|
||||
|
||||
# :nodoc:
|
||||
|
|
Loading…
Reference in a new issue