quiet_quality 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +13 -0
- data/lib/quiet_quality/config/builder.rb +13 -4
- data/lib/quiet_quality/config/file_filter.rb +6 -0
- data/lib/quiet_quality/config/parsed_options.rb +4 -1
- data/lib/quiet_quality/config/parser.rb +11 -10
- data/lib/quiet_quality/config/tool_options.rb +9 -5
- data/lib/quiet_quality/executors/execcer.rb +3 -1
- data/lib/quiet_quality/executors/pipeline.rb +3 -1
- data/lib/quiet_quality/logger.rb +4 -2
- data/lib/quiet_quality/tools/base_runner.rb +4 -2
- data/lib/quiet_quality/tools/brakeman/parser.rb +4 -0
- data/lib/quiet_quality/tools/brakeman/runner.rb +2 -2
- data/lib/quiet_quality/tools/markdown_lint/runner.rb +13 -8
- data/lib/quiet_quality/tools/relevant_runner.rb +2 -2
- data/lib/quiet_quality/tools/rspec/parser.rb +24 -1
- data/lib/quiet_quality/tools/rspec.rb +2 -0
- data/lib/quiet_quality/version.rb +1 -1
- data/quiet_quality.gemspec +4 -4
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f411385dc4547ecadf2e182ca8628a5f95973c43c7340314293b76489b5a5b5a
|
4
|
+
data.tar.gz: e414999cb5645c7d64fbcb8b52d02cae9b12be5ec8ea02ae640f2dbd434a5db2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: de6977b310cc518f46e81ca7404a3913419226c8723faa2554f52aa974759fbe572eab4486b29afe96880d8d5d80a4bc466b14ee85e8a51e2da52a46f2a335c1
|
7
|
+
data.tar.gz: 5bacf59ca7abd7004e2910f47e0cfc5fb5e4c8145faa6154b95d308ad73a0cc74a465b8a8a962b0471e4a417de09a486d11aea23f39972399633754c70be0bac
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## Release 1.5.2
|
4
|
+
|
5
|
+
* Support command/exec-command overrides (yaml-only) (#127)
|
6
|
+
* Support ruby-git 2.x (#130 resolves #129)
|
7
|
+
|
8
|
+
## Release 1.5.1
|
9
|
+
|
10
|
+
* Refactor ConfigParser to just parse the config into ParsedOptions, separating
|
11
|
+
the file-filter/excludes handling properly (#114)
|
12
|
+
* Update the standard/rubocop constraints (dev-only)
|
13
|
+
* Fail the pipeline when rspec encounters non-spec failures (#120 resolves #119)
|
14
|
+
* Expose error messages when brakeman encounters errors (#122 resolves #115)
|
15
|
+
|
3
16
|
## Release 1.5.0
|
4
17
|
|
5
18
|
* Update to comply with current standardrb rules, and use checkout@v4
|
@@ -84,7 +84,7 @@ module QuietQuality
|
|
84
84
|
|
85
85
|
def set_unless_nil(object, method, value)
|
86
86
|
return if value.nil?
|
87
|
-
object.send("#{method}=", value)
|
87
|
+
object.send(:"#{method}=", value)
|
88
88
|
end
|
89
89
|
|
90
90
|
# ---- update the global options -------------
|
@@ -129,15 +129,24 @@ module QuietQuality
|
|
129
129
|
options.tools.each do |tool_options|
|
130
130
|
update_tool_option(tool_options, :limit_targets)
|
131
131
|
update_tool_option(tool_options, :filter_messages)
|
132
|
-
update_tool_option(tool_options, :
|
132
|
+
update_tool_option(tool_options, :command, global: false)
|
133
|
+
update_tool_option(tool_options, :exec_command, global: false)
|
134
|
+
set_unless_nil(tool_options, :file_filter, build_file_filter(tool_options.tool_name))
|
133
135
|
end
|
134
136
|
end
|
135
137
|
|
136
|
-
def update_tool_option(tool_options, option_name)
|
138
|
+
def update_tool_option(tool_options, option_name, global: true)
|
137
139
|
tool_name = tool_options.tool_name
|
138
|
-
set_unless_nil(tool_options, option_name, apply.global_option(option_name))
|
140
|
+
set_unless_nil(tool_options, option_name, apply.global_option(option_name)) if global
|
139
141
|
set_unless_nil(tool_options, option_name, apply.tool_option(tool_name, option_name))
|
140
142
|
end
|
143
|
+
|
144
|
+
def build_file_filter(tool_name)
|
145
|
+
filter_string = apply.tool_option(tool_name, :file_filter)
|
146
|
+
excludes_strings = apply.tool_option(tool_name, :excludes)
|
147
|
+
return nil if filter_string.nil? && (excludes_strings.nil? || excludes_strings.empty?)
|
148
|
+
Config::FileFilter.new(regex: filter_string, excludes: excludes_strings)
|
149
|
+
end
|
141
150
|
end
|
142
151
|
end
|
143
152
|
end
|
@@ -8,6 +8,8 @@ module QuietQuality
|
|
8
8
|
@excludes_strings = excludes
|
9
9
|
end
|
10
10
|
|
11
|
+
attr_reader :regex_string, :excludes_strings
|
12
|
+
|
11
13
|
def regex
|
12
14
|
return nil if @regex_string.nil?
|
13
15
|
@_regex ||= Regexp.new(@regex_string)
|
@@ -33,6 +35,10 @@ module QuietQuality
|
|
33
35
|
regex_match?(s) && !excludes_match?(s)
|
34
36
|
end
|
35
37
|
|
38
|
+
def ==(other)
|
39
|
+
regex_string == other.regex_string && excludes_strings.sort == other.excludes_strings.sort
|
40
|
+
end
|
41
|
+
|
36
42
|
private
|
37
43
|
|
38
44
|
# The regex is an allow-match - if it's not supplied, treat everything as matching.
|
@@ -65,7 +65,10 @@ module QuietQuality
|
|
65
65
|
read_tool_option(opts, tool_name, :unfiltered, :filter_messages, as: :reversed_boolean)
|
66
66
|
read_tool_option(opts, tool_name, :changed_files, :limit_targets, as: :boolean)
|
67
67
|
read_tool_option(opts, tool_name, :all_files, :limit_targets, as: :reversed_boolean)
|
68
|
-
|
68
|
+
read_tool_option(opts, tool_name, :file_filter, :file_filter, as: :string)
|
69
|
+
read_tool_option(opts, tool_name, :excludes, :excludes, as: :strings)
|
70
|
+
read_tool_option(opts, tool_name, :command, :command, as: :strings)
|
71
|
+
read_tool_option(opts, tool_name, :exec_command, :exec_command, as: :strings)
|
69
72
|
end
|
70
73
|
|
71
74
|
def invalid!(message)
|
@@ -98,21 +101,13 @@ module QuietQuality
|
|
98
101
|
opts.set_tool_option(tool, into, coerced_value)
|
99
102
|
end
|
100
103
|
|
101
|
-
def read_file_filter(opts, tool)
|
102
|
-
parsed_regex = data.dig(tool.to_sym, :file_filter)
|
103
|
-
parsed_excludes = data.dig(tool.to_sym, :excludes)
|
104
|
-
if parsed_regex || parsed_excludes
|
105
|
-
filter = Config::FileFilter.new(regex: parsed_regex, excludes: parsed_excludes)
|
106
|
-
opts.set_tool_option(tool, :file_filter, filter)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
104
|
def validate_value(name, value, as:, from: nil)
|
111
105
|
case as
|
112
106
|
when :boolean then validate_boolean(name, value)
|
113
107
|
when :reversed_boolean then validate_boolean(name, value)
|
114
108
|
when :symbol then validate_symbol(name, value, from: from)
|
115
109
|
when :string then validate_string(name, value)
|
110
|
+
when :strings then validate_strings(name, value)
|
116
111
|
end
|
117
112
|
end
|
118
113
|
|
@@ -138,11 +133,17 @@ module QuietQuality
|
|
138
133
|
invalid!("option #{name} must not be empty") if value.empty?
|
139
134
|
end
|
140
135
|
|
136
|
+
def validate_strings(name, value)
|
137
|
+
invalid!("option #{name} must be an array") unless value.is_a?(Array)
|
138
|
+
value.each_with_index { |item, n| validate_string("#{name}[#{n}]", item) }
|
139
|
+
end
|
140
|
+
|
141
141
|
def coerce_value(value, as:)
|
142
142
|
case as
|
143
143
|
when :boolean then !!value
|
144
144
|
when :reversed_boolean then !value
|
145
145
|
when :string then value.to_s
|
146
|
+
when :strings then value.map(&:to_s)
|
146
147
|
when :symbol then value.to_sym
|
147
148
|
end
|
148
149
|
end
|
@@ -1,14 +1,16 @@
|
|
1
1
|
module QuietQuality
|
2
2
|
module Config
|
3
3
|
class ToolOptions
|
4
|
-
def initialize(tool,
|
4
|
+
def initialize(tool, **options)
|
5
5
|
@tool_name = tool.to_sym
|
6
|
-
@limit_targets = limit_targets
|
7
|
-
@filter_messages = filter_messages
|
8
|
-
@file_filter = file_filter
|
6
|
+
@limit_targets = options.fetch(:limit_targets, true)
|
7
|
+
@filter_messages = options.fetch(:filter_messages, true)
|
8
|
+
@file_filter = options.fetch(:file_filter, nil)
|
9
|
+
@command = options.fetch(:command, nil)
|
10
|
+
@exec_command = options.fetch(:exec_command, nil)
|
9
11
|
end
|
10
12
|
|
11
|
-
attr_accessor :file_filter
|
13
|
+
attr_accessor :file_filter, :command, :exec_command
|
12
14
|
attr_reader :tool_name
|
13
15
|
attr_writer :limit_targets, :filter_messages
|
14
16
|
|
@@ -38,6 +40,8 @@ module QuietQuality
|
|
38
40
|
limit_targets: limit_targets?,
|
39
41
|
filter_messages: filter_messages?,
|
40
42
|
file_filter: file_filter&.regex&.to_s,
|
43
|
+
command: command,
|
44
|
+
exec_command: exec_command,
|
41
45
|
excludes: file_filter&.excludes&.map(&:to_s)
|
42
46
|
}
|
43
47
|
end
|
@@ -32,7 +32,9 @@ module QuietQuality
|
|
32
32
|
def runner
|
33
33
|
@_runner ||= tool_options.runner_class.new(
|
34
34
|
changed_files: limit_targets? ? changed_files : nil,
|
35
|
-
file_filter: tool_options.file_filter
|
35
|
+
file_filter: tool_options.file_filter,
|
36
|
+
command_override: tool_options.command,
|
37
|
+
exec_override: tool_options.exec_command
|
36
38
|
).tap { |r| log_runner(r) }
|
37
39
|
end
|
38
40
|
|
@@ -49,7 +49,9 @@ module QuietQuality
|
|
49
49
|
def runner
|
50
50
|
@_runner ||= tool_options.runner_class.new(
|
51
51
|
changed_files: limit_targets? ? changed_files : nil,
|
52
|
-
file_filter: tool_options.file_filter
|
52
|
+
file_filter: tool_options.file_filter,
|
53
|
+
command_override: tool_options.command,
|
54
|
+
exec_override: tool_options.exec_command
|
53
55
|
).tap { |r| log_runner(r) }
|
54
56
|
end
|
55
57
|
|
data/lib/quiet_quality/logger.rb
CHANGED
@@ -53,8 +53,10 @@ module QuietQuality
|
|
53
53
|
data_text = JSON.pretty_generate(data)
|
54
54
|
message = message + "\n" + data_text
|
55
55
|
end
|
56
|
-
|
57
|
-
|
56
|
+
message.split("\n")
|
57
|
+
.map { |line| "[#{prefix}] #{line}" }
|
58
|
+
.map { |prefixed_line| colorize(prefixed_line, message_level) }
|
59
|
+
.join("\n")
|
58
60
|
end
|
59
61
|
|
60
62
|
def colorize(s, message_level)
|
@@ -6,9 +6,11 @@ module QuietQuality
|
|
6
6
|
# In general, we don't want to supply a huge number of arguments to a command-line tool.
|
7
7
|
MAX_FILES = 100
|
8
8
|
|
9
|
-
def initialize(changed_files: nil, file_filter: nil)
|
9
|
+
def initialize(changed_files: nil, file_filter: nil, command_override: nil, exec_override: nil)
|
10
10
|
@changed_files = changed_files
|
11
11
|
@file_filter = file_filter
|
12
|
+
@command_override = command_override
|
13
|
+
@exec_override = exec_override
|
12
14
|
end
|
13
15
|
|
14
16
|
def invoke!
|
@@ -38,7 +40,7 @@ module QuietQuality
|
|
38
40
|
|
39
41
|
private
|
40
42
|
|
41
|
-
attr_reader :changed_files, :file_filter
|
43
|
+
attr_reader :changed_files, :file_filter, :command_override, :exec_override
|
42
44
|
|
43
45
|
def performed_outcome
|
44
46
|
out, err, stat = Open3.capture3(*command)
|
@@ -2,6 +2,8 @@ module QuietQuality
|
|
2
2
|
module Tools
|
3
3
|
module Brakeman
|
4
4
|
class Parser
|
5
|
+
include Logging
|
6
|
+
|
5
7
|
def initialize(text)
|
6
8
|
@text = text
|
7
9
|
end
|
@@ -24,6 +26,8 @@ module QuietQuality
|
|
24
26
|
def check_errors!
|
25
27
|
errors = data[:errors]
|
26
28
|
return if errors.nil? || errors.empty?
|
29
|
+
warn "Brakeman errors:"
|
30
|
+
errors.each { |error| warn " #{error}" }
|
27
31
|
fail(ParsingError, "Found #{errors.length} errors in brakeman output")
|
28
32
|
end
|
29
33
|
|
@@ -7,11 +7,11 @@ module QuietQuality
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def command
|
10
|
-
["brakeman", "-f", "json"]
|
10
|
+
command_override || ["brakeman", "-f", "json"]
|
11
11
|
end
|
12
12
|
|
13
13
|
def exec_command
|
14
|
-
["brakeman"]
|
14
|
+
exec_override || ["brakeman"]
|
15
15
|
end
|
16
16
|
|
17
17
|
# These are specified in constants at the top of brakeman.rb:
|
@@ -12,22 +12,27 @@ module QuietQuality
|
|
12
12
|
|
13
13
|
def command(json: true)
|
14
14
|
return nil if skip_execution?
|
15
|
-
|
16
|
-
base_command << "--json" if json
|
17
|
-
if target_files.any?
|
18
|
-
base_command + target_files.sort
|
19
|
-
else
|
20
|
-
base_command + ["."]
|
21
|
-
end
|
15
|
+
(command_override || ["mdl", "--json"]) + command_targets
|
22
16
|
end
|
23
17
|
|
24
18
|
def exec_command
|
25
|
-
|
19
|
+
return nil if skip_execution?
|
20
|
+
(exec_override || ["mdl"]) + command_targets
|
26
21
|
end
|
27
22
|
|
28
23
|
def relevant_path?(path)
|
29
24
|
path.end_with?(".md")
|
30
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def command_targets
|
30
|
+
if target_files.any?
|
31
|
+
target_files.sort
|
32
|
+
else
|
33
|
+
["."]
|
34
|
+
end
|
35
|
+
end
|
31
36
|
end
|
32
37
|
end
|
33
38
|
end
|
@@ -13,12 +13,12 @@ module QuietQuality
|
|
13
13
|
|
14
14
|
def command
|
15
15
|
return nil if skip_execution?
|
16
|
-
base_command + target_files.sort
|
16
|
+
(command_override || base_command) + target_files.sort
|
17
17
|
end
|
18
18
|
|
19
19
|
def exec_command
|
20
20
|
return nil if skip_execution?
|
21
|
-
base_exec_command + target_files.sort
|
21
|
+
(exec_override || base_exec_command) + target_files.sort
|
22
22
|
end
|
23
23
|
|
24
24
|
def relevant_path?(path)
|
@@ -2,6 +2,8 @@ module QuietQuality
|
|
2
2
|
module Tools
|
3
3
|
module Rspec
|
4
4
|
class Parser
|
5
|
+
include Logging
|
6
|
+
|
5
7
|
def initialize(text)
|
6
8
|
@text = text
|
7
9
|
end
|
@@ -39,7 +41,9 @@ module QuietQuality
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def examples
|
42
|
-
@_examples
|
44
|
+
return @_examples if defined?(@_examples)
|
45
|
+
raise_if_errors_outside_of_examples!
|
46
|
+
@_examples = content.fetch(:examples)
|
43
47
|
end
|
44
48
|
|
45
49
|
def failed_examples
|
@@ -63,6 +67,25 @@ module QuietQuality
|
|
63
67
|
tool_name: TOOL_NAME
|
64
68
|
)
|
65
69
|
end
|
70
|
+
|
71
|
+
def errors_count
|
72
|
+
@_errors_count ||= content.dig(:summary, :errors_outside_of_examples_count) || 0
|
73
|
+
end
|
74
|
+
|
75
|
+
def error_messages
|
76
|
+
@_error_messages ||= content.fetch(:messages, [])
|
77
|
+
end
|
78
|
+
|
79
|
+
def raise_if_errors_outside_of_examples!
|
80
|
+
return if errors_count < 1
|
81
|
+
warn "RSpec errors:"
|
82
|
+
warn "-" * 80
|
83
|
+
error_messages.each do |msg|
|
84
|
+
warn msg
|
85
|
+
warn "-" * 80
|
86
|
+
end
|
87
|
+
fail Rspec::Error, "Rspec encountered #{errors_count} errors outside of examples"
|
88
|
+
end
|
66
89
|
end
|
67
90
|
end
|
68
91
|
end
|
data/quiet_quality.gemspec
CHANGED
@@ -31,15 +31,15 @@ Gem::Specification.new do |spec|
|
|
31
31
|
.map { |path| path.sub(/^bin\//, "") }
|
32
32
|
end
|
33
33
|
|
34
|
-
spec.add_dependency "git", "
|
34
|
+
spec.add_dependency "git", ">= 1.18"
|
35
35
|
spec.add_dependency "git_diff_parser", "~> 4"
|
36
36
|
|
37
|
-
spec.add_development_dependency "rspec", "~> 3.
|
37
|
+
spec.add_development_dependency "rspec", "~> 3.13"
|
38
38
|
spec.add_development_dependency "rspec-its", "~> 1.3"
|
39
39
|
spec.add_development_dependency "simplecov", "~> 0.22.0"
|
40
40
|
spec.add_development_dependency "pry", "~> 0.14"
|
41
|
-
spec.add_development_dependency "standard", "
|
42
|
-
spec.add_development_dependency "rubocop", "
|
41
|
+
spec.add_development_dependency "standard", ">= 1.35.1"
|
42
|
+
spec.add_development_dependency "rubocop", ">= 1.62"
|
43
43
|
spec.add_development_dependency "debug", "~> 1.7"
|
44
44
|
spec.add_development_dependency "mdl", "~> 0.12"
|
45
45
|
spec.add_development_dependency "rspec-cover_it", "~> 0.1.0"
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quiet_quality
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Mueller
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: git
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.18'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.18'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.13'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.13'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec-its
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,30 +98,30 @@ dependencies:
|
|
98
98
|
name: standard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version:
|
103
|
+
version: 1.35.1
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - "
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
110
|
+
version: 1.35.1
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rubocop
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - ">="
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '1.
|
117
|
+
version: '1.62'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '1.
|
124
|
+
version: '1.62'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: debug
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|