goodcheck 2.5.2 → 2.6.0

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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -3
  3. data/lib/goodcheck.rb +3 -1
  4. data/lib/goodcheck/cli.rb +78 -54
  5. data/lib/goodcheck/commands/check.rb +19 -1
  6. data/lib/goodcheck/commands/config_loading.rb +19 -2
  7. data/lib/goodcheck/commands/init.rb +4 -2
  8. data/lib/goodcheck/commands/pattern.rb +2 -1
  9. data/lib/goodcheck/commands/test.rb +5 -4
  10. data/lib/goodcheck/config_loader.rb +5 -4
  11. data/lib/goodcheck/error.rb +3 -0
  12. data/lib/goodcheck/exit_status.rb +6 -0
  13. data/lib/goodcheck/glob.rb +14 -3
  14. data/lib/goodcheck/import_loader.rb +25 -9
  15. data/lib/goodcheck/version.rb +1 -1
  16. metadata +5 -55
  17. data/.github/dependabot.yml +0 -18
  18. data/.github/workflows/release.yml +0 -16
  19. data/.github/workflows/test.yml +0 -46
  20. data/.gitignore +0 -13
  21. data/.rubocop.yml +0 -5
  22. data/Dockerfile +0 -13
  23. data/Gemfile +0 -6
  24. data/Rakefile +0 -75
  25. data/bin/console +0 -14
  26. data/bin/setup +0 -8
  27. data/cheatsheet.pdf +0 -0
  28. data/docusaurus/.dockerignore +0 -2
  29. data/docusaurus/.gitignore +0 -12
  30. data/docusaurus/Dockerfile +0 -10
  31. data/docusaurus/docker-compose.yml +0 -18
  32. data/docusaurus/docs/commands.md +0 -69
  33. data/docusaurus/docs/configuration.md +0 -300
  34. data/docusaurus/docs/development.md +0 -15
  35. data/docusaurus/docs/getstarted.md +0 -46
  36. data/docusaurus/docs/rules.md +0 -79
  37. data/docusaurus/website/README.md +0 -193
  38. data/docusaurus/website/core/Footer.js +0 -100
  39. data/docusaurus/website/package.json +0 -14
  40. data/docusaurus/website/pages/en/index.js +0 -207
  41. data/docusaurus/website/pages/en/versions.js +0 -118
  42. data/docusaurus/website/sidebars.json +0 -11
  43. data/docusaurus/website/siteConfig.js +0 -171
  44. data/docusaurus/website/static/css/code-block-buttons.css +0 -39
  45. data/docusaurus/website/static/css/custom.css +0 -245
  46. data/docusaurus/website/static/img/favicon.ico +0 -0
  47. data/docusaurus/website/static/js/code-block-buttons.js +0 -47
  48. data/docusaurus/website/versioned_docs/version-1.0.0/commands.md +0 -70
  49. data/docusaurus/website/versioned_docs/version-1.0.0/configuration.md +0 -296
  50. data/docusaurus/website/versioned_docs/version-1.0.0/development.md +0 -16
  51. data/docusaurus/website/versioned_docs/version-1.0.0/getstarted.md +0 -47
  52. data/docusaurus/website/versioned_docs/version-1.0.0/rules.md +0 -81
  53. data/docusaurus/website/versioned_docs/version-1.0.2/rules.md +0 -79
  54. data/docusaurus/website/versioned_docs/version-2.4.0/configuration.md +0 -301
  55. data/docusaurus/website/versioned_docs/version-2.4.3/rules.md +0 -80
  56. data/docusaurus/website/versioned_sidebars/version-1.0.0-sidebars.json +0 -11
  57. data/docusaurus/website/versioned_sidebars/version-1.0.2-sidebars.json +0 -11
  58. data/docusaurus/website/versioned_sidebars/version-2.4.0-sidebars.json +0 -11
  59. data/docusaurus/website/versions.json +0 -12
  60. data/docusaurus/website/yarn.lock +0 -6604
  61. data/goodcheck.gemspec +0 -35
  62. data/goodcheck.yml +0 -10
  63. data/logo/GoodCheck Horizontal.pdf +0 -899
  64. data/logo/GoodCheck Horizontal.png +0 -0
  65. data/logo/GoodCheck Horizontal.svg +0 -55
  66. data/logo/GoodCheck logo.png +0 -0
  67. data/logo/GoodCheck vertical.png +0 -0
  68. data/sample.yml +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a8fa2f7ee1e8534b3495e3d77a0d0cfb8b49eeaefc77a6507fee9604e0b829a
