goodcheck 2.5.2 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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