goodcheck 2.4.3 → 2.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.
@@ -24,12 +24,12 @@ Gem::Specification.new do |spec|
24
24
  spec.required_ruby_version = '>= 2.4.0'
25
25
 
26
26
  spec.add_development_dependency "bundler", ">= 1.16"
27
- spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "rake", "~> 13.0"
28
28
  spec.add_development_dependency "minitest", "~> 5.0"
29
- spec.add_development_dependency "minitest-reporters", "~> 1.3.6"
29
+ spec.add_development_dependency "minitest-reporters", "~> 1.4.2"
30
30
 
31
31
  spec.add_runtime_dependency "activesupport", ">= 4.0", "< 7.0"
32
- spec.add_runtime_dependency "strong_json", "~> 1.1.0"
32
+ spec.add_runtime_dependency "strong_json", ">= 1.1", "< 2.2"
33
33
  spec.add_runtime_dependency "rainbow", "~> 3.0.0"
34
- spec.add_runtime_dependency "httpclient", "~> 2.8.3"
34
+ spec.add_runtime_dependency "psych", ">= 3.1", "< 4.0" # NOTE: Needed for old Ruby versions (<= 2.5)
35
35
  end
@@ -0,0 +1,10 @@
1
+ import:
2
+ - https://raw.githubusercontent.com/sider/goodcheck-rules/master/rules/typo.yml
3
+ - https://raw.githubusercontent.com/sider/goodcheck-rules/master/rules/ruby.yml
4
+
5
+ exclude:
6
+ - "**/build"
7
+ - "**/node_modules"
8
+ - "**/vendor"
9
+ - "**/*.{ico,pdf,png}"
10
+ - "**/yarn.lock"
@@ -5,11 +5,10 @@ require "yaml"
5
5
  require "json"
6
6
  require "active_support/core_ext/hash/indifferent_access"
7
7
  require "active_support/core_ext/integer/inflections"
8
- require "active_support/core_ext/regexp"
9
8
  require "active_support/tagged_logging"
10
9
  require "rainbow"
11
10
  require "digest/sha2"
12
- require "httpclient"
11
+ require "net/http"
13
12
 
14
13
  require "goodcheck/version"
15
14
  require "goodcheck/logger"
@@ -3,9 +3,37 @@ module Goodcheck
3
3
  attr_reader :path
4
4
  attr_reader :content
5
5
 
6
+ DISABLE_LINE_PATTERNS = [
7
+ /\/\/ goodcheck-disable-line$/, #JS, Java, C, ...
8
+ /# goodcheck-disable-line$/, # Ruby, Python, PHP, ...
9
+ /-- goodcheck-disable-line$/, # Haskel, SQL, ...
10
+ /<!-- goodcheck-disable-line -->$/, # HTML, Markdown, ...
11
+ /\/\* goodcheck-disable-line \*\/$/, # CSS, SCSS,
12
+ /\{\s*\/\* goodcheck-disable-line \*\/\s*\}$/, # JSX, ...
13
+ /<%# goodcheck-disable-line %>$/, # ERB, ...
14
+ /' goodcheck-disable-line$/, # VB
15
+ ].freeze
16
+
17
+ DISABLE_NEXT_LINE_PATTERNS = [
18
+ /\/\/ goodcheck-disable-next-line$/, #JS, Java, C, ...
19
+ /# goodcheck-disable-next-line$/, # Ruby, Python, PHP, ...
20
+ /-- goodcheck-disable-next-line$/, # Haskel, SQL, ...
21
+ /<!-- goodcheck-disable-next-line -->$/, # HTML, Markdown, ...
22
+ /\/\* goodcheck-disable-next-line \*\/$/, # CSS, SCSS,
23
+ /\{\s*\/\* goodcheck-disable-next-line \*\/\s*\}$/, # JSX, ...
24
+ /<%# goodcheck-disable-next-line %>$/, # ERB, ...
25
+ /' goodcheck-disable-next-line$/, # VB
26
+ ].freeze
27
+
28
+ class << self
29
+ attr_accessor :DISABLE_LINE_PATTERNS
30
+ attr_accessor :DISABLE_NEXT_LINE_PATTERNS
31
+ end
32
+
6
33
  def initialize(path:, content:)
