mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Merge pull request #361 from crystal-ameba/issue-275
Support hierarchical loading of the config file
This commit is contained in:
commit
3fbbe3986e
5 changed files with 62 additions and 18 deletions
|
@ -21,7 +21,7 @@ module Ameba::Cli
|
||||||
%w(-c --config).each do |f|
|
%w(-c --config).each do |f|
|
||||||
it "accepts #{f} flag" do
|
it "accepts #{f} flag" do
|
||||||
c = Cli.parse_args [f, "config.yml"]
|
c = Cli.parse_args [f, "config.yml"]
|
||||||
c.config.should eq "config.yml"
|
c.config.should eq Path["config.yml"]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -82,12 +82,6 @@ module Ameba::Cli
|
||||||
c.colors?.should be_true
|
c.colors?.should be_true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "ignores --config if --gen-config flag passed" do
|
|
||||||
c = Cli.parse_args %w(--gen-config --config my_config.yml)
|
|
||||||
c.formatter.should eq :todo
|
|
||||||
c.config.should eq ""
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "-e/--explain" do
|
describe "-e/--explain" do
|
||||||
it "configures file/line/column" do
|
it "configures file/line/column" do
|
||||||
c = Cli.parse_args %w(--explain src/file.cr:3:5)
|
c = Cli.parse_args %w(--explain src/file.cr:3:5)
|
||||||
|
@ -166,7 +160,7 @@ module Ameba::Cli
|
||||||
c.globs.should be_nil
|
c.globs.should be_nil
|
||||||
c.only.should be_nil
|
c.only.should be_nil
|
||||||
c.except.should be_nil
|
c.except.should be_nil
|
||||||
c.config.should eq Config::PATH
|
c.config.should be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -20,7 +20,7 @@ module Ameba
|
||||||
|
|
||||||
describe Formatter::TODOFormatter do
|
describe Formatter::TODOFormatter do
|
||||||
::Spec.after_each do
|
::Spec.after_each do
|
||||||
FileUtils.rm_rf(Ameba::Config::PATH)
|
FileUtils.rm_rf(Ameba::Config::DEFAULT_PATH)
|
||||||
end
|
end
|
||||||
|
|
||||||
context "problems not found" do
|
context "problems not found" do
|
||||||
|
@ -45,7 +45,7 @@ module Ameba
|
||||||
s = Source.new "a = 1", "source.cr"
|
s = Source.new "a = 1", "source.cr"
|
||||||
s.add_issue DummyRule.new, {1, 2}, "message"
|
s.add_issue DummyRule.new, {1, 2}, "message"
|
||||||
formatter.finished([s])
|
formatter.finished([s])
|
||||||
io.to_s.should contain "Created .ameba.yml"
|
io.to_s.should contain "Created #{Config::DEFAULT_PATH}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Ameba::Cli
|
||||||
end
|
end
|
||||||
|
|
||||||
private class Opts
|
private class Opts
|
||||||
property config = Config::PATH
|
property config : Path?
|
||||||
property formatter : Symbol | String | Nil
|
property formatter : Symbol | String | Nil
|
||||||
property globs : Array(String)?
|
property globs : Array(String)?
|
||||||
property only : Array(String)?
|
property only : Array(String)?
|
||||||
|
@ -76,7 +76,7 @@ module Ameba::Cli
|
||||||
|
|
||||||
parser.on("-c", "--config PATH",
|
parser.on("-c", "--config PATH",
|
||||||
"Specify a configuration file") do |path|
|
"Specify a configuration file") do |path|
|
||||||
opts.config = path unless opts.config.empty?
|
opts.config = Path[path] unless path.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on("-f", "--format FORMATTER",
|
parser.on("-f", "--format FORMATTER",
|
||||||
|
@ -105,7 +105,6 @@ module Ameba::Cli
|
||||||
parser.on("--gen-config",
|
parser.on("--gen-config",
|
||||||
"Generate a configuration file acting as a TODO list") do
|
"Generate a configuration file acting as a TODO list") do
|
||||||
opts.formatter = :todo
|
opts.formatter = :todo
|
||||||
opts.config = ""
|
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.on("--fail-level SEVERITY",
|
parser.on("--fail-level SEVERITY",
|
||||||
|
|
|
@ -10,8 +10,30 @@ require "./glob_utils"
|
||||||
# config.formatter = my_formatter
|
# config.formatter = my_formatter
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
# By default config loads `.ameba.yml` file in a current directory.
|
# By default config loads `.ameba.yml` file located in a current
|
||||||
|
# working directory.
|
||||||
#
|
#
|
||||||
|
# If it cannot be found until reaching the root directory, then it will be
|
||||||
|
# searched for in the user’s global config locations, which consists of a
|
||||||
|
# dotfile or a config file inside the XDG Base Directory specification.
|
||||||
|
#
|
||||||
|
# - `~/.ameba.yml`
|
||||||
|
# - `$XDG_CONFIG_HOME/ameba/config.yml` (expands to `~/.config/ameba/config.yml`
|
||||||
|
# if `$XDG_CONFIG_HOME` is not set)
|
||||||
|
#
|
||||||
|
# If both files exist, the dotfile will be selected.
|
||||||
|
#
|
||||||
|
# As an example, if Ameba is invoked from inside `/path/to/project/lib/utils`,
|
||||||
|
# then it will use the config as specified inside the first of the following files:
|
||||||
|
#
|
||||||
|
# - `/path/to/project/lib/utils/.ameba.yml`
|
||||||
|
# - `/path/to/project/lib/.ameba.yml`
|
||||||
|
# - `/path/to/project/.ameba.yml`
|
||||||
|
# - `/path/to/.ameba.yml`
|
||||||
|
# - `/path/.ameba.yml`
|
||||||
|
# - `/.ameba.yml`
|
||||||
|
# - `~/.ameba.yml`
|
||||||
|
# - `~/.config/ameba/config.yml`
|
||||||
class Ameba::Config
|
class Ameba::Config
|
||||||
include GlobUtils
|
include GlobUtils
|
||||||
|
|
||||||
|
@ -24,7 +46,14 @@ class Ameba::Config
|
||||||
json: Formatter::JSONFormatter,
|
json: Formatter::JSONFormatter,
|
||||||
}
|
}
|
||||||
|
|
||||||
PATH = ".ameba.yml"
|
XDG_CONFIG_HOME = ENV.fetch("XDG_CONFIG_HOME", "~/.config")
|
||||||
|
|
||||||
|
FILENAME = ".ameba.yml"
|
||||||
|
DEFAULT_PATH = Path[Dir.current] / FILENAME
|
||||||
|
DEFAULT_PATHS = {
|
||||||
|
Path["~"] / FILENAME,
|
||||||
|
Path[XDG_CONFIG_HOME] / "ameba/config.yml",
|
||||||
|
}
|
||||||
|
|
||||||
DEFAULT_GLOBS = %w(
|
DEFAULT_GLOBS = %w(
|
||||||
**/*.cr
|
**/*.cr
|
||||||
|
@ -77,14 +106,36 @@ class Ameba::Config
|
||||||
# ```
|
# ```
|
||||||
# config = Ameba::Config.load
|
# config = Ameba::Config.load
|
||||||
# ```
|
# ```
|
||||||
def self.load(path = PATH, colors = true)
|
def self.load(path = nil, colors = true)
|
||||||
Colorize.enabled = colors
|
Colorize.enabled = colors
|
||||||
content = File.exists?(path) ? File.read path : "{}"
|
content = read_config(path) || "{}"
|
||||||
Config.new YAML.parse(content)
|
Config.new YAML.parse(content)
|
||||||
rescue e
|
rescue e
|
||||||
raise "Config file is invalid: #{e.message}"
|
raise "Config file is invalid: #{e.message}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
protected def self.read_config(path = nil)
|
||||||
|
if path
|
||||||
|
return File.exists?(path) ? File.read(path) : nil
|
||||||
|
end
|
||||||
|
each_config_path do |config_path|
|
||||||
|
return File.read(config_path) if File.exists?(config_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def self.each_config_path(&)
|
||||||
|
path = Path[DEFAULT_PATH].expand(home: true)
|
||||||
|
|
||||||
|
search_paths = path.parents
|
||||||
|
search_paths.reverse_each do |search_path|
|
||||||
|
yield search_path / FILENAME
|
||||||
|
end
|
||||||
|
|
||||||
|
DEFAULT_PATHS.each do |default_path|
|
||||||
|
yield default_path
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.formatter_names
|
def self.formatter_names
|
||||||
AVAILABLE_FORMATTERS.keys.join('|')
|
AVAILABLE_FORMATTERS.keys.join('|')
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,7 +26,7 @@ module Ameba::Formatter
|
||||||
end
|
end
|
||||||
|
|
||||||
private def generate_todo_config(issues)
|
private def generate_todo_config(issues)
|
||||||
file = File.new(Config::PATH, mode: "w")
|
file = File.new(Config::DEFAULT_PATH, mode: "w")
|
||||||
file << header
|
file << header
|
||||||
rule_issues_map(issues).each do |rule, rule_issues|
|
rule_issues_map(issues).each do |rule, rule_issues|
|
||||||
file << "\n# Problems found: #{rule_issues.size}"
|
file << "\n# Problems found: #{rule_issues.size}"
|
||||||
|
|
Loading…
Reference in a new issue