4
- data.tar.gz: 5cd0ac1288b2bb90978998410ff93e234ec08bc645b2ace741f339e0e0b811b2
3
+ metadata.gz: de4b1a0cef4a741eeb0307e0df5be2dcf68ad43ed59e5a9b5bf1d16e991b4c5e
4
+ data.tar.gz: a9a980614761ccc2bed278df1c51400878330e3ba92d5999a0133502eb8fa47c
5
5
  SHA512:
6
- metadata.gz: dbadbb4097eb8ba35fff5845ade562e47830c197297176118f5144ad984132331f890ef9f7b1e30f14e66ae9d43df64819fb7794dd3059f22fe46e75fcd76a6a
7
- data.tar.gz: 3728f7b3037174382675361fa05be02e0f1bf1ede5cb6aadacef2098c062568a95e560a10eed72bffd12baac171b636279738ecf3cccd78be11526922bba50bb
6
+ metadata.gz: 2978efccddd1d7132703a1b993aa25d9e3f588a33ed07cadce73aa514d252bdf963b537314d9d20ea509b437a88ce018ea7d7f38b7cb165572c6e8b8cef07880
7
+ data.tar.gz: 980698f9a9e94346cc2d727a6c8b3709281747e698e9424f95f00a5c473c75ea16de0026f879f4fde91f3a935004234c712e81913ba0ee5b092b04bef369a58f
@@ -1,10 +1,19 @@
1
- # CHANGELOG
1
+ # Changelog
2
2
 