7
34
  @path = path
8
35
  @content = content
36
+ @line_ranges = nil
9
37
  end
10
38
 
11
39
  def line_ranges
@@ -23,6 +51,18 @@ module Goodcheck
23
51
 
24
52
  @line_ranges
25
53
  end
54
+
55
+ def line_disabled?(line_number)
56
+ if line_number > 1
57
+ return true if DISABLE_NEXT_LINE_PATTERNS.any? { |pattern| line(line_number - 1).match?(pattern) }
58
+ end
59
+
60
+ if line_number <= lines.length
61
+ return DISABLE_LINE_PATTERNS.any? { |pattern| line(line_number).match?(pattern) }
62
+ end
63
+
64
+ return false
65
+ end
26
66
 
27
67
  def location_for_position(position)
28
68
  line_index = line_ranges.bsearch_index do |range|
@@ -34,8 +74,12 @@ module Goodcheck
34
74
  end
35
75
  end
36
76
 
77
+ def lines
78
+ @lines ||= content.lines
79
+ end
80
+
37
81
  def line(line_number)
38
- content.lines[line_number-1]
82
+ lines[line_number-1]
39
83
  end
40
84
 
41
85
  def position_for_location(line, column)
@@ -18,7 +18,7 @@ module Goodcheck
18
18
  test: "Test your configuration",
19
19
  pattern: "Print regexp for rules",
20
20
  version: "Print version",
21
- help: "Show goodcheck version and quit"
21
+ help: "Show help and quit"
22
22
  }
23
23
 
24
24
 
@@ -27,8 +27,12 @@ module Goodcheck
27
27
 
28
28
  if COMMANDS.key?(command)
29
29
  __send__(command, args)
30
+ elsif command == :"--version"
31
+ version(args)
30
32
  else
33
+ stderr.puts "Invalid command: #{command}" if command
31
34
  help(args)
35
+ 1
32
36
  end
33
37
  rescue => exn
34
38
  stderr.puts exn.inspect
@@ -80,7 +84,7 @@ module Goodcheck
80
84
  if args.empty?
81
85
  targets << Pathname(".")
82
86
  else
83
- targets.push *args.map {|arg| Pathname(arg) }
87
+ args.each {|arg| targets << Pathname(arg) }
84
88
  end
85
89
 
86
90
  reporter = case format
@@ -1,6 +1,8 @@
1
1
  module Goodcheck
2
2
  module Commands
3
3
  class Check
4
+ DEFAULT_EXCLUSIONS = [".git", ".svn", ".hg"].freeze
5
+
4
6
  attr_reader :config_path
5
7
  attr_reader :rules
6
8
  attr_reader :targets
@@ -34,6 +36,7 @@ module Goodcheck
34
36
  reporter.rule(rule) do
35
37
  analyzer = Analyzer.new(rule: rule, buffer: buffer, trigger: trigger)
36
38
  analyzer.scan do |issue|
39
+ next if issue.location && buffer.line_disabled?(issue.location.start_line)
37
40
  if reported_issues.add?(issue)
38
41
  issue_reported = true
39
42
  reporter.issue(issue)
@@ -82,24 +85,23 @@ module Goodcheck
82
85
  end
83
86
  end
84
87
 
85
- def is_dotfile?(path)
86
- /\A\.[^.]+/.match?(path.basename.to_s)
87
- end
88
-
89
88
  def each_file(path, immediate: false, &block)
90
89
  case
91
90
  when path.symlink?
92
91
  # noop
93
92
  when path.directory?
94
- if immediate || (!is_dotfile?(path) && !excluded?(path))
93
+ case
94
+ when DEFAULT_EXCLUSIONS.include?(path.basename.to_s)
95
+ # noop
96
+ when immediate || !excluded?(path)
95
97
  path.children.each do |child|
96
98
  each_file(child, &block)
97
99
  end
98
100
  end
99
101
  when path.file?
100
102
  case
101
- when path == config_path || is_dotfile?(path)
102
- # Skip dotfiles/config file unless explicitly given by command line
103
+ when path == config_path
104
+ # Skip the config file unless explicitly given by command line
103
105
  yield path if immediate
104
106
  when excluded?(path)
105
107
  # Skip excluded files unless explicitly given by command line
@@ -5,7 +5,7 @@ module Goodcheck
5
5
 
6
6
  def load_config!(force_download:, cache_path:)
7
7
  import_loader = ImportLoader.new(cache_path: cache_path, force_download: force_download, config_path: config_path)
8
- content = JSON.parse(JSON.dump(YAML.load(config_path.read, config_path.to_s)), symbolize_names: true)
8
+ content = JSON.parse(JSON.dump(YAML.load(config_path.read, filename: config_path.to_s)), symbolize_names: true)
9
9
  loader = ConfigLoader.new(path: config_path, content: content, stderr: stderr, import_loader: import_loader)
10
10
  @config = loader.load
11
11
  end
@@ -22,6 +22,11 @@ module Goodcheck
22
22
  handle_config_errors stderr do
23
23
  load_config!(cache_path: cache_dir_path, force_download: force_download)
24
24
 
25
+ if config.rules.empty?
26
+ stdout.puts "No rules."
27
+ return 0
28
+ end
29
+
25
30
  validate_rule_uniqueness or return 1
26
31
  validate_rules or return 1
27
32
 
@@ -44,7 +49,8 @@ module Goodcheck
44
49
  stdout.puts " OK!👍"
45
50
  true
46
51
  else
47
- stdout.puts(Rainbow(" Found #{duplicated_ids.size} duplications.😞").red)
52
+ count = duplicated_ids.size
53
+ stdout.puts(Rainbow(" Found #{count} #{'duplication'.pluralize(count)}.😞").red)
48
54
  duplicated_ids.each do |id|
49
55
  stdout.puts " #{id}"
50
56
  end
@@ -54,10 +60,13 @@ module Goodcheck
54
60
 
55
61
  def validate_rules
56
62
  test_pass = true
63
+ success_count = 0
64
+ failure_count = 0
65
+ failed_rule_ids = Set[]
57
66
 
58
67
  config.rules.each do |rule|
59
68
  if rule.triggers.any? {|trigger| !trigger.passes.empty? || !trigger.fails.empty?}
60
- stdout.puts "Testing rule #{rule.id}..."
69
+ stdout.puts "Testing rule #{Rainbow(rule.id).cyan}..."
61
70
 
62
71
  rule_ok = true
63
72
 
@@ -82,7 +91,8 @@ module Goodcheck
82
91
  rule_ok = false
83
92
 
84
93
  pass_errors.each do |_, index|
85
- stdout.puts " #{(index+1).ordinalize} pass example matched.😱"
94
+ stdout.puts " #{(index+1).ordinalize} #{Rainbow('pass').green} example matched.😱"
95
+ failed_rule_ids << rule.id
86
96
  end
87
97
  end
88
98
 
@@ -91,7 +101,8 @@ module Goodcheck
91
101
  rule_ok = false
92
102
 
93
103
  fail_errors.each do |_, index|
94
- stdout.puts " #{(index+1).ordinalize} fail example didn't match.😱"
104
+ stdout.puts " #{(index+1).ordinalize} #{Rainbow('fail').red} example didn't match.😱"
105
+ failed_rule_ids << rule.id
95
106
  end
96
107
  end
97
108
  end
@@ -104,10 +115,27 @@ module Goodcheck
104
115
 
105
116
  if rule_ok
106
117
  stdout.puts " OK!🎉"
118
+ success_count += 1
119
+ else
120
+ failure_count += 1
107
121
  end
108
122
  end
109
123
  end
110
124
 
125
+ unless failed_rule_ids.empty?
126
+ stdout.puts ""
127
+ stdout.puts "Failed rules:"
128
+ failed_rule_ids.each do |rule_id|
129
+ stdout.puts " - #{Rainbow(rule_id).background(:red)}"
130
+ end
131
+ end
132
+
133
+ rule_count = success_count + failure_count
134
+ stdout.puts ""
135
+ stdout.puts ["Tested #{rule_count} #{'rule'.pluralize(rule_count)}",
136
+ Rainbow("#{success_count} #{'success'.pluralize(success_count)}").green,
137
+ Rainbow("#{failure_count} #{'failure'.pluralize(failure_count)}").red].join(", ")
138
+
111
139
  test_pass
112
140
  end
113
141
 
@@ -241,7 +241,7 @@ module Goodcheck
241
241
 
242
242
  Goodcheck.logger.tagged import do
243
243
  import_loader.load(import) do |content|
244
- json = JSON.parse(JSON.dump(YAML.load(content, import)), symbolize_names: true)
244
+ json = JSON.parse(JSON.dump(YAML.load(content, filename: import)), symbolize_names: true)
245
245
 
246
246
  Schema.rules.coerce json
247
247
  load_rules(rules, json)
@@ -360,7 +360,7 @@ module Goodcheck
360
360
  when ::Regexp
361
361
  Pattern::Regexp.new(source: pattern,
362
362
  regexp: pat,
363
- multiline: pat.multiline?,
363
+ multiline: pat.options & ::Regexp::MULTILINE == ::Regexp::MULTILINE,
364
364
  case_sensitive: !pat.casefold?)
365
365
  end
366
366
  when Hash
@@ -9,7 +9,7 @@ module Goodcheck
9
9
  end
10
10
 
11
11
  def test(path)
12
- path.fnmatch?(pattern, File::FNM_PATHNAME | File::FNM_EXTGLOB)
12
+ path.fnmatch?(pattern, File::FNM_PATHNAME | File::FNM_EXTGLOB | File::FNM_DOTMATCH)
13
13
  end
14
14
 
15
15
  def ==(other)
@@ -71,7 +71,7 @@ module Goodcheck
71
71
  if download
72
72
  path.rmtree if path.exist?
73
73
  Goodcheck.logger.info "Downloading content..."
74
- content = HTTPClient.new.get_content(uri)
74
+ content = http_get uri
75
75
  Goodcheck.logger.debug "Downloaded content: #{content[0, 1024].inspect}#{content.size > 1024 ? "..." : ""}"
76
76
  yield content
77
77
  write_cache uri, content
@@ -85,5 +85,21 @@ module Goodcheck
85
85
  path = cache_path + cache_name(uri)
86
86
  path.write(content)
87
87
  end
88
+
89
+ # @see https://ruby-doc.org/stdlib-2.7.0/libdoc/net/http/rdoc/Net/HTTP.html#class-Net::HTTP-label-Following+Redirection
90
+ def http_get(uri, limit = 10)
91
+ raise ArgumentError, "Too many HTTP redirects" if limit == 0
92
+
93
+ res = Net::HTTP.get_response URI(uri)
94
+ case res
95
+ when Net::HTTPSuccess
96
+ res.body
97
+ when Net::HTTPRedirection
98
+ location = res['Location']
99
+ http_get location, limit - 1
100
+ else
101
+ raise "Error: HTTP GET #{uri.inspect} #{res.inspect}"
102
+ end
103
+ end
88
104
  end
89
105
  end
@@ -10,6 +10,7 @@ module Goodcheck
10
10
  @range = range
11
11
  @rule = rule
12
12
  @text = text
13
+ @location = nil
13
14
  end
14
15
 
15
16
  def path
@@ -12,6 +12,8 @@ module Goodcheck
12
12
  @passes = passes
13
13
  @fails = fails
14
14
  @negated = negated
15
+ @by_pattern = false
16
+ @skips_fail_examples = false
15
17
  end
16
18
 
17
19
  def by_pattern!
@@ -1,3 +1,3 @@
1
1
  module Goodcheck
2
- VERSION = "2.4.3"
2
+ VERSION = "2.5.2"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goodcheck
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.3
4
+ version: 2.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Soutaro Matsumoto
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-07 00:00:00.000000000 Z
11
+ date: 2020-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 1.3.6
61
+ version: 1.4.2
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 1.3.6
68
+ version: 1.4.2
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: activesupport
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -90,16 +90,22 @@ dependencies:
90
90
  name: strong_json
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - "~>"
93
+ - - ">="
94
94
  - !ruby/object:Gem::Version
95
- version: 1.1.0
95
+ version: '1.1'
96
+ - - "<"
97
+ - !ruby/object:Gem::Version
98
+ version: '2.2'
96
99
  type: :runtime
97
100
  prerelease: false
98
101
  version_requirements: !ruby/object:Gem::Requirement
99
102
  requirements:
100
- - - "~>"
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '1.1'
106
+ - - "<"
101
107
  - !ruby/object:Gem::Version
102
- version: 1.1.0
108
+ version: '2.2'
103
109
  - !ruby/object:Gem::Dependency
104
110
  name: rainbow
105
111
  requirement: !ruby/object:Gem::Requirement
@@ -115,19 +121,25 @@ dependencies:
115
121
  - !ruby/object:Gem::Version
116
122
  version: 3.0.0
117
123
  - !ruby/object:Gem::Dependency
118
- name: httpclient
124
+ name: psych
119
125
  requirement: !ruby/object:Gem::Requirement
120
126
  requirements:
121
- - - "~>"
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '3.1'
130
+ - - "<"
122
131
  - !ruby/object:Gem::Version
123
- version: 2.8.3
132
+ version: '4.0'
124
133
  type: :runtime
125
134
  prerelease: false
126
135
  version_requirements: !ruby/object:Gem::Requirement
127
136
  requirements:
128
- - - "~>"
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '3.1'
140
+ - - "<"
129
141
  - !ruby/object:Gem::Version
130
- version: 2.8.3
142
+ version: '4.0'
131
143
  description: Regexp based customizable linter
132
144
  email:
133
145
  - matsumoto@soutaro.com
@@ -136,9 +148,11 @@ executables:
136
148
  extensions: []
137
149
  extra_rdoc_files: []
138
150
  files:
151
+ - ".github/dependabot.yml"
152
+ - ".github/workflows/release.yml"
153
+ - ".github/workflows/test.yml"
139
154
  - ".gitignore"
140
155
  - ".rubocop.yml"
141
- - ".travis.yml"
142
156
  - CHANGELOG.md
143
157
  - Dockerfile
144
158
  - Gemfile
@@ -175,6 +189,7 @@ files:
175
189
  - docusaurus/website/versioned_docs/version-1.0.0/rules.md
176
190
  - docusaurus/website/versioned_docs/version-1.0.2/rules.md
177
191
  - docusaurus/website/versioned_docs/version-2.4.0/configuration.md
192
+ - docusaurus/website/versioned_docs/version-2.4.3/rules.md
178
193
  - docusaurus/website/versioned_sidebars/version-1.0.0-sidebars.json
179
194
  - docusaurus/website/versioned_sidebars/version-1.0.2-sidebars.json
180
195
  - docusaurus/website/versioned_sidebars/version-2.4.0-sidebars.json
@@ -182,6 +197,7 @@ files:
182
197
  - docusaurus/website/yarn.lock
183
198
  - exe/goodcheck
184
199
  - goodcheck.gemspec
200
+ - goodcheck.yml
185
201
  - lib/goodcheck.rb
186
202
  - lib/goodcheck/analyzer.rb
187
203
  - lib/goodcheck/array_helper.rb
@@ -216,7 +232,7 @@ homepage: https://github.com/sider/goodcheck
216
232
  licenses:
217
233
  - MIT
218
234
  metadata: {}
219
- post_install_message:
235
+ post_install_message:
220
236
  rdoc_options: []
221
237
  require_paths:
222
238
  - lib
@@ -231,8 +247,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
247
  - !ruby/object:Gem::Version
232
248
  version: '0'
233
249
  requirements: []
234
- rubygems_version: 3.0.6
235
- signing_key:
250
+ rubygems_version: 3.1.2
251
+ signing_key:
236
252
  specification_version: 4
237
253
  summary: Regexp based customizable linter
238
254
  test_files: []