goodcheck 2.5.2 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -3
- data/LICENSE +1 -1
- data/README.md +8 -445
- data/lib/goodcheck.rb +9 -4
- data/lib/goodcheck/analyzer.rb +13 -9
- data/lib/goodcheck/buffer.rb +9 -21
- data/lib/goodcheck/cli.rb +79 -57
- data/lib/goodcheck/commands/check.rb +41 -27
- data/lib/goodcheck/commands/config_loading.rb +28 -5
- data/lib/goodcheck/commands/init.rb +4 -2
- data/lib/goodcheck/commands/pattern.rb +2 -1
- data/lib/goodcheck/commands/test.rb +38 -30
- data/lib/goodcheck/config.rb +68 -1
- data/lib/goodcheck/config_loader.rb +41 -31
- data/lib/goodcheck/error.rb +3 -0
- data/lib/goodcheck/exit_status.rb +8 -0
- data/lib/goodcheck/glob.rb +14 -3
- data/lib/goodcheck/import_loader.rb +96 -26
- data/lib/goodcheck/issue.rb +3 -3
- data/lib/goodcheck/location.rb +28 -0
- data/lib/goodcheck/logger.rb +4 -4
- data/lib/goodcheck/reporters/json.rb +6 -1
- data/lib/goodcheck/reporters/text.rb +44 -11
- data/lib/goodcheck/rule.rb +3 -1
- data/lib/goodcheck/unarchiver.rb +40 -0
- data/lib/goodcheck/version.rb +1 -1
- metadata +44 -82
- data/.github/dependabot.yml +0 -18
- data/.github/workflows/release.yml +0 -16
- data/.github/workflows/test.yml +0 -46
- data/.gitignore +0 -13
- data/.rubocop.yml +0 -5
- data/Dockerfile +0 -13
- data/Gemfile +0 -6
- data/Rakefile +0 -75
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/cheatsheet.pdf +0 -0
- data/docusaurus/.dockerignore +0 -2
- data/docusaurus/.gitignore +0 -12
- data/docusaurus/Dockerfile +0 -10
- data/docusaurus/docker-compose.yml +0 -18
- data/docusaurus/docs/commands.md +0 -69
- data/docusaurus/docs/configuration.md +0 -300
- data/docusaurus/docs/development.md +0 -15
- data/docusaurus/docs/getstarted.md +0 -46
- data/docusaurus/docs/rules.md +0 -79
- data/docusaurus/website/README.md +0 -193
- data/docusaurus/website/core/Footer.js +0 -100
- data/docusaurus/website/package.json +0 -14
- data/docusaurus/website/pages/en/index.js +0 -207
- data/docusaurus/website/pages/en/versions.js +0 -118
- data/docusaurus/website/sidebars.json +0 -11
- data/docusaurus/website/siteConfig.js +0 -171
- data/docusaurus/website/static/css/code-block-buttons.css +0 -39
- data/docusaurus/website/static/css/custom.css +0 -245
- data/docusaurus/website/static/img/favicon.ico +0 -0
- data/docusaurus/website/static/js/code-block-buttons.js +0 -47
- data/docusaurus/website/versioned_docs/version-1.0.0/commands.md +0 -70
- data/docusaurus/website/versioned_docs/version-1.0.0/configuration.md +0 -296
- data/docusaurus/website/versioned_docs/version-1.0.0/development.md +0 -16
- data/docusaurus/website/versioned_docs/version-1.0.0/getstarted.md +0 -47
- data/docusaurus/website/versioned_docs/version-1.0.0/rules.md +0 -81
- data/docusaurus/website/versioned_docs/version-1.0.2/rules.md +0 -79
- data/docusaurus/website/versioned_docs/version-2.4.0/configuration.md +0 -301
- data/docusaurus/website/versioned_docs/version-2.4.3/rules.md +0 -80
- data/docusaurus/website/versioned_sidebars/version-1.0.0-sidebars.json +0 -11
- data/docusaurus/website/versioned_sidebars/version-1.0.2-sidebars.json +0 -11
- data/docusaurus/website/versioned_sidebars/version-2.4.0-sidebars.json +0 -11
- data/docusaurus/website/versions.json +0 -12
- data/docusaurus/website/yarn.lock +0 -6604
- data/goodcheck.gemspec +0 -35
- data/goodcheck.yml +0 -10
- data/logo/GoodCheck Horizontal.pdf +0 -899
- data/logo/GoodCheck Horizontal.png +0 -0
- data/logo/GoodCheck Horizontal.svg +0 -55
- data/logo/GoodCheck logo.png +0 -0
- data/logo/GoodCheck vertical.png +0 -0
- data/sample.yml +0 -57
@@ -1,11 +1,29 @@
|
|
1
1
|
module Goodcheck
|
2
2
|
module Commands
|
3
3
|
module ConfigLoading
|
4
|
+
include ExitStatus
|
5
|
+
|
6
|
+
class ConfigFileNotFound < Error
|
7
|
+
attr_reader :path
|
8
|
+
|
9
|
+
def initialize(path:)
|
10
|
+
super(path.to_s)
|
11
|
+
@path = path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
4
15
|
attr_reader :config
|
5
16
|
|
6
17
|
def load_config!(force_download:, cache_path:)
|
18
|
+
config_content =
|
19
|
+
begin
|
20
|
+
config_path.read
|
21
|
+
rescue Errno::ENOENT
|
22
|
+
raise ConfigFileNotFound.new(path: config_path)
|
23
|
+
end
|
24
|
+
|
7
25
|
import_loader = ImportLoader.new(cache_path: cache_path, force_download: force_download, config_path: config_path)
|
8
|
-
content = JSON.parse(JSON.dump(YAML.
|
26
|
+
content = JSON.parse(JSON.dump(YAML.safe_load(config_content, filename: config_path.to_s)), symbolize_names: true)
|
9
27
|
loader = ConfigLoader.new(path: config_path, content: content, stderr: stderr, import_loader: import_loader)
|
10
28
|
@config = loader.load
|
11
29
|
end
|
@@ -13,20 +31,25 @@ module Goodcheck
|
|
13
31
|
def handle_config_errors(stderr)
|
14
32
|
begin
|
15
33
|
yield
|
16
|
-
|
34
|
+
rescue ConfigFileNotFound => exn
|
35
|
+
stderr.puts "Configuration file not found: #{exn.path}"
|
36
|
+
EXIT_ERROR
|
37
|
+
rescue ConfigLoader::InvalidPattern => exn
|
38
|
+
stderr.puts exn.message
|
39
|
+
EXIT_ERROR
|
17
40
|
rescue Psych::Exception => exn
|
18
41
|
stderr.puts "Unexpected error happens while loading YAML file: #{exn.inspect}"
|
19
42
|
exn.backtrace.each do |trace_loc|
|
20
43
|
stderr.puts " #{trace_loc}"
|
21
44
|
end
|
22
|
-
|
45
|
+
EXIT_ERROR
|
23
46
|
rescue StrongJSON::Type::TypeError, StrongJSON::Type::UnexpectedAttributeError => exn
|
24
47
|
stderr.puts "Invalid config: #{exn.message}"
|
25
48
|
stderr.puts StrongJSON::ErrorReporter.new(path: exn.path).to_s
|
26
|
-
|
49
|
+
EXIT_ERROR
|
27
50
|
rescue Errno::ENOENT => exn
|
28
51
|
stderr.puts "#{exn}"
|
29
|
-
|
52
|
+
EXIT_ERROR
|
30
53
|
end
|
31
54
|
end
|
32
55
|
end
|
@@ -58,6 +58,8 @@ rules:
|
|
58
58
|
# - vendor
|
59
59
|
EOC
|
60
60
|
|
61
|
+
include ExitStatus
|
62
|
+
|
61
63
|
attr_reader :stdout
|
62
64
|
attr_reader :stderr
|
63
65
|
attr_reader :path
|
@@ -73,7 +75,7 @@ rules:
|
|
73
75
|
def run
|
74
76
|
if path.file? && !force
|
75
77
|
stderr.puts "#{path} already exists. Try --force option to overwrite the file."
|
76
|
-
return
|
78
|
+
return EXIT_ERROR
|
77
79
|
end
|
78
80
|
|
79
81
|
path.open("w") do |io|
|
@@ -82,7 +84,7 @@ rules:
|
|
82
84
|
|
83
85
|
stdout.puts "Wrote #{path}. ✍️"
|
84
86
|
|
85
|
-
|
87
|
+
EXIT_SUCCESS
|
86
88
|
end
|
87
89
|
end
|
88
90
|
end
|
@@ -9,6 +9,7 @@ module Goodcheck
|
|
9
9
|
|
10
10
|
include ConfigLoading
|
11
11
|
include HomePath
|
12
|
+
include ExitStatus
|
12
13
|
|
13
14
|
def initialize(stdout:, stderr:, path:, ids:, home_path:)
|
14
15
|
@stdout = stdout
|
@@ -34,7 +35,7 @@ module Goodcheck
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
+
EXIT_SUCCESS
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
@@ -3,6 +3,7 @@ module Goodcheck
|
|
3
3
|
class Test
|
4
4
|
include ConfigLoading
|
5
5
|
include HomePath
|
6
|
+
include ExitStatus
|
6
7
|
|
7
8
|
attr_reader :stdout
|
8
9
|
attr_reader :stderr
|
@@ -24,18 +25,18 @@ module Goodcheck
|
|
24
25
|
|
25
26
|
if config.rules.empty?
|
26
27
|
stdout.puts "No rules."
|
27
|
-
return
|
28
|
+
return EXIT_SUCCESS
|
28
29
|
end
|
29
30
|
|
30
|
-
validate_rule_uniqueness or return
|
31
|
-
validate_rules or return
|
31
|
+
validate_rule_uniqueness or return EXIT_TEST_FAILED
|
32
|
+
validate_rules or return EXIT_TEST_FAILED
|
32
33
|
|
33
|
-
|
34
|
+
EXIT_SUCCESS
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
38
|
def validate_rule_uniqueness
|
38
|
-
stdout.puts "Validating rule
|
39
|
+
stdout.puts "Validating rule ID uniqueness..."
|
39
40
|
|
40
41
|
duplicated_ids = []
|
41
42
|
|
@@ -46,36 +47,35 @@ module Goodcheck
|
|
46
47
|
end
|
47
48
|
|
48
49
|
if duplicated_ids.empty?
|
49
|
-
stdout.puts " OK
|
50
|
+
stdout.puts Rainbow(" OK! 👍").green
|
50
51
|
true
|
51
52
|
else
|
52
53
|
count = duplicated_ids.size
|
53
|
-
|
54
|
+
duplication = count == 1 ? 'duplication' : 'duplications'
|
55
|
+
stdout.puts " Found #{Rainbow(count).bold} #{duplication}. 😱"
|
54
56
|
duplicated_ids.each do |id|
|
55
|
-
stdout.puts " #{id}"
|
57
|
+
stdout.puts " - #{Rainbow(id).background(:red)}"
|
56
58
|
end
|
57
59
|
false
|
58
60
|
end
|
59
61
|
end
|
60
62
|
|
61
63
|
def validate_rules
|
62
|
-
test_pass = true
|
63
64
|
success_count = 0
|
64
|
-
failure_count = 0
|
65
65
|
failed_rule_ids = Set[]
|
66
66
|
|
67
67
|
config.rules.each do |rule|
|
68
|
-
|
69
|
-
stdout.puts "Testing rule #{Rainbow(rule.id).cyan}..."
|
68
|
+
stdout.puts "Testing rule #{Rainbow(rule.id).cyan}..."
|
70
69
|
|
71
|
-
|
70
|
+
rule_ok = true
|
72
71
|
|
72
|
+
if rule.triggers.any? {|trigger| !trigger.passes.empty? || !trigger.fails.empty?}
|
73
73
|
rule.triggers.each.with_index do |trigger, index|
|
74
74
|
if !trigger.passes.empty? || !trigger.fails.empty?
|
75
75
|
if trigger.by_pattern?
|
76
76
|
stdout.puts " Testing pattern..."
|
77
77
|
else
|
78
|
-
stdout.puts "
|
78
|
+
stdout.puts " #{index + 1}. Testing trigger..."
|
79
79
|
end
|
80
80
|
|
81
81
|
pass_errors = trigger.passes.each.with_index.select do |pass, _|
|
@@ -87,21 +87,19 @@ module Goodcheck
|
|
87
87
|
end
|
88
88
|
|
89
89
|
unless pass_errors.empty?
|
90
|
-
test_pass = false
|
91
90
|
rule_ok = false
|
92
91
|
|
93
92
|
pass_errors.each do |_, index|
|
94
|
-
stdout.puts " #{
|
93
|
+
stdout.puts " #{index + 1}. #{Rainbow('pass').green} example matched. 😱"
|
95
94
|
failed_rule_ids << rule.id
|
96
95
|
end
|
97
96
|
end
|
98
97
|
|
99
98
|
unless fail_errors.empty?
|
100
|
-
test_pass = false
|
101
99
|
rule_ok = false
|
102
100
|
|
103
101
|
fail_errors.each do |_, index|
|
104
|
-
stdout.puts " #{
|
102
|
+
stdout.puts " #{index + 1}. #{Rainbow('fail').red} example didn’t match. 😱"
|
105
103
|
failed_rule_ids << rule.id
|
106
104
|
end
|
107
105
|
end
|
@@ -109,16 +107,27 @@ module Goodcheck
|
|
109
107
|
end
|
110
108
|
|
111
109
|
if rule.triggers.any?(&:skips_fail_examples?)
|
112
|
-
stdout.puts "
|
110
|
+
stdout.puts " The rule contains a `pattern` with `glob`, which is not supported by the test command. 🚨"
|
113
111
|
stdout.puts " Skips testing `fail` examples."
|
114
112
|
end
|
113
|
+
end
|
115
114
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
115
|
+
if rule.severity && !config.severity_allowed?(rule.severity)
|
116
|
+
allowed_severities = config.allowed_severities.map { |s| %("#{s}") }.join(', ')
|
117
|
+
stdout.puts Rainbow(" \"#{rule.severity}\" severity isn’t allowed. Must be one of #{allowed_severities}. 😱").red
|
118
|
+
rule_ok = false
|
119
|
+
failed_rule_ids << rule.id
|
120
|
+
end
|
121
|
+
|
122
|
+
if !rule.severity && config.severity_required?
|
123
|
+
stdout.puts Rainbow(" Severity is required. 😱").red
|
124
|
+
rule_ok = false
|
125
|
+
failed_rule_ids << rule.id
|
126
|
+
end
|
127
|
+
|
128
|
+
if rule_ok
|
129
|
+
stdout.puts Rainbow(" OK! 👍").green
|
130
|
+
success_count += 1
|
122
131
|
end
|
123
132
|
end
|
124
133
|
|
@@ -130,13 +139,12 @@ module Goodcheck
|
|
130
139
|
end
|
131
140
|
end
|
132
141
|
|
133
|
-
|
142
|
+
total = success_count + failed_rule_ids.size
|
134
143
|
stdout.puts ""
|
135
|
-
stdout.puts
|
136
|
-
|
137
|
-
Rainbow("#{failure_count} #{'failure'.pluralize(failure_count)}").red].join(", ")
|
144
|
+
stdout.puts "#{Rainbow(total).bold} #{total == 1 ? 'rule' : 'rules'} tested: " \
|
145
|
+
"#{Rainbow(success_count.to_s + ' successful').green.bold}, #{Rainbow(failed_rule_ids.size.to_s + ' failed').red.bold}"
|
138
146
|
|
139
|
-
|
147
|
+
failed_rule_ids.empty?
|
140
148
|
end
|
141
149
|
|
142
150
|
def rule_matches_example?(rule, trigger, example)
|
data/lib/goodcheck/config.rb
CHANGED
@@ -1,11 +1,43 @@
|
|
1
1
|
module Goodcheck
|
2
2
|
class Config
|
3
|
+
DEFAULT_EXCLUDE_BINARY = false
|
4
|
+
|
5
|
+
# https://www.iana.org/assignments/media-types/media-types.xhtml
|
6
|
+
BINARY_MIME_TYPES = %w[
|
7
|
+
audio
|
8
|
+
font
|
9
|
+
image
|
10
|
+
model
|
11
|
+
multipart
|
12
|
+
video
|
13
|
+
].to_set.freeze
|
14
|
+
BINARY_MIME_FULLTYPES = %w[
|
15
|
+
application/gzip
|
16
|
+
application/illustrator
|
17
|
+
application/pdf
|
18
|
+
application/zip
|
19
|
+
].to_set.freeze
|
20
|
+
|
3
21
|
attr_reader :rules
|
4
22
|
attr_reader :exclude_paths
|
23
|
+
attr_reader :exclude_binary
|
24
|
+
alias exclude_binary? exclude_binary
|
25
|
+
attr_reader :allowed_severities
|
26
|
+
attr_reader :severity_required
|
27
|
+
alias severity_required? severity_required
|
5
28
|
|
6
|
-
def initialize(rules:, exclude_paths:)
|
29
|
+
def initialize(rules:, exclude_paths:, exclude_binary: DEFAULT_EXCLUDE_BINARY, severity: nil)
|
7
30
|
@rules = rules
|
8
31
|
@exclude_paths = exclude_paths
|
32
|
+
@exclude_binary = exclude_binary || DEFAULT_EXCLUDE_BINARY
|
33
|
+
severity ||= {}
|
34
|
+
@allowed_severities = Set.new(severity.fetch(:allow, []))
|
35
|
+
@severity_required = severity.fetch(:required, false)
|
36
|
+
end
|
37
|
+
|
38
|
+
def severity_allowed?(severity)
|
39
|
+
return true if allowed_severities.empty?
|
40
|
+
allowed_severities.include?(severity)
|
9
41
|
end
|
10
42
|
|
11
43
|
def each_rule(filter:, &block)
|
@@ -44,5 +76,40 @@ module Goodcheck
|
|
44
76
|
enum_for(:rules_for_path, path, rules_filter: rules_filter)
|
45
77
|
end
|
46
78
|
end
|
79
|
+
|
80
|
+
def exclude_path?(path)
|
81
|
+
excluded = exclude_paths.any? do |pattern|
|
82
|
+
path.fnmatch?(pattern, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
83
|
+
end
|
84
|
+
|
85
|
+
return true if excluded
|
86
|
+
return excluded unless exclude_binary?
|
87
|
+
return excluded unless path.file?
|
88
|
+
|
89
|
+
exclude_file_by_mime_type?(path)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def exclude_file_by_mime_type?(file)
|
95
|
+
# NOTE: Lazy load to save memory
|
96
|
+
require "marcel"
|
97
|
+
|
98
|
+
fulltype = Marcel::MimeType.for(file)
|
99
|
+
type, subtype = fulltype.split("/")
|
100
|
+
|
101
|
+
case
|
102
|
+
when subtype.end_with?("+xml") # e.g. "image/svg+xml"
|
103
|
+
false
|
104
|
+
when BINARY_MIME_TYPES.include?(type)
|
105
|
+
Goodcheck.logger.debug "Exclude file: #{file} (#{fulltype})"
|
106
|
+
true
|
107
|
+
when BINARY_MIME_FULLTYPES.include?(fulltype)
|
108
|
+
Goodcheck.logger.debug "Exclude file: #{file} (#{fulltype})"
|
109
|
+
true
|
110
|
+
else
|
111
|
+
false
|
112
|
+
end
|
113
|
+
end
|
47
114
|
end
|
48
115
|
end
|
@@ -2,7 +2,7 @@ module Goodcheck
|
|
2
2
|
class ConfigLoader
|
3
3
|
include ArrayHelper
|
4
4
|
|
5
|
-
class InvalidPattern <
|
5
|
+
class InvalidPattern < Error; end
|
6
6
|
|
7
7
|
Schema = StrongJSON.new do
|
8
8
|
def self.array_or(type)
|
@@ -22,7 +22,8 @@ module Goodcheck
|
|
22
22
|
let :deprecated_token_pattern, object(token: string, case_insensitive: boolean?)
|
23
23
|
|
24
24
|
let :encoding, enum(*Encoding.name_list.map {|name| literal(name) })
|
25
|
-
let :glob_obj, object(pattern: string, encoding: optional(encoding)
|
25
|
+
let :glob_obj, object(pattern: string, encoding: optional(encoding),
|
26
|
+
exclude: enum?(string, array(string)))
|
26
27
|
let :one_glob, enum(glob_obj,
|
27
28
|
string,
|
28
29
|
detector: -> (value) {
|
@@ -102,7 +103,8 @@ module Goodcheck
|
|
102
103
|
justification: optional(array_or(string)),
|
103
104
|
glob: optional(glob),
|
104
105
|
pass: optional(array_or(string)),
|
105
|
-
fail: optional(array_or(string))
|
106
|
+
fail: optional(array_or(string)),
|
107
|
+
severity: optional(string)
|
106
108
|
)
|
107
109
|
|
108
110
|
let :negative_rule, object(
|
@@ -112,14 +114,16 @@ module Goodcheck
|
|
112
114
|
justification: optional(array_or(string)),
|
113
115
|
glob: optional(glob),
|
114
116
|
pass: optional(array_or(string)),
|
115
|
-
fail: optional(array_or(string))
|
117
|
+
fail: optional(array_or(string)),
|
118
|
+
severity: optional(string)
|
116
119
|
)
|
117
120
|
|
118
121
|
let :nopattern_rule, object(
|
119
122
|
id: string,
|
120
123
|
message: string,
|
121
124
|
justification: optional(array_or(string)),
|
122
|
-
glob: glob
|
125
|
+
glob: glob,
|
126
|
+
severity: optional(string)
|
123
127
|
)
|
124
128
|
|
125
129
|
let :positive_trigger, object(
|
@@ -162,7 +166,8 @@ module Goodcheck
|
|
162
166
|
id: string,
|
163
167
|
message: string,
|
164
168
|
justification: optional(array_or(string)),
|
165
|
-
trigger: array_or(trigger)
|
169
|
+
trigger: array_or(trigger),
|
170
|
+
severity: optional(string)
|
166
171
|
)
|
167
172
|
|
168
173
|
let :rule, enum(positive_rule,
|
@@ -186,14 +191,17 @@ module Goodcheck
|
|
186
191
|
|
187
192
|
let :rules, array(rule)
|
188
193
|
|
189
|
-
let :
|
190
|
-
|
191
|
-
|
194
|
+
let :severity, object(
|
195
|
+
allow: optional(array(string)),
|
196
|
+
required: boolean?
|
197
|
+
)
|
192
198
|
|
193
199
|
let :config, object(
|
194
200
|
rules: optional(rules),
|
195
|
-
import: optional(
|
196
|
-
exclude: optional(
|
201
|
+
import: optional(array(string)),
|
202
|
+
exclude: optional(array_or(string)),
|
203
|
+
exclude_binary: boolean?,
|
204
|
+
severity: optional(severity)
|
197
205
|
)
|
198
206
|
end
|
199
207
|
|
@@ -213,39 +221,40 @@ module Goodcheck
|
|
213
221
|
|
214
222
|
def load
|
215
223
|
Goodcheck.logger.info "Loading configuration: #{path}"
|
216
|
-
|
217
|
-
Schema.config.coerce(content)
|
224
|
+
Schema.config.coerce(content)
|
218
225
|
|
219
|
-
|
226
|
+
rules = []
|
220
227
|
|
221
|
-
|
222
|
-
|
223
|
-
Array(content[:import]).each do |import|
|
224
|
-
load_import rules, import
|
225
|
-
end
|
228
|
+
load_rules(rules, array(content[:rules]))
|
226
229
|
|
227
|
-
|
228
|
-
|
229
|
-
Config.new(rules: rules, exclude_paths: exclude_paths)
|
230
|
+
Array(content[:import]).each do |import|
|
231
|
+
load_import rules, import
|
230
232
|
end
|
233
|
+
|
234
|
+
Config.new(
|
235
|
+
rules: rules,
|
236
|
+
exclude_paths: Array(content[:exclude]),
|
237
|
+
exclude_binary: content[:exclude_binary],
|
238
|
+
severity: content[:severity]
|
239
|
+
)
|
231
240
|
end
|
232
241
|
|
233
242
|
def load_rules(rules, array)
|
234
243
|
array.each do |hash|
|
235
244
|
rules << load_rule(hash)
|
245
|
+
rescue RegexpError => exn
|
246
|
+
raise InvalidPattern, "Invalid pattern of the `#{hash.fetch(:id)}` rule in `#{path}`: #{exn.message}"
|
236
247
|
end
|
237
248
|
end
|
238
249
|
|
239
250
|
def load_import(rules, import)
|
240
251
|
Goodcheck.logger.info "Importing rules from #{import}"
|
241
252
|
|
242
|
-
|
243
|
-
|
244
|
-
json = JSON.parse(JSON.dump(YAML.load(content, filename: import)), symbolize_names: true)
|
253
|
+
import_loader.load(import) do |content, filename|
|
254
|
+
json = JSON.parse(JSON.dump(YAML.safe_load(content, filename: filename)), symbolize_names: true)
|
245
255
|
|
246
|
-
|
247
|
-
|
248
|
-
end
|
256
|
+
Schema.rules.coerce json
|
257
|
+
load_rules(rules, json)
|
249
258
|
end
|
250
259
|
end
|
251
260
|
|
@@ -256,8 +265,9 @@ module Goodcheck
|
|
256
265
|
triggers = retrieve_triggers(hash)
|
257
266
|
justifications = array(hash[:justification])
|
258
267
|
message = hash[:message].chomp
|
268
|
+
severity = hash[:severity]
|
259
269
|
|
260
|
-
Rule.new(id: id, message: message, justifications: justifications, triggers: triggers)
|
270
|
+
Rule.new(id: id, message: message, justifications: justifications, triggers: triggers, severity: severity)
|
261
271
|
end
|
262
272
|
|
263
273
|
def retrieve_triggers(hash)
|
@@ -344,9 +354,9 @@ module Goodcheck
|
|
344
354
|
globs.map do |glob|
|
345
355
|
case glob
|
346
356
|
when String
|
347
|
-
Glob.new(pattern: glob, encoding: nil)
|
357
|
+
Glob.new(pattern: glob, encoding: nil, exclude: nil)
|
348
358
|
when Hash
|
349
|
-
Glob.new(pattern: glob[:pattern], encoding: glob[:encoding])
|
359
|
+
Glob.new(pattern: glob[:pattern], encoding: glob[:encoding], exclude: glob[:exclude])
|
350
360
|
end
|
351
361
|
end
|
352
362
|
end
|