inspecstyle 0.1.0 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/Gemfile +1 -0
  4. data/Gemfile.lock +12 -7
  5. data/README.md +56 -5
  6. data/Rakefile +3 -0
  7. data/config/default.yml +18 -0
  8. data/doc/RuboCop.html +128 -0
  9. data/doc/RuboCop/Cop.html +117 -0
  10. data/doc/RuboCop/Cop/InSpecStyle.html +117 -0
  11. data/doc/RuboCop/Cop/InSpecStyle/AzureGenericResource.html +249 -0
  12. data/doc/RuboCop/Cop/InSpecStyle/DeprecatedAttributes.html +310 -0
  13. data/doc/RuboCop/Cop/InSpecStyle/FirstCop.html +345 -0
  14. data/doc/RuboCop/InSpecStyle.html +140 -0
  15. data/doc/RuboCop/InSpecStyle/Error.html +124 -0
  16. data/doc/RuboCop/InSpecStyle/Inject.html +195 -0
  17. data/doc/_index.html +211 -0
  18. data/doc/class_list.html +51 -0
  19. data/doc/css/common.css +1 -0
  20. data/doc/css/full_list.css +58 -0
  21. data/doc/css/style.css +496 -0
  22. data/doc/file.README.html +131 -0
  23. data/doc/file_list.html +56 -0
  24. data/doc/frames.html +17 -0
  25. data/doc/index.html +131 -0
  26. data/doc/js/app.js +314 -0
  27. data/doc/js/full_list.js +216 -0
  28. data/doc/js/jquery.js +4 -0
  29. data/doc/method_list.html +99 -0
  30. data/doc/top-level-namespace.html +110 -0
  31. data/lib/rubocop/cop/inspecstyle/azure_generic_resource.rb +34 -0
  32. data/lib/rubocop/cop/inspecstyle/deprecated_attributes.rb +15 -14
  33. data/lib/rubocop/cop/inspecstyle/first_cop.rb +0 -1
  34. data/lib/rubocop/cop/inspecstyle/oracle_db_session_pass.rb +37 -0
  35. data/lib/rubocop/cop/inspecstyle/shadow_properties.rb +59 -0
  36. data/lib/rubocop/cop/inspecstyle_cops.rb +3 -0
  37. data/lib/rubocop/inspecstyle/version.rb +1 -1
  38. data/notes-for-development.md +3 -0
  39. data/tasks/cops_documentation.rake +300 -0
  40. metadata +29 -2
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: when finished, run `rake generate_cops_documentation` to update the docs
4
3
  module RuboCop
5
4
  module Cop
6
5
  module InSpecStyle
6
+ # Checks if deprecated method attribute is used.
7
7
  #
8
- # @example DeprecatedAttributes: Do not use attributes
8
+ # @example EnforcedStyle: InSpecStyle (default)
9
9
  # # Attributes have been deprecated for inputs
10
10
  # # https://github.com/inspec/inspec/issues/3802
11
11
  #
@@ -26,24 +26,25 @@ module RuboCop
26
26
 
27
27
  def on_send(node)
28
28
  return unless attribute?(node)
29
- add_offense(node, location: range(node))
29
+
30
+ add_offense(node, location: node.loc.selector)
31
+ end
32
+
33
+ def autocorrect(node)
34
+ lambda do |corrector|
35
+ corrector.replace(offense_range(node), preferred_replacement)
36
+ end
30
37
  end
31
38
 
32
39
  private
33
40
 
34
- def range(node)
35
- # Only highlights the method 'attribute'
36
- range_between(node.source_range.begin_pos,
37
- node.source_range.begin_pos+9
38
- )
41
+ def offense_range(node)
42
+ node.loc.selector
39
43
  end
40
44
 
41
- # def autocorrect
42
- # ->(corrector) do
43
- # corrector.insert_before(node.source_range, 'input')
44
- # corrector.remove(node.source_range, 'attribute')
45
- # end
46
- # end
45
+ def preferred_replacement
46
+ cop_config.fetch('PreferredReplacement')
47
+ end
47
48
  end
48
49
  end
49
50
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: when finished, run `rake generate_cops_documentation` to update the docs
4
3
  module RuboCop
5
4
  module Cop
6
5
  module InSpecStyle
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InSpecStyle
6
+ #
7
+ # @example EnforcedStyle: InSpecStyle (default)
8
+ # # Description of the `bar` style.
9
+ #
10
+ # # bad
11
+ # sql = oracledb_session(user: 'my_user', pass: 'password')
12
+ #
13
+ # # good
14
+ # sql = oracledb_session(user: 'my_user', password: 'password')
15
+ class OracleDbSessionPass < Cop
16
+ include MatchRange
17
+ MSG = 'Use `:password` instead of `:pass`.'
18
+
19
+ def_node_matcher :oracledb_session_pass?, <<~PATTERN
20
+ (send _ :oracledb_session
21
+ (hash
22
+ ...
23
+ (pair
24
+ (sym $:pass)
25
+ ...)))
26
+ PATTERN
27
+
28
+ # Getting location was a bit tricky on this one, looking at docs perhaps
29
+ # convention does allow highlighting an entire line.
30
+ def on_send(node)
31
+ return unless result = oracledb_session_pass?(node)
32
+ add_offense(node, message: MSG)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ # NOTE TO SELF - this one isn't currently working even though my pattern works in Rubocop's bin/console
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module InSpecStyle
8
+ # Shadow resource property user is deprecated in favor of `users`
9
+ #
10
+ # @example EnforcedStyle: InSpecStyle (default)
11
+ # # Use users instead
12
+ #
13
+ # # bad
14
+ # describe shadow('/etc/my-custom-place/shadow') do
15
+ # its('user') { should eq 'user' }
16
+ # end
17
+ #
18
+ # # good
19
+ # describe shadow('/etc/my-custom-place/shadow') do
20
+ # its('users') { should eq 'user' }
21
+ # end
22
+ #
23
+ class ShadowProperties < Cop
24
+ # TODO: Implement the cop in here.
25
+ #
26
+ # In many cases, you can use a node matcher for matching node pattern.
27
+ # See https://github.com/rubocop-hq/rubocop-ast/blob/master/lib/rubocop/node_pattern.rb
28
+ #
29
+ # For example
30
+ MSG = 'Use `#users` instead of `#user`. This property will be removed '\
31
+ 'in InSpec 5'
32
+
33
+ def_node_matcher :shadow_resource_user_property?, <<~PATTERN
34
+ (block
35
+ (send _ :describe
36
+ (send _ :shadow ...) ...)
37
+ (args ...)
38
+ (block
39
+ (send _ :its
40
+ (str ${"user" "password" "last_change" "expiry_date" "line"} ...) ...) ...) ...)
41
+ PATTERN
42
+
43
+ def on_block(node)
44
+ return unless shadow_resource_user_property?(node) do |result|
45
+ require 'pry'
46
+ # binding.pry
47
+ add_offense(node, message: message(result))
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ def message(result)
54
+ MSG #
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  require_relative 'inspecstyle/first_cop'
3
3
  require_relative 'inspecstyle/deprecated_attributes'
4
+ require_relative 'inspecstyle/azure_generic_resource'
5
+ require_relative 'inspecstyle/shadow_properties'
6
+ require_relative 'inspecstyle/oracle_db_session_pass'
@@ -1,5 +1,5 @@
1
1
  module RuboCop
2
2
  module InSpecStyle
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.5"
4
4
  end
5
5
  end
@@ -42,4 +42,7 @@ node = source.ast
42
42
  node.type
43
43
  node.children
44
44
  node.source
45
+ NodePattern.new('(send ...)').match(node) # => true
45
46
  ```
47
+
48
+ Correction docs at rubocop's: lib/rubocop/cop/corrector.rb
@@ -0,0 +1,300 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yard'
4
+ require 'rubocop'
5
+
6
+ YARD::Rake::YardocTask.new(:yard_for_generate_documentation) do |task|
7
+ task.files = ['lib/rubocop/cop/*/*.rb']
8
+ task.options = ['--no-output']
9
+ end
10
+
11
+ desc 'Generate docs of all cops departments'
12
+ task generate_cops_documentation: :yard_for_generate_documentation do
13
+ def cops_of_department(cops, department)
14
+ cops.with_department(department).sort!
15
+ end
16
+
17
+ # rubocop:disable Metrics/AbcSize
18
+ def cops_body(config, cop, description, examples_objects, pars)
19
+ content = h2(cop.cop_name)
20
+ content << required_ruby_version(cop)
21
+ content << properties(cop.new(config))
22
+ content << "#{description}\n"
23
+ content << examples(examples_objects) if examples_objects.count.positive?
24
+ content << configurations(pars)
25
+ content << references(config, cop)
26
+ content
27
+ end
28
+ # rubocop:enable Metrics/AbcSize
29
+
30
+ def examples(examples_object)
31
+ examples_object.each_with_object(h3('Examples').dup) do |example, content|
32
+ content << "\n" unless content.end_with?("\n\n")
33
+ content << h4(example.name) unless example.name == ''
34
+ content << code_example(example)
35
+ end
36
+ end
37
+
38
+ def required_ruby_version(cop)
39
+ return '' unless cop.respond_to?(:required_minimum_ruby_version)
40
+
41
+ "NOTE: Required Ruby version: #{cop.required_minimum_ruby_version}\n\n"
42
+ end
43
+
44
+ # rubocop:disable Metrics/MethodLength
45
+ def properties(cop_instance)
46
+ header = [
47
+ 'Enabled by default', 'Safe', 'Supports autocorrection', 'VersionAdded',
48
+ 'VersionChanged'
49
+ ]
50
+ autocorrect = if cop_instance.support_autocorrect?
51
+ "Yes#{' (Unsafe)' unless cop_instance.safe_autocorrect?}"
52
+ else
53
+ 'No'
54
+ end
55
+ cop_config = cop_instance.cop_config
56
+ content = [[
57
+ cop_status(cop_config.fetch('Enabled')),
58
+ cop_config.fetch('Safe', true) ? 'Yes' : 'No',
59
+ autocorrect,
60
+ cop_config.fetch('VersionAdded', '-'),
61
+ cop_config.fetch('VersionChanged', '-')
62
+ ]]
63
+ to_table(header, content) + "\n"
64
+ end
65
+ # rubocop:enable Metrics/MethodLength
66
+
67
+ def h2(title)
68
+ content = +"\n"
69
+ content << "== #{title}\n"
70
+ content << "\n"
71
+ content
72
+ end
73
+
74
+ def h3(title)
75
+ content = +"\n"
76
+ content << "=== #{title}\n"
77
+ content << "\n"
78
+ content
79
+ end
80
+
81
+ def h4(title)
82
+ content = +"==== #{title}\n"
83
+ content << "\n"
84
+ content
85
+ end
86
+
87
+ def code_example(ruby_code)
88
+ content = +"[source,ruby]\n----\n"
89
+ content << ruby_code.text.gsub('@good', '# good')
90
+ .gsub('@bad', '# bad').strip
91
+ content << "\n----\n"
92
+ content
93
+ end
94
+
95
+ def configurations(pars)
96
+ return '' if pars.empty?
97
+
98
+ header = ['Name', 'Default value', 'Configurable values']
99
+ configs = pars
100
+ .each_key
101
+ .reject { |key| key.start_with?('Supported') }
102
+ .reject { |key| key.start_with?('AllowMultipleStyles') }
103
+ content = configs.map do |name|
104
+ configurable = configurable_values(pars, name)
105
+ default = format_table_value(pars[name])
106
+ [name, default, configurable]
107
+ end
108
+
109
+ h3('Configurable attributes') + to_table(header, content)
110
+ end
111
+
112
+ # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
113
+ def configurable_values(pars, name)
114
+ case name
115
+ when /^Enforced/
116
+ supported_style_name = RuboCop::Cop::Util.to_supported_styles(name)
117
+ format_table_value(pars[supported_style_name])
118
+ when 'IndentationWidth'
119
+ 'Integer'
120
+ when 'Database'
121
+ format_table_value(pars['SupportedDatabases'])
122
+ else
123
+ case pars[name]
124
+ when String
125
+ 'String'
126
+ when Integer
127
+ 'Integer'
128
+ when Float
129
+ 'Float'
130
+ when true, false
131
+ 'Boolean'
132
+ when Array
133
+ 'Array'
134
+ else
135
+ ''
136
+ end
137
+ end
138
+ end
139
+ # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
140
+
141
+ def to_table(header, content)
142
+ table = [
143
+ '|===',
144
+ "| #{header.join(' | ')}\n\n"
145
+ ].join("\n")
146
+ marked_contents = content.map do |plain_content|
147
+ plain_content.map { |c| "| #{c}" }.join("\n")
148
+ end
149
+ table << marked_contents.join("\n\n")
150
+ table << "\n|===\n"
151
+ end
152
+
153
+ def format_table_value(val)
154
+ value =
155
+ case val
156
+ when Array
157
+ if val.empty?
158
+ '`[]`'
159
+ else
160
+ val.map { |config| format_table_value(config) }.join(', ')
161
+ end
162
+ else
163
+ wrap_backtick(val.nil? ? '<none>' : val)
164
+ end
165
+ value.gsub("#{Dir.pwd}/", '').rstrip
166
+ end
167
+
168
+ def wrap_backtick(value)
169
+ if value.is_a?(String)
170
+ # Use `+` to prevent text like `**/*.gemspec` from being bold.
171
+ value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
172
+ else
173
+ "`#{value}`"
174
+ end
175
+ end
176
+
177
+ def references(config, cop)
178
+ cop_config = config.for_cop(cop)
179
+ urls = RuboCop::Cop::MessageAnnotator.new(
180
+ config, cop.name, cop_config, {}
181
+ ).urls
182
+ return '' if urls.empty?
183
+
184
+ content = h3('References')
185
+ content << urls.map { |url| "* #{url}" }.join("\n")
186
+ content << "\n"
187
+ content
188
+ end
189
+
190
+ def print_cops_of_department(cops, department, config)
191
+ selected_cops = cops_of_department(cops, department)
192
+ content = +"= #{department}\n"
193
+ selected_cops.each do |cop|
194
+ content << print_cop_with_doc(cop, config)
195
+ end
196
+ file_name = "#{Dir.pwd}/docs/modules/ROOT/pages/cops_#{department.downcase}.adoc"
197
+ File.open(file_name, 'w') do |file|
198
+ puts "* generated #{file_name}"
199
+ file.write(content.strip + "\n")
200
+ end
201
+ end
202
+
203
+ def print_cop_with_doc(cop, config)
204
+ t = config.for_cop(cop)
205
+ non_display_keys = %w[
206
+ Description Enabled StyleGuide Reference Safe SafeAutoCorrect VersionAdded
207
+ VersionChanged
208
+ ]
209
+ pars = t.reject { |k| non_display_keys.include? k }
210
+ description = 'No documentation'
211
+ examples_object = []
212
+ cop_code(cop) do |code_object|
213
+ description = code_object.docstring unless code_object.docstring.blank?
214
+ examples_object = code_object.tags('example')
215
+ end
216
+ cops_body(config, cop, description, examples_object, pars)
217
+ end
218
+
219
+ def cop_code(cop)
220
+ YARD::Registry.all(:class).detect do |code_object|
221
+ next unless RuboCop::Cop::Badge.for(code_object.to_s) == cop.badge
222
+
223
+ yield code_object
224
+ end
225
+ end
226
+
227
+ def table_of_content_for_department(cops, department)
228
+ type_title = department[0].upcase + department[1..-1]
229
+ filename = "cops_#{department.downcase}.adoc"
230
+ content = +"=== Department xref:#{filename}[#{type_title}]\n\n"
231
+ cops_of_department(cops, department.to_sym).each do |cop|
232
+ anchor = cop.cop_name.sub('/', '').downcase
233
+ content << "* xref:#{filename}##{anchor}[#{cop.cop_name}]\n"
234
+ end
235
+
236
+ content
237
+ end
238
+
239
+ def print_table_of_contents(cops)
240
+ path = "#{Dir.pwd}/docs/modules/ROOT/pages/cops.adoc"
241
+ original = File.read(path)
242
+ content = +"// START_COP_LIST\n\n"
243
+
244
+ content << table_contents(cops)
245
+
246
+ content << "\n// END_COP_LIST"
247
+
248
+ content = original.sub(
249
+ %r{// START_COP_LIST.+// END_COP_LIST}m, content
250
+ )
251
+ File.write(path, content)
252
+ end
253
+
254
+ def table_contents(cops)
255
+ cops
256
+ .departments
257
+ .map(&:to_s)
258
+ .sort
259
+ .map { |department| table_of_content_for_department(cops, department) }
260
+ .join("\n")
261
+ end
262
+
263
+ def cop_status(status)
264
+ return 'Disabled' unless status
265
+
266
+ status == 'pending' ? 'Pending' : 'Enabled'
267
+ end
268
+
269
+ def assert_docs_synchronized
270
+ # Do not print diff and yield whether exit code was zero
271
+ sh('git diff --quiet docs') do |outcome, _|
272
+ return if outcome
273
+
274
+ # Output diff before raising error
275
+ sh('GIT_PAGER=cat git diff docs')
276
+
277
+ warn 'The docs directory is out of sync. ' \
278
+ 'Run `rake generate_cops_documentation` and commit the results.'
279
+ exit!
280
+ end
281
+ end
282
+
283
+ def main
284
+ cops = RuboCop::Cop::Cop.registry
285
+ config = RuboCop::ConfigLoader.default_configuration
286
+
287
+ YARD::Registry.load!
288
+ cops.departments.sort!.each do |department|
289
+ print_cops_of_department(cops, department, config)
290
+ end
291
+
292
+ print_table_of_contents(cops)
293
+
294
+ assert_docs_synchronized if ENV['CI'] == 'true'
295
+ ensure
296
+ RuboCop::ConfigLoader.default_configuration = nil
297
+ end
298
+
299
+ main
300
+ end