-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new ruleset,
gitignore
, with rules `gitignore_required_patterns…
…` and `gitignore_forbidden_patterns` (#357) * Add new ruleset, gitignore, with rule gitignore_patterns It'll use files identified by `dirs`+`filter` (which should be `.gitignore`) and apply (at the moment, the only existing) rule `gitignore_patterns` with the default value found in the documentation * Act on CI results: thanks Windows! * Refactor it into two rules, different option name and different ruleset * Update `since` * Make naming more consistent with reality * Tweak whitespace Using OTP 27 locally :-( --------- Co-authored-by: Brujo Benavides <[email protected]>
- Loading branch information
1 parent
74260eb
commit 478df9c
Showing
9 changed files
with
245 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# `.gitignore` forbidden patterns | ||
|
||
(since [4.0.0](https://github.com/inaka/elvis_core/releases/tag/4.0.0)) | ||
|
||
Exclude, from the project's `.gitignore` file, the patterns identified by the rule. | ||
|
||
## Options | ||
|
||
- `regexes :: [string()]`. | ||
- default: `["^rebar.lock$"]`. | ||
|
||
## Example | ||
|
||
```erlang | ||
{elvis_gitignore, forbidden_patterns, #{}} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# `.gitignore` required patterns | ||
|
||
(since [4.0.0](https://github.com/inaka/elvis_core/releases/tag/4.0.0)) | ||
|
||
Include, in the project's `.gitignore` file, the patterns identified by the rule. | ||
|
||
## Options | ||
|
||
- `regexes :: [string()]`. | ||
- default: `["^.rebar3/$", | ||
"^_build/$", | ||
"^_checkouts/$", | ||
"^doc/$", | ||
"^/erl_crash.dump$", | ||
"^/rebar3.crashdump$", | ||
"^test/logs/$"]`. | ||
|
||
## Example | ||
|
||
```erlang | ||
{elvis_gitignore, required_patterns, #{}} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
-module(elvis_gitignore). | ||
|
||
-export([required_patterns/3, forbidden_patterns/3]). | ||
|
||
-define(REQUIRED_PATTERN, "Your .gitignore file should contain pattern '~s'."). | ||
-define(FORBIDDEN_PATTERN, "Your .gitignore file should not contain pattern '~s'."). | ||
|
||
-hank([{unnecessary_function_arguments, | ||
[{required_patterns, 3}, {forbidden_patterns, 3}]}]). | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Default values | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
-spec default(Rule :: atom()) -> DefaultRuleConfig :: term(). | ||
default(required_patterns) -> | ||
#{regexes => | ||
["^.rebar3/$", | ||
"^_build/$", | ||
"^_checkouts/$", | ||
"^doc/$", | ||
"^/erl_crash.dump$", | ||
"^/rebar3.crashdump$", | ||
"^test/logs/$"]}; | ||
default(forbidden_patterns) -> | ||
#{regexes => ["^rebar.lock$"]}. | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Rules | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
-spec required_patterns(elvis_config:config(), | ||
elvis_file:file(), | ||
elvis_style:empty_rule_config()) -> | ||
[elvis_result:item()]. | ||
required_patterns(_Config, #{path := Path}, RuleConfig) -> | ||
Regexes = option(regexes, RuleConfig, required_patterns), | ||
case file:read_file(Path) of | ||
{ok, PatternsBin} -> | ||
Patterns = elvis_utils:split_all_lines(PatternsBin), | ||
check_patterns_in_lines(Patterns, Regexes, [], required); | ||
{error, _} -> | ||
[] | ||
end. | ||
|
||
-spec forbidden_patterns(elvis_config:config(), | ||
elvis_file:file(), | ||
elvis_style:empty_rule_config()) -> | ||
[elvis_result:item()]. | ||
forbidden_patterns(_Config, #{path := Path}, RuleConfig) -> | ||
Regexes = option(regexes, RuleConfig, forbidden_patterns), | ||
case file:read_file(Path) of | ||
{ok, PatternsBin} -> | ||
Patterns = elvis_utils:split_all_lines(PatternsBin), | ||
check_patterns_in_lines(Patterns, Regexes, [], forbidden); | ||
{error, _} -> | ||
[] | ||
end. | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Private | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
%% .gitignore | ||
%% @private | ||
check_patterns_in_lines(_Lines, [], Results, _Mode) -> | ||
{ok, Results}; | ||
check_patterns_in_lines(Lines, [Pattern | Rest], Results0, Mode) -> | ||
ModeRespected = | ||
case Mode of | ||
required -> | ||
lists:any(fun(Line) -> re:run(Line, Pattern) =/= nomatch end, Lines); | ||
forbidden -> | ||
lists:all(fun(Line) -> re:run(Line, Pattern) =:= nomatch end, Lines) | ||
end, | ||
Results = | ||
case ModeRespected of | ||
true -> | ||
Results0; | ||
false when Mode =:= required -> | ||
[elvis_result:new(item, ?REQUIRED_PATTERN, [Pattern]) | Results0]; | ||
false when Mode =:= forbidden -> | ||
[elvis_result:new(item, ?FORBIDDEN_PATTERN, [Pattern]) | Results0] | ||
end, | ||
check_patterns_in_lines(Lines, Rest, Results, Mode). | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Internal Function Definitions | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
-spec option(OptionName, RuleConfig, Rule) -> OptionValue | ||
when OptionName :: atom(), | ||
RuleConfig :: elvis_config:config(), | ||
Rule :: atom(), | ||
OptionValue :: term(). | ||
option(OptionName, RuleConfig, Rule) -> | ||
maybe_default_option(maps:get(OptionName, RuleConfig, undefined), OptionName, Rule). | ||
|
||
-spec maybe_default_option(UserDefinedOptionValue, OptionName, Rule) -> OptionValue | ||
when UserDefinedOptionValue :: undefined | term(), | ||
OptionName :: atom(), | ||
Rule :: atom(), | ||
OptionValue :: term(). | ||
maybe_default_option(undefined = _UserDefinedOptionValue, OptionName, Rule) -> | ||
maps:get(OptionName, default(Rule)); | ||
maybe_default_option(UserDefinedOptionValue, _OptionName, _Rule) -> | ||
UserDefinedOptionValue. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
.rebar3/ | ||
_build/ | ||
|
||
_checkouts/ | ||
extra | ||
doc/ | ||
/erl_crash.dump | ||
/rebar3.crashdump | ||
test/logs/ | ||
rebar0.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.rebar3/ | ||
_build/ | ||
_checkouts/ | ||
#doc/ | ||
|
||
/erl_crash.dump | ||
/rebar3.crashdump | ||
test/logs/ | ||
rebar.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
-module(gitignore_SUITE). | ||
|
||
-behaviour(ct_suite). | ||
|
||
-export([all/0, init_per_suite/1, end_per_suite/1]). | ||
-export([verify_required_patterns/1, verify_forbidden_patterns/1]). | ||
|
||
-define(EXCLUDED_FUNS, [module_info, all, test, init_per_suite, end_per_suite]). | ||
|
||
-type config() :: [{atom(), term()}]. | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Common test | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
-spec all() -> [atom()]. | ||
all() -> | ||
Exports = ?MODULE:module_info(exports), | ||
[F || {F, _} <- Exports, not lists:member(F, ?EXCLUDED_FUNS)]. | ||
|
||
-spec init_per_suite(config()) -> config(). | ||
init_per_suite(Config) -> | ||
{ok, _} = application:ensure_all_started(elvis_core), | ||
Config. | ||
|
||
-spec end_per_suite(config()) -> config(). | ||
end_per_suite(Config) -> | ||
ok = application:stop(elvis_core), | ||
Config. | ||
|
||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
%% Test Cases | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
|
||
-spec verify_required_patterns(config()) -> any(). | ||
verify_required_patterns(_Config) -> | ||
GitIgnoreConfig = elvis_test_utils:config(gitignore), | ||
[SrcDirPass, SrcDirFail] = elvis_config:dirs(GitIgnoreConfig), | ||
NoRuleConfig = #{}, | ||
|
||
PathPass = ".gitignore", | ||
{ok, FilePass} = elvis_test_utils:find_file([SrcDirPass], PathPass), | ||
{ok, []} = elvis_gitignore:required_patterns(GitIgnoreConfig, FilePass, NoRuleConfig), | ||
|
||
PathFail = ".gitignore", | ||
{ok, FileFail} = elvis_test_utils:find_file([SrcDirFail], PathFail), | ||
{ok, [Res]} = elvis_gitignore:required_patterns(GitIgnoreConfig, FileFail, NoRuleConfig), | ||
#{info := ["^doc/$"]} = Res. | ||
|
||
-spec verify_forbidden_patterns(config()) -> any(). | ||
verify_forbidden_patterns(_Config) -> | ||
GitIgnoreConfig = elvis_test_utils:config(gitignore), | ||
[SrcDirPass, SrcDirFail] = elvis_config:dirs(GitIgnoreConfig), | ||
NoRuleConfig = #{}, | ||
|
||
PathPass = ".gitignore", | ||
{ok, FilePass} = elvis_test_utils:find_file([SrcDirPass], PathPass), | ||
{ok, []} = elvis_gitignore:forbidden_patterns(GitIgnoreConfig, FilePass, NoRuleConfig), | ||
|
||
PathFail = ".gitignore", | ||
{ok, FileFail} = elvis_test_utils:find_file([SrcDirFail], PathFail), | ||
{ok, [Res]} = elvis_gitignore:forbidden_patterns(GitIgnoreConfig, FileFail, NoRuleConfig), | ||
#{info := ["^rebar.lock$"]} = Res. |