Skip to content

Commit 0ec9dcf

Browse files
committed
fix no files found causes an error
1 parent aba42bf commit 0ec9dcf

4 files changed

Lines changed: 66 additions & 11 deletions

File tree

MIGRATION.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ subdirs).
143143
, #{ files => [".gitignore"], ruleset => gitignore }
144144
```
145145

146-
Allowed config keys per rule group are now: `files`, `ignore`, `ruleset`, `rules`. At least one glob
147-
in `files` must match at least one file.
146+
Allowed config keys per rule group are now: `files`, `ignore`, `allow_no_files`, `ruleset`, `rules`.
147+
At least one glob in `files` must match at least one file unless `allow_no_files => true` is set.
148148

149149
### Rule renames
150150

@@ -187,9 +187,10 @@ Referenced removed rules are skipped with a warning.
187187

188188
### Stricter configuration validation
189189

190-
Configuration is validated more strictly: only the keys `files`, `ignore`, `ruleset`, and `rules` are
191-
allowed per rule group; unknown keys cause validation to fail. Non‑existing rules or rulesets also
192-
fail validation (renamed/removed rules are handled as above and do not fail validation).
190+
Configuration is validated more strictly: only the keys `files`, `ignore`, `allow_no_files`,
191+
`ruleset`, and `rules` are allowed per rule group; unknown keys cause validation to fail.
192+
Non‑existing rules or rulesets also fail validation (renamed/removed rules are handled as above and
193+
do not fail validation).
193194

194195
### Parallelism default
195196

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ documentation was updated.
151151
The `files` key is a list of glob patterns that tell `elvis_core` which files to analyse. Each
152152
pattern uses [`filelib:wildcard/1`](https://erlang.org/doc/man/filelib.html#wildcard-1), so you can
153153
use patterns like `"src/*.erl"` or `"apps/**/src/*.erl"`. Matching files are run through the
154-
pre-defined rules in the specified `ruleset`.
154+
pre-defined rules in the specified `ruleset`. By default, at least one glob must match a file; set
155+
`allow_no_files => true` on a config section to allow shared optional sections, such as header-file
156+
checks, to match no files.
155157
156158
If you want to override the [pre-defined rules](#pre-defined-rules), for a given ruleset, you need
157159
to specify them in a `rules` key which is a list of items with the following structure

src/elvis_config.erl

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
ruleset := atom(),
2929
rules => [tuple()],
3030
resolved_files => dynamic(),
31-
ignore => [string()]
31+
ignore => [string()],
32+
allow_no_files => boolean()
3233
}.
3334
-export_type([t/0]).
3435

@@ -280,6 +281,8 @@ default_for([config, files]) ->
280281
[];
281282
default_for([config, ignore]) ->
282283
[];
284+
default_for([config, allow_no_files]) ->
285+
false;
283286
default_for([config, ruleset]) ->
284287
undefined;
285288
default_for([config, rules]) ->
@@ -713,9 +716,11 @@ get_config_opt(OptName, Config, true = _Compulsory) ->
713716

714717
config_is_valid(CustomRulesetNames, Config) ->
715718
maybe
716-
ok ?= map_keys_are_in(Config, [files, ignore, ruleset, rules]),
719+
ok ?= map_keys_are_in(Config, [files, ignore, allow_no_files, ruleset, rules]),
717720
{ok, FileGlobs} ?= get_config_opt(files, Config, true),
718-
ok ?= all_files_globs_are_valid(FileGlobs),
721+
{ok, AllowNoFiles} ?= get_config_opt(allow_no_files, Config, false),
722+
ok ?= is_config_boolean(allow_no_files, AllowNoFiles),
723+
ok ?= all_files_globs_are_valid(FileGlobs, AllowNoFiles),
719724
{ok, Ignore} ?= get_config_opt(ignore, Config, false),
720725
ok ?= is_list_of_ignorables(ignore, Ignore),
721726
{ok, Ruleset} ?= get_config_opt(ruleset, Config, false),
@@ -744,14 +749,18 @@ map_keys_are_in(Map, Keys) ->
744749
])}
745750
end.
746751

747-
all_files_globs_are_valid(FileGlobs) when not is_list(FileGlobs) orelse FileGlobs =:= [] ->
752+
all_files_globs_are_valid(FileGlobs, _AllowNoFiles) when
753+
not is_list(FileGlobs) orelse FileGlobs =:= []
754+
->
748755
{error, "'files' is expected to be a non-empty list."};
749-
all_files_globs_are_valid(FileGlobs) ->
756+
all_files_globs_are_valid(FileGlobs, AllowNoFiles) ->
750757
case lists:all(fun(G) -> is_list(G) andalso G =/= [] end, FileGlobs) of
751758
true ->
752759
case lists:any(fun(G) -> filelib:wildcard(G) =/= [] end, FileGlobs) of
753760
true ->
754761
ok;
762+
false when AllowNoFiles ->
763+
ok;
755764
false ->
756765
{error,
757766
io_lib:format("yielded no files to analyse in [\"~s\"].", [
@@ -762,6 +771,11 @@ all_files_globs_are_valid(FileGlobs) ->
762771
{error, "'files' is expected to be a non-empty list of non-empty strings."}
763772
end.
764773

774+
is_config_boolean(_What, Value) when is_boolean(Value) ->
775+
ok;
776+
is_config_boolean(What, _Value) ->
777+
{error, io_lib:format("'~s' is expected to be a boolean.", [What])}.
778+
765779
is_list_of_ignorables(What, List) when not is_list(List) ->
766780
{error, io_lib:format("'~s' is expected to be a list.", [What])};
767781
is_list_of_ignorables(What, List) ->

test/elvis_config_SUITE.erl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
-export([rock_with_rebar_default_config/1]).
1212
-export([throw_configuration/1]).
1313
-export([validate_config_with_string_ignore/1]).
14+
-export([validate_config_with_allow_no_files/1]).
1415
-export([validate/1]).
1516

1617
-include_lib("stdlib/include/assert.hrl").
@@ -98,6 +99,43 @@ validate_config_with_string_ignore(_Config) ->
9899
],
99100
ok = elvis_config:validate(Config, undefined).
100101

102+
validate_config_with_allow_no_files(_Config) ->
103+
FileGlobs = [
104+
"../../../../_build/test/lib/elvis_core/test/dirs/src/**/*.hrl",
105+
"../../../../_build/test/lib/elvis_core/test/dirs/test/**/*.hrl"
106+
],
107+
ConfigWithoutAllowNoFiles = [
108+
#{
109+
files => FileGlobs,
110+
ruleset => hrl_files
111+
}
112+
],
113+
?assertMatch(
114+
{error, "key 'config', at list position number 1, yielded no files to analyse in " ++ _},
115+
elvis_config:validate(ConfigWithoutAllowNoFiles, undefined)
116+
),
117+
118+
ConfigWithAllowNoFiles = [
119+
#{
120+
files => FileGlobs,
121+
ruleset => hrl_files,
122+
allow_no_files => true
123+
}
124+
],
125+
ok = elvis_config:validate(ConfigWithAllowNoFiles, undefined),
126+
ok = elvis_core:rock({config, ConfigWithAllowNoFiles}),
127+
128+
ConfigWithInvalidAllowNoFiles = [
129+
#{
130+
files => FileGlobs,
131+
ruleset => hrl_files,
132+
allow_no_files => not_a_boolean
133+
}
134+
],
135+
{error,
136+
"key 'config', at list position number 1, 'allow_no_files' is expected to be a boolean."} =
137+
elvis_config:validate(ConfigWithInvalidAllowNoFiles, undefined).
138+
101139
validate(_Config) ->
102140
ConfigDir = filename:join(["test", "examples", "configs"]),
103141
lists:foreach(

0 commit comments

Comments
 (0)