3
- ## master
3
+ ## HEAD
4
+
5
+ ## 2.6.0 (2020-11-17)
6
+
7
+ * Improve CLI help and error messages [#141](https://github.com/sider/goodcheck/pull/141)
8
+ * Fail if missing rules on `goodcheck check` command [#142](https://github.com/sider/goodcheck/pull/142)
9
+ * Reduce needless files in this gem [#143](https://github.com/sider/goodcheck/pull/143)
10
+ * Add `Goodcheck::Error` as a base error class [#144](https://github.com/sider/goodcheck/pull/144)
11
+ * Improve error message when config file is not found [#145](https://github.com/sider/goodcheck/pull/145)
12
+ * Add `rules[].glob.exclude` option to `goodcheck.yml` [#146](https://github.com/sider/goodcheck/pull/146)
4
13
 
5
14
  ## 2.5.2 (2020-08-31)
6
15
 
7
- * Fix the pattern of disable lines for Slash-asterisk and add support for JSX [#131](https: //github.com/sider/goodcheck/pull/131)
16
+ * Fix the pattern of disable lines for Slash-asterisk and add support for JSX [#131](https://github.com/sider/goodcheck/pull/131)
8
17
 
9
18
  ## 2.5.1 (2020-03-09)
10
19
 
@@ -1,5 +1,6 @@
1
1
  require "strscan"
2
2
  require "pathname"
3
+ require "set"
3
4
  require "strong_json"
4
5
  require "yaml"
5
6
  require "json"
@@ -11,9 +12,10 @@ require "digest/sha2"
11
12
  require "net/http"
12
13
 
13
14
  require "goodcheck/version"
15
+ require "goodcheck/error"
14
16
  require "goodcheck/logger"
15
17
  require "goodcheck/home_path"
16
-
18
+ require "goodcheck/exit_status"
17
19
  require "goodcheck/glob"
18
20
  require "goodcheck/buffer"
19
21
  require "goodcheck/location"
@@ -1,9 +1,9 @@
1
1
  require "optparse"
2
2
 
3
- Version = Goodcheck::VERSION
4
-
5
3
  module Goodcheck
6
4
  class CLI
5
+ include ExitStatus
6
+
7
7
  attr_reader :stdout
8
8
  attr_reader :stderr
9
9
 
@@ -19,8 +19,9 @@ module Goodcheck
19
19
  pattern: "Print regexp for rules",
20
20
  version: "Print version",
21
21
  help: "Show help and quit"
22
- }
22
+ }.freeze
23
23
 
24
+ DEFAULT_CONFIG_FILE = Pathname("goodcheck.yml").freeze
24
25
 
25
26
  def run(args)
26
27
  command = args.shift&.to_sym
@@ -30,16 +31,22 @@ module Goodcheck
30
31
  elsif command == :"--version"
31
32
  version(args)
32
33
  else
33
- stderr.puts "Invalid command: #{command}" if command
34
+ if command
35
+ stderr.puts "invalid command: #{command}"
36
+ stderr.puts ""
37
+ end
34
38
  help(args)
35
- 1
39
+ EXIT_ERROR
36
40
  end
41
+ rescue OptionParser::ParseError => exn
42
+ stderr.puts exn
43
+ EXIT_ERROR
37
44
  rescue => exn
38
45
  stderr.puts exn.inspect
39
46
  exn.backtrace.each do |bt|
40
47
  stderr.puts " #{bt}"
41
48
  end
42
- 1
49
+ EXIT_ERROR
43
50
  end
44
51
 
45
52
  def home_path
@@ -51,32 +58,28 @@ module Goodcheck
51
58
  end
52
59
 
53
60
  def check(args)
54
- config_path = Pathname("goodcheck.yml")
61
+ config_path = DEFAULT_CONFIG_FILE
55
62
  targets = []
56
63
  rules = []
57
- format = nil
64
+ formats = [:text, :json]
65
+ format = :text
58
66
  loglevel = Logger::ERROR
59
67
  force_download = false
60
68
 
61
- OptionParser.new("Usage: goodcheck check [options] dirs...") do |opts|
62
- opts.on("-c CONFIG", "--config=CONFIG") do |config|
63
- config_path = Pathname(config)
64
- end
65
- opts.on("-R RULE", "--rule=RULE") do |rule|
69
+ OptionParser.new("Usage: goodcheck check [options] paths...") do |opts|
70
+ config_option(opts) { |config| config_path = config }
71
+ verbose_option(opts) { |level| loglevel = level }
72
+ debug_option(opts) { |level| loglevel = level }
73
+ force_download_option(opts) { force_download = true }
74
+ common_options(opts)
75
+
76
+ opts.on("-R RULE", "--rule=RULE", "Only rule(s) to check") do |rule|
66
77
  rules << rule
67
78
  end
68
- opts.on("--format=<text|json> [default: 'text']") do |f|
79
+
80
+ opts.on("--format=<#{formats.join('|')}>", formats, "Output format [default: '#{format}']") do |f|
69
81
  format = f
70
82
  end
71
- opts.on("-v", "--verbose") do
72
- loglevel = Logger::INFO
73
- end
74
- opts.on("-d", "--debug") do
75
- loglevel = Logger::DEBUG
76
- end
77
- opts.on("--force") do
78
- force_download = true
79
- end
80
83
  end.parse!(args)
81
84
 
82
85
  Goodcheck.logger.level = loglevel
@@ -88,13 +91,12 @@ module Goodcheck
88
91
  end
89
92
 
90
93
  reporter = case format
91
- when "text", nil
94
+ when :text
92
95
  Reporters::Text.new(stdout: stdout)
93
- when "json"
96
+ when :json
94
97
  Reporters::JSON.new(stdout: stdout, stderr: stderr)
95
98
  else
96
- stderr.puts "Unknown format: #{format}"
97
- return 1
99
+ raise ArgumentError, format.inspect
98
100
  end
99
101
 
100
102
  Goodcheck.logger.info "Configuration = #{config_path}"
@@ -108,23 +110,16 @@ module Goodcheck
108
110
  end
109
111
 
110
112
  def test(args)
111
- config_path = Pathname("goodcheck.yml")
112
- loglevel = Logger::ERROR
113
+ config_path = DEFAULT_CONFIG_FILE
114
+ loglevel = ::Logger::ERROR
113
115
  force_download = false
114
116
 
115
117
  OptionParser.new("Usage: goodcheck test [options]") do |opts|
116
- opts.on("-c CONFIG", "--config=CONFIG") do |config|
117
- config_path = Pathname(config)
118
- end
119
- opts.on("-v", "--verbose") do
120
- loglevel = Logger::INFO
121
- end
122
- opts.on("-d", "--debug") do
123
- loglevel = Logger::DEBUG
124
- end
125
- opts.on("--force") do
126
- force_download = true
127
- end
118
+ config_option(opts) { |config| config_path = config }
119
+ verbose_option(opts) { |level| loglevel = level }
120
+ debug_option(opts) { |level| loglevel = level }
121
+ force_download_option(opts) { force_download = true }
122
+ common_options(opts)
128
123
  end.parse!(args)
129
124
 
130
125
  Goodcheck.logger.level = loglevel
@@ -137,14 +132,14 @@ module Goodcheck
137
132
  end
138
133
 
139
134
  def init(args)
140
- config_path = Pathname("goodcheck.yml")
135
+ config_path = DEFAULT_CONFIG_FILE
141
136
  force = false
142
137
 
143
138
  OptionParser.new("Usage: goodcheck init [options]") do |opts|
144
- opts.on("-c CONFIG", "--config=CONFIG") do |config|
145
- config_path = Pathname(config)
146
- end
147
- opts.on("--force") do
139
+ config_option(opts) { |config| config_path = config }
140
+ common_options(opts)
141
+
142
+ opts.on("--force", "Overwrite an existing file") do
148
143
  force = true
149
144
  end
150
145
  end.parse!(args)
@@ -152,9 +147,9 @@ module Goodcheck
152
147
  Commands::Init.new(stdout: stdout, stderr: stderr, path: config_path, force: force).run
153
148
  end
154
149
 
155
- def version(args)
150
+ def version(_args = nil)
156
151
  stdout.puts "goodcheck #{VERSION}"
157
- 0
152
+ EXIT_SUCCESS
158
153
  end
159
154
 
160
155
  def help(args)
@@ -164,19 +159,48 @@ module Goodcheck
164
159
  COMMANDS.each do |c, msg|
165
160
  stdout.puts " goodcheck #{c}\t#{msg}"
166
161
  end
167
- 0
162
+ EXIT_SUCCESS
168
163
  end
169
164
 
170
165
  def pattern(args)
171
- config_path = Pathname("goodcheck.yml")
166
+ config_path = DEFAULT_CONFIG_FILE
172
167
 
173
- OptionParser.new("Usage: goodcheck pattern [options] ids...") do |opts|
174
- opts.on("-c CONFIG", "--config=CONFIG") do |config|
175
- config_path = Pathname(config)
176
- end
168
+ OptionParser.new do |opts|
169
+ opts.banner = "Usage: goodcheck pattern [options] ids..."
170
+ config_option(opts) { |config| config_path = config }
171
+ common_options(opts)
177
172
  end.parse!(args)
178
173
 
179
174
  Commands::Pattern.new(stdout: stdout, stderr: stderr, path: config_path, ids: Set.new(args), home_path: home_path).run
180
175
  end
176
+
177
+ def config_option(opts)
178
+ opts.on("-c CONFIG", "--config=CONFIG", "Configuration file path [default: '#{DEFAULT_CONFIG_FILE}']") do |config|
179
+ yield Pathname(config)
180
+ end
181
+ end
182
+
183
+ def verbose_option(opts)
184
+ opts.on("-v", "--verbose", "Set log level to verbose") { yield ::Logger::INFO }
185
+ end
186
+
187
+ def debug_option(opts)
188
+ opts.on("-d", "--debug", "Set log level to debug") { yield ::Logger::DEBUG }
189
+ end
190
+
191
+ def force_download_option(opts, &block)
192
+ opts.on("--force", "Download importing files always", &block)
193
+ end
194
+
195
+ def common_options(opts)
196
+ opts.on_tail("--version", COMMANDS.fetch(:version)) do
197
+ version
198
+ exit EXIT_SUCCESS
199
+ end
200
+ opts.on_tail("-h", "--help", COMMANDS.fetch(:help)) do
201
+ stdout.puts opts.help
202
+ exit EXIT_SUCCESS
203
+ end
204
+ end
181
205
  end
182
206
  end
@@ -13,6 +13,9 @@ module Goodcheck
13
13
 
14
14
  include ConfigLoading
15
15
  include HomePath
16
+ include ExitStatus
17
+
18
+ EXIT_MATCH = 2
16
19
 
17
20
  def initialize(config_path:, rules:, targets:, reporter:, stderr:, home_path:, force_download:)
18
21
  @config_path = config_path
@@ -30,6 +33,14 @@ module Goodcheck
30
33
 
31
34
  reporter.analysis do
32
35
  load_config!(force_download: force_download, cache_path: cache_dir_path)
36
+
37
+ unless missing_rules.empty?
38
+ missing_rules.each do |rule|
39
+ stderr.puts "missing rule: #{rule}"
40
+ end
41
+ return EXIT_ERROR
42
+ end
43
+
33
44
  each_check do |buffer, rule, trigger|
34
45
  reported_issues = Set[]
35
46
 
@@ -46,7 +57,14 @@ module Goodcheck
46
57
  end
47
58
  end
48
59
 
49
- issue_reported ? 2 : 0
60
+ issue_reported ? EXIT_MATCH : EXIT_SUCCESS
61
+ end
62
+ end
63
+
64
+ def missing_rules
65
+ @missing_rules ||= begin
66
+ config_rule_ids = config.rules.map(&:id)
67
+ rules.reject { |rule| config_rule_ids.include?(rule) }
50
68
  end
51
69
  end
52
70
 
@@ -1,11 +1,26 @@
1
1
  module Goodcheck
2
2
  module Commands
3
3
  module ConfigLoading
4
+ class ConfigFileNotFound < Error
5
+ attr_reader :path
6
+
7
+ def initialize(path:)
8
+ @path = path
9
+ end
10
+ end
11
+
4
12
  attr_reader :config
5
13
 
6
14
  def load_config!(force_download:, cache_path:)
15
+ config_content =
16
+ begin
17
+ config_path.read
18
+ rescue Errno::ENOENT
19
+ raise ConfigFileNotFound.new(path: config_path)
20
+ end
21
+
7
22
  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, filename: config_path.to_s)), symbolize_names: true)
23
+ content = JSON.parse(JSON.dump(YAML.load(config_content, filename: config_path.to_s)), symbolize_names: true)
9
24
  loader = ConfigLoader.new(path: config_path, content: content, stderr: stderr, import_loader: import_loader)
10
25
  @config = loader.load
11
26
  end
@@ -13,7 +28,9 @@ module Goodcheck
13
28
  def handle_config_errors(stderr)
14
29
  begin
15
30
  yield
16
-
31
+ rescue ConfigFileNotFound => exn
32
+ stderr.puts "Configuration file not found: #{exn.path}"
33
+ 1
17
34
  rescue Psych::Exception => exn
18
35
  stderr.puts "Unexpected error happens while loading YAML file: #{exn.inspect}"
19
36
  exn.backtrace.each do |trace_loc|
@@ -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 1
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
- 0
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
- 0
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,13 +25,13 @@ module Goodcheck
24
25
 
25
26
  if config.rules.empty?
26
27
  stdout.puts "No rules."
27
- return 0
28
+ return EXIT_SUCCESS
28
29
  end
29
30
 
30
- validate_rule_uniqueness or return 1
31
- validate_rules or return 1
31
+ validate_rule_uniqueness or return EXIT_ERROR
32
+ validate_rules or return EXIT_ERROR
32
33
 
33
- 0
34
+ EXIT_SUCCESS
34
35
  end
35
36
  end
36
37
 
@@ -2,7 +2,7 @@ module Goodcheck
2
2
  class ConfigLoader
3
3
  include ArrayHelper
4
4
 
5
- class InvalidPattern < StandardError; end
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) {
@@ -344,9 +345,9 @@ module Goodcheck
344
345
  globs.map do |glob|
345
346
  case glob
346
347
  when String
347
- Glob.new(pattern: glob, encoding: nil)
348
+ Glob.new(pattern: glob, encoding: nil, exclude: nil)
348
349
  when Hash
349
- Glob.new(pattern: glob[:pattern], encoding: glob[:encoding])
350
+ Glob.new(pattern: glob[:pattern], encoding: glob[:encoding], exclude: glob[:exclude])
350
351
  end
351
352
  end
352
353
  end