foodcritic 7.0.1 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/Gemfile +10 -10
- data/Rakefile +21 -21
- data/bin/foodcritic +1 -1
- data/chef_dsl_metadata/chef_12.12.13.json +17809 -0
- data/chef_dsl_metadata/chef_12.13.37.json +18021 -0
- data/features/step_definitions/cookbook_steps.rb +456 -457
- data/features/support/command_helpers.rb +120 -120
- data/features/support/cookbook_helpers.rb +87 -87
- data/features/support/env.rb +6 -6
- data/foodcritic.gemspec +22 -22
- data/lib/foodcritic.rb +20 -20
- data/lib/foodcritic/api.rb +94 -91
- data/lib/foodcritic/chef.rb +14 -14
- data/lib/foodcritic/command_line.rb +35 -35
- data/lib/foodcritic/domain.rb +4 -4
- data/lib/foodcritic/dsl.rb +1 -2
- data/lib/foodcritic/linter.rb +31 -32
- data/lib/foodcritic/notifications.rb +5 -5
- data/lib/foodcritic/output.rb +5 -5
- data/lib/foodcritic/rake_task.rb +7 -7
- data/lib/foodcritic/rules.rb +234 -234
- data/lib/foodcritic/template.rb +1 -1
- data/lib/foodcritic/version.rb +1 -1
- data/lib/foodcritic/xml.rb +5 -5
- data/spec/foodcritic/api_spec.rb +275 -275
- data/spec/foodcritic/chef_spec.rb +11 -11
- data/spec/foodcritic/command_line_spec.rb +7 -7
- data/spec/foodcritic/domain_spec.rb +20 -20
- data/spec/foodcritic/linter_spec.rb +10 -11
- data/spec/foodcritic/template_spec.rb +8 -8
- data/spec/regression/regression_spec.rb +3 -3
- data/spec/regression_helpers.rb +10 -10
- data/spec/spec_helper.rb +6 -6
- metadata +5 -3
@@ -14,74 +14,74 @@ module FoodCritic
|
|
14
14
|
|
15
15
|
# The warning codes and messages displayed to the end user.
|
16
16
|
WARNINGS = {
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
17
|
+
"FC001" => "Use strings in preference to symbols to access node attributes",
|
18
|
+
"FC002" => "Avoid string interpolation where not required",
|
19
|
+
"FC003" => "Check whether you are running with chef server before using server-specific features",
|
20
|
+
"FC004" => "Use a service resource to start and stop services",
|
21
|
+
"FC005" => "Avoid repetition of resource declarations",
|
22
|
+
"FC006" => "Mode should be quoted or fully specified when setting file permissions",
|
23
|
+
"FC007" => "Ensure recipe dependencies are reflected in cookbook metadata",
|
24
|
+
"FC008" => "Generated cookbook metadata needs updating",
|
25
|
+
"FC009" => "Resource attribute not recognised",
|
26
|
+
"FC010" => "Invalid search syntax",
|
27
|
+
"FC011" => "Missing README in markdown format",
|
28
|
+
"FC012" => "Use Markdown for README rather than RDoc",
|
29
|
+
"FC013" => "Use file_cache_path rather than hard-coding tmp paths",
|
30
|
+
"FC014" => "Consider extracting long ruby_block to library",
|
31
|
+
"FC015" => "Consider converting definition to a Custom Resource",
|
32
|
+
"FC016" => "LWRP does not declare a default action",
|
33
|
+
"FC017" => "LWRP does not notify when updated",
|
34
|
+
"FC018" => "LWRP uses deprecated notification syntax",
|
35
|
+
"FC019" => "Access node attributes in a consistent manner",
|
36
|
+
"FC021" => "Resource condition in provider may not behave as expected",
|
37
|
+
"FC022" => "Resource condition within loop may not behave as expected",
|
38
|
+
"FC023" => "Prefer conditional attributes",
|
39
|
+
"FC024" => "Consider adding platform equivalents",
|
40
|
+
"FC025" => "Prefer chef_gem to compile-time gem install",
|
41
|
+
"FC026" => "Conditional execution block attribute contains only string",
|
42
|
+
"FC027" => "Resource sets internal attribute",
|
43
|
+
"FC028" => 'Incorrect #platform? usage',
|
44
|
+
"FC029" => "No leading cookbook name in recipe metadata",
|
45
|
+
"FC030" => "Cookbook contains debugger breakpoints",
|
46
|
+
"FC031" => "Cookbook without metadata file",
|
47
|
+
"FC032" => "Invalid notification timing",
|
48
|
+
"FC033" => "Missing template",
|
49
|
+
"FC034" => "Unused template variables",
|
50
|
+
"FC037" => "Invalid notification action",
|
51
|
+
"FC038" => "Invalid resource action",
|
52
|
+
"FC039" => "Node method cannot be accessed with key",
|
53
|
+
"FC040" => "Execute resource used to run git commands",
|
54
|
+
"FC041" => "Execute resource used to run curl or wget commands",
|
55
|
+
"FC042" => "Prefer include_recipe to require_recipe",
|
56
|
+
"FC043" => "Prefer new notification syntax",
|
57
|
+
"FC044" => "Avoid bare attribute keys",
|
58
|
+
"FC045" => "Metadata does not contain cookbook name",
|
59
|
+
"FC046" => "Attribute assignment uses assign unless nil",
|
60
|
+
"FC047" => "Attribute assignment does not specify precedence",
|
61
|
+
"FC048" => "Prefer Mixlib::ShellOut",
|
62
|
+
"FC049" => "Role name does not match containing file name",
|
63
|
+
"FC050" => "Name includes invalid characters",
|
64
|
+
"FC051" => "Template partials loop indefinitely",
|
65
|
+
"FC052" => 'Metadata uses the unimplemented "suggests" keyword',
|
66
|
+
"FC053" => 'Metadata uses the unimplemented "recommends" keyword',
|
67
67
|
# FC054 was yanked and is considered reserved, do not reuse it
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
68
|
+
"FC055" => "Ensure maintainer is set in metadata",
|
69
|
+
"FC056" => "Ensure maintainer_email is set in metadata",
|
70
|
+
"FC057" => "Library provider does not declare use_inline_resources",
|
71
|
+
"FC058" => 'Library provider declares use_inline_resources and declares #action_<name> methods',
|
72
|
+
"FC059" => "LWRP provider does not declare use_inline_resources",
|
73
|
+
"FC060" => 'LWRP provider declares use_inline_resources and declares #action_<name> methods',
|
74
|
+
"FC061" => "Valid cookbook versions are of the form x.y or x.y.z",
|
75
|
+
"FC062" => "Cookbook should have version metadata",
|
76
|
+
"FC063" => "Cookbook incorrectly depends on itself",
|
77
|
+
"FC064" => "Ensure issues_url is set in metadata",
|
78
|
+
"FC065" => "Ensure source_url is set in metadata",
|
79
|
+
"FCTEST001" => "Test Rule",
|
80
80
|
}
|
81
81
|
|
82
82
|
# If the cucumber features should run foodcritic in the same process or spawn a separate process.
|
83
83
|
def self.running_in_process?
|
84
|
-
! (ENV.has_key?(
|
84
|
+
! (ENV.has_key?("FC_FORK_PROCESS") && ENV["FC_FORK_PROCESS"] == true.to_s)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Capture an error expected when calling a command.
|
@@ -117,16 +117,16 @@ module FoodCritic
|
|
117
117
|
# @option options [String] :file The path to the file the warning should be raised against
|
118
118
|
# @option options [Symbol] :file_type Alternative to specifying file name. One of: :attributes, :definition,
|
119
119
|
# :metadata, :provider, :resource
|
120
|
-
def expect_warning(code, options={})
|
120
|
+
def expect_warning(code, options = {})
|
121
121
|
if options.has_key?(:file_type)
|
122
|
-
options[:file] = {:attributes =>
|
123
|
-
|
124
|
-
|
122
|
+
options[:file] = { :attributes => "attributes/default.rb", :definition => "definitions/apache_site.rb",
|
123
|
+
:metadata => "metadata.rb", :provider => "providers/site.rb",
|
124
|
+
:resource => "resources/site.rb", :libraries => "libraries/lib.rb" }[options[:file_type]]
|
125
125
|
end
|
126
|
-
options = {:line => 1, :expect_warning => true, :file =>
|
127
|
-
unless options[:file].include?(
|
128
|
-
|
129
|
-
|
126
|
+
options = { :line => 1, :expect_warning => true, :file => "recipes/default.rb" }.merge!(options)
|
127
|
+
unless options[:file].include?("roles") ||
|
128
|
+
options[:file].include?("environments")
|
129
|
+
options[:file] = "cookbooks/example/#{options[:file]}"
|
130
130
|
end
|
131
131
|
if options[:warning_only]
|
132
132
|
warning = "#{code}: #{WARNINGS[code]}"
|
@@ -139,7 +139,7 @@ module FoodCritic
|
|
139
139
|
# Expect a warning not to be included in the command output.
|
140
140
|
#
|
141
141
|
# @see CommandHelpers#expect_warning
|
142
|
-
def expect_no_warning(code, options={:expect_warning => false})
|
142
|
+
def expect_no_warning(code, options = { :expect_warning => false })
|
143
143
|
expect_warning(code, options)
|
144
144
|
end
|
145
145
|
|
@@ -155,28 +155,28 @@ module FoodCritic
|
|
155
155
|
|
156
156
|
def has_test_warnings?(output)
|
157
157
|
output.split("\n").grep(/FC[0-9]+:/).map do |warn|
|
158
|
-
File.basename(File.dirname(warn.split(
|
159
|
-
end.include?(
|
158
|
+
File.basename(File.dirname(warn.split(":").take(3).last.strip))
|
159
|
+
end.include?("test")
|
160
160
|
end
|
161
161
|
|
162
162
|
def man_page_options
|
163
|
-
man_path = Pathname.new(__FILE__) +
|
163
|
+
man_path = Pathname.new(__FILE__) + "../../../man/foodcritic.1.ronn"
|
164
164
|
option_lines = File.read(man_path).split('## ').find do |s|
|
165
|
-
s.start_with?(
|
166
|
-
end.split("\n").select{|o| o.start_with?(
|
165
|
+
s.start_with?("OPTIONS")
|
166
|
+
end.split("\n").select { |o| o.start_with?(" *") }
|
167
167
|
option_lines.map do |o|
|
168
|
-
o.sub(
|
168
|
+
o.sub("`[`no-`]`", "").split("`").select { |f| f.include?("-") }
|
169
169
|
end.map do |option|
|
170
|
-
{:short => option.first.sub(/^-/,
|
171
|
-
|
172
|
-
end.sort_by{|o| o[:short]}
|
170
|
+
{ :short => option.first.sub(/^-/, ""),
|
171
|
+
:long => option.last.sub(/^--/, "") }
|
172
|
+
end.sort_by { |o| o[:short] }
|
173
173
|
end
|
174
174
|
|
175
175
|
# Assert that the usage message is displayed.
|
176
176
|
#
|
177
177
|
# @param [Boolean] is_exit_zero The exit code to check for.
|
178
178
|
def usage_displayed(is_exit_zero)
|
179
|
-
expect_output
|
179
|
+
expect_output "foodcritic [cookbook_paths]"
|
180
180
|
|
181
181
|
usage_options.each do |option|
|
182
182
|
expect_usage_option(option[:short], option[:long], option[:description])
|
@@ -191,50 +191,50 @@ module FoodCritic
|
|
191
191
|
|
192
192
|
def usage_options
|
193
193
|
[
|
194
|
-
{:short =>
|
195
|
-
|
194
|
+
{ :short => "c", :long => "chef-version VERSION",
|
195
|
+
:description => "Only check against rules valid for this version of Chef." },
|
196
196
|
|
197
|
-
{:short =>
|
198
|
-
|
197
|
+
{ :short => "f", :long => "epic-fail TAGS",
|
198
|
+
:description => "Fail the build based on tags. Use 'any' to fail on all warnings." },
|
199
199
|
|
200
|
-
{:short =>
|
201
|
-
|
200
|
+
{ :short => "l", :long => "list",
|
201
|
+
:description => "List all enabled rules and their descriptions." },
|
202
202
|
|
203
|
-
{:short =>
|
204
|
-
|
203
|
+
{ :short => "t", :long => "tags TAGS",
|
204
|
+
:description => "Check against (or exclude ~) rules with the specified tags." },
|
205
205
|
|
206
|
-
{:short =>
|
207
|
-
|
206
|
+
{ :short => "B", :long => "cookbook-path PATH",
|
207
|
+
:description => "Cookbook path(s) to check." },
|
208
208
|
|
209
|
-
{:short =>
|
210
|
-
|
209
|
+
{ :short => "C", :long => "[no-]context",
|
210
|
+
:description => "Show lines matched against rather than the default summary." },
|
211
211
|
|
212
|
-
{:short =>
|
213
|
-
|
212
|
+
{ :short => "E", :long => "environment-path PATH",
|
213
|
+
:description => "Environment path(s) to check." },
|
214
214
|
|
215
|
-
{:short =>
|
216
|
-
|
215
|
+
{ :short => "I", :long => "include PATH",
|
216
|
+
:description => "Additional rule file path(s) to load." },
|
217
217
|
|
218
|
-
{:short =>
|
219
|
-
|
218
|
+
{ :short => "R", :long => "role-path PATH",
|
219
|
+
:description => "Role path(s) to check." },
|
220
220
|
|
221
|
-
{:short =>
|
222
|
-
|
221
|
+
{ :short => "S", :long => "search-grammar PATH",
|
222
|
+
:description => "Specify grammar to use when validating search syntax." },
|
223
223
|
|
224
|
-
{:short =>
|
225
|
-
|
224
|
+
{ :short => "V", :long => "version",
|
225
|
+
:description => "Display the foodcritic version." },
|
226
226
|
|
227
|
-
{:short =>
|
228
|
-
|
227
|
+
{ :short => "X", :long => "exclude PATH",
|
228
|
+
:description => "Exclude path(s) from being linted." },
|
229
229
|
|
230
230
|
]
|
231
231
|
end
|
232
232
|
|
233
233
|
def usage_options_for_diff
|
234
234
|
usage_options.map do |o|
|
235
|
-
{:short => o[:short],
|
236
|
-
|
237
|
-
end.sort_by{|o| o[:short]}
|
235
|
+
{ :short => o[:short],
|
236
|
+
:long => o[:long].split(" ").first.sub(/^\[no-\]/, "") }
|
237
|
+
end.sort_by { |o| o[:short] }
|
238
238
|
end
|
239
239
|
|
240
240
|
end
|
@@ -290,12 +290,12 @@ module FoodCritic
|
|
290
290
|
#
|
291
291
|
# @param [Array] cmd_args The command line arguments.
|
292
292
|
def run_lint(cmd_args)
|
293
|
-
cd
|
294
|
-
show_context = cmd_args.include?(
|
293
|
+
cd "." do
|
294
|
+
show_context = cmd_args.include?("-C")
|
295
295
|
review, @status = FoodCritic::Linter.run(CommandLine.new(cmd_args))
|
296
296
|
@review =
|
297
297
|
if review.nil? || (review.respond_to?(:warnings) && review.warnings.empty?)
|
298
|
-
|
298
|
+
""
|
299
299
|
elsif show_context
|
300
300
|
ContextOutput.new.output(review)
|
301
301
|
else
|
@@ -338,21 +338,21 @@ module FoodCritic
|
|
338
338
|
# @return [Array] Task name and description
|
339
339
|
def build_tasks
|
340
340
|
all_output.split("\n").map do |task|
|
341
|
-
next unless task.start_with?
|
342
|
-
task.split("#").map{|t| t.strip.sub(/^rake /,
|
341
|
+
next unless task.start_with? "rake"
|
342
|
+
task.split("#").map { |t| t.strip.sub(/^rake /, "") }
|
343
343
|
end.compact
|
344
344
|
end
|
345
345
|
|
346
346
|
# List the defined Rake tasks
|
347
347
|
def list_available_build_tasks
|
348
|
-
cd
|
348
|
+
cd "cookbooks/example"
|
349
349
|
unset_bundler_env_vars
|
350
|
-
run_simple
|
350
|
+
run_simple "bundle exec rake -T"
|
351
351
|
end
|
352
352
|
|
353
353
|
# Run a build for a Rakefile that uses the lint rake task
|
354
354
|
def run_build
|
355
|
-
cd
|
355
|
+
cd "cookbooks/example"
|
356
356
|
run_simple "bundle exec rake", false
|
357
357
|
end
|
358
358
|
|
@@ -360,10 +360,10 @@ module FoodCritic
|
|
360
360
|
# performance hit and because gems may contain deeply-nested code which
|
361
361
|
# will blow the stack on parsing.
|
362
362
|
def vendor_gems
|
363
|
-
cd
|
363
|
+
cd "cookbooks/example"
|
364
364
|
unset_bundler_env_vars
|
365
|
-
run_simple
|
366
|
-
cd
|
365
|
+
run_simple "bundle install --path vendor/bundle"
|
366
|
+
cd "../.."
|
367
367
|
end
|
368
368
|
|
369
369
|
end
|
@@ -12,7 +12,7 @@ module FoodCritic
|
|
12
12
|
|
13
13
|
# Create a Gemfile for a cookbook
|
14
14
|
def buildable_gemfile
|
15
|
-
write_file
|
15
|
+
write_file "cookbooks/example/Gemfile", %q{
|
16
16
|
source 'https://rubygems.org/'
|
17
17
|
gem 'rake'
|
18
18
|
gem 'foodcritic', :path => '../../../..'
|
@@ -45,24 +45,24 @@ module FoodCritic
|
|
45
45
|
#
|
46
46
|
# @param [Array] codes The codes to match. Only FC002, FC003 and FC004 are supported.
|
47
47
|
def cookbook_that_matches_rules(codes)
|
48
|
-
recipe =
|
48
|
+
recipe = ""
|
49
49
|
codes.each do |code|
|
50
|
-
if code ==
|
50
|
+
if code == "FC002"
|
51
51
|
recipe += %q{
|
52
52
|
directory "#{node['base_dir']}" do
|
53
53
|
action :create
|
54
54
|
end
|
55
55
|
}
|
56
|
-
elsif code ==
|
56
|
+
elsif code == "FC003"
|
57
57
|
recipe += %Q{nodes = search(:node, "hostname:[* TO *]")\n}
|
58
|
-
elsif code ==
|
58
|
+
elsif code == "FC004"
|
59
59
|
recipe += %q{
|
60
60
|
execute "stop-jetty" do
|
61
61
|
command "/etc/init.d/jetty6 stop"
|
62
62
|
action :run
|
63
63
|
end
|
64
64
|
}
|
65
|
-
elsif code ==
|
65
|
+
elsif code == "FC006"
|
66
66
|
recipe += %q{
|
67
67
|
directory "/var/lib/foo" do
|
68
68
|
mode 644
|
@@ -72,16 +72,16 @@ module FoodCritic
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
write_recipe(recipe)
|
75
|
-
write_file(
|
76
|
-
write_readme(
|
77
|
-
write_metadata(%q
|
75
|
+
write_file("cookbooks/example/recipes/server.rb", "")
|
76
|
+
write_readme("Hello World") # Don't trigger FC011
|
77
|
+
write_metadata(%q{
|
78
78
|
name 'example'
|
79
79
|
maintainer 'A Maintainer'
|
80
80
|
maintainer_email 'maintainer@example.com'
|
81
81
|
version '0.0.1'
|
82
82
|
issues_url 'http://github.com/foo/bar_cookbook/issues'
|
83
83
|
source_url 'http://github.com/foo/bar_cookbook'
|
84
|
-
|
84
|
+
}.strip)
|
85
85
|
end
|
86
86
|
|
87
87
|
# Create a cookbook with a LRWP
|
@@ -91,8 +91,8 @@ module FoodCritic
|
|
91
91
|
# @option lwrp [Symbol] :notifies One of :does_not_notify, :does_notify, :does_notify_without_parens, :deprecated_syntax, :class_variable
|
92
92
|
# @option lwrp [Symbol] :use_inline_resources Defaults to false
|
93
93
|
def cookbook_with_lwrp(lwrp)
|
94
|
-
lwrp = {:default_action => false, :notifies => :does_not_notify,
|
95
|
-
|
94
|
+
lwrp = { :default_action => false, :notifies => :does_not_notify,
|
95
|
+
:use_inline_resources => false }.merge!(lwrp)
|
96
96
|
ruby_default_action = %q{
|
97
97
|
def initialize(*args)
|
98
98
|
super
|
@@ -105,10 +105,10 @@ module FoodCritic
|
|
105
105
|
#{ruby_default_action if lwrp[:default_action] == :ruby_default_action}
|
106
106
|
#{'default_action :create' if lwrp[:default_action] == :dsl_default_action}
|
107
107
|
})
|
108
|
-
notifications = {:does_notify =>
|
109
|
-
|
110
|
-
|
111
|
-
|
108
|
+
notifications = { :does_notify => "new_resource.updated_by_last_action(true)",
|
109
|
+
:does_notify_without_parens => "new_resource.updated_by_last_action true",
|
110
|
+
:deprecated_syntax => "new_resource.updated = true",
|
111
|
+
:class_variable => "@updated = true" }
|
112
112
|
write_provider("site", %Q{
|
113
113
|
#{'use_inline_resources' if lwrp[:use_inline_resources]}
|
114
114
|
action :create do
|
@@ -120,10 +120,10 @@ module FoodCritic
|
|
120
120
|
|
121
121
|
def cookbook_with_lwrp_actions(actions)
|
122
122
|
write_resource("site", %Q{
|
123
|
-
actions #{actions.map{|a| a[:name].inspect}.join(', ')}
|
123
|
+
actions #{actions.map { |a| a[:name].inspect }.join(', ')}
|
124
124
|
attribute :name, :kind_of => String, :name_attribute => true
|
125
125
|
})
|
126
|
-
write_provider("site", actions.map{|a| provider_action(a)}.join("\n"))
|
126
|
+
write_provider("site", actions.map { |a| provider_action(a) }.join("\n"))
|
127
127
|
end
|
128
128
|
|
129
129
|
# Create an cookbook with the maintainer specified in the metadata
|
@@ -143,10 +143,10 @@ module FoodCritic
|
|
143
143
|
}
|
144
144
|
|
145
145
|
fields = {}
|
146
|
-
fields[
|
147
|
-
fields[
|
146
|
+
fields["maintainer"] = name unless name.nil?
|
147
|
+
fields["maintainer_email"] = email unless email.nil?
|
148
148
|
write_metadata %Q{
|
149
|
-
#{fields.map{|field,value| %Q{#{field}\t"#{value}"}}.join("\n")}
|
149
|
+
#{fields.map { |field, value| %Q{#{field}\t"#{value}"} }.join("\n")}
|
150
150
|
license "All rights reserved"
|
151
151
|
description "Installs/Configures example"
|
152
152
|
long_description IO.read(File.join(File.dirname(__FILE__), 'README.rdoc'))
|
@@ -160,10 +160,10 @@ module FoodCritic
|
|
160
160
|
# @option options [String] :dir The relative directory to write to
|
161
161
|
# @option options [String] :environment_name The name of the environment declared in the file
|
162
162
|
# @option options [String] :file_name The containing file relative to the environments directory
|
163
|
-
def environment(options={})
|
164
|
-
options = {:dir =>
|
163
|
+
def environment(options = {})
|
164
|
+
options = { :dir => "environments" }.merge(options)
|
165
165
|
write_file "#{options[:dir]}/#{options[:file_name]}", %Q{
|
166
|
-
#{Array(options[:environment_name]).map{|r| "name #{r}"}.join("\n")}
|
166
|
+
#{Array(options[:environment_name]).map { |r| "name #{r}" }.join("\n")}
|
167
167
|
cookbook "apache2"
|
168
168
|
}.strip
|
169
169
|
end
|
@@ -171,7 +171,7 @@ module FoodCritic
|
|
171
171
|
# Create a placeholder minitest spec that would be linted due to its path
|
172
172
|
# unless an exclusion is specified.
|
173
173
|
def minitest_spec_attributes
|
174
|
-
write_file
|
174
|
+
write_file "cookbooks/example/test/attributes/default_spec.rb", %q{
|
175
175
|
describe 'Example::Attributes::Default' do
|
176
176
|
end
|
177
177
|
}
|
@@ -209,9 +209,9 @@ module FoodCritic
|
|
209
209
|
# @option options [String] :files Files to process
|
210
210
|
# @option options [String] :options The options to set on the rake task
|
211
211
|
def rakefile(task, options)
|
212
|
-
rakefile_content =
|
212
|
+
rakefile_content = "task :default => []"
|
213
213
|
task_def = case task
|
214
|
-
when :no_block then
|
214
|
+
when :no_block then "FoodCritic::Rake::LintTask.new"
|
215
215
|
else %Q{
|
216
216
|
FoodCritic::Rake::LintTask.new do |t|
|
217
217
|
#{"t.name = '#{options[:name]}'" if options[:name]}
|
@@ -227,17 +227,17 @@ module FoodCritic
|
|
227
227
|
#{task_def}
|
228
228
|
}
|
229
229
|
end
|
230
|
-
write_file
|
230
|
+
write_file "cookbooks/example/Rakefile", rakefile_content
|
231
231
|
end
|
232
232
|
|
233
233
|
# Create a recipe that downloads a file
|
234
234
|
#
|
235
235
|
# @param [Symbol] path_type The type of path, one of: :tmp_dir, :chef_file_cache_dir, :home_dir
|
236
236
|
def recipe_downloads_file(path_type)
|
237
|
-
download_path = {:tmp_dir =>
|
238
|
-
|
239
|
-
|
240
|
-
|
237
|
+
download_path = { :tmp_dir => "/tmp/large-file.tar.gz",
|
238
|
+
:tmp_dir_expr => '/tmp/#{file}',
|
239
|
+
:home_dir => "/home/ernie/large-file.tar.gz",
|
240
|
+
:chef_file_cache_dir => '#{Chef::Config[:file_cache_path]}/large-file.tar.gz' }[path_type]
|
241
241
|
write_recipe %Q{
|
242
242
|
remote_file "#{download_path}" do
|
243
243
|
source "http://www.example.org/large-file.tar.gz"
|
@@ -286,7 +286,7 @@ module FoodCritic
|
|
286
286
|
end
|
287
287
|
}.strip
|
288
288
|
else
|
289
|
-
|
289
|
+
raise "Unrecognised type: #{type}"
|
290
290
|
end
|
291
291
|
end
|
292
292
|
|
@@ -295,8 +295,8 @@ module FoodCritic
|
|
295
295
|
# @param [String] type The type of resource (file, template)
|
296
296
|
# @param [String] mode The file mode as a string
|
297
297
|
# @param [String] comment Comment that may specify to exclude a match
|
298
|
-
def recipe_resource_with_mode(type, mode, comment=
|
299
|
-
source_att = type ==
|
298
|
+
def recipe_resource_with_mode(type, mode, comment = "")
|
299
|
+
source_att = type == "template" ? 'source "foo.erb"' : ""
|
300
300
|
write_recipe %Q{
|
301
301
|
#{type} "/tmp/something" do #{comment}
|
302
302
|
#{source_att}
|
@@ -314,8 +314,8 @@ module FoodCritic
|
|
314
314
|
# @param [Boolean] do_sleep Whether to prefix the service cmd with a bash sleep
|
315
315
|
# @param [Symbol] action The action to take (start, stop, reload, restart)
|
316
316
|
def recipe_controls_service(method = :service, do_sleep = false, action = :start)
|
317
|
-
cmds = {:init_d => "/etc/init.d/foo #{action}", :invoke_rc_d => "invoke-rc.d foo #{action}", :upstart => "#{action} foo",
|
318
|
-
|
317
|
+
cmds = { :init_d => "/etc/init.d/foo #{action}", :invoke_rc_d => "invoke-rc.d foo #{action}", :upstart => "#{action} foo",
|
318
|
+
:service => "service foo #{action}", :service_full_path => "/sbin/service foo #{action}" }
|
319
319
|
write_recipe %Q{
|
320
320
|
execute "#{action}-foo-service" do
|
321
321
|
command "#{do_sleep ? 'sleep 5; ' : ''}#{cmds[method]}"
|
@@ -331,13 +331,13 @@ module FoodCritic
|
|
331
331
|
# @option dep [Boolean] :is_scoped True if the include_recipe references a specific recipe or the cookbook
|
332
332
|
# @option dep [Boolean] :parentheses True if the include_recipe is called with parentheses
|
333
333
|
def recipe_with_dependency(dep)
|
334
|
-
dep = {:is_scoped => true, :is_declared => true,
|
335
|
-
|
334
|
+
dep = { :is_scoped => true, :is_declared => true,
|
335
|
+
:parentheses => false }.merge!(dep)
|
336
336
|
recipe = "foo#{dep[:is_scoped] ? '::default' : ''}"
|
337
337
|
write_recipe(if dep[:parentheses]
|
338
|
-
|
339
|
-
|
340
|
-
|
338
|
+
"include_recipe('#{recipe}')"
|
339
|
+
else
|
340
|
+
"include_recipe '#{recipe}'"
|
341
341
|
end)
|
342
342
|
write_metadata %Q{
|
343
343
|
version "1.9.0"
|
@@ -350,9 +350,9 @@ module FoodCritic
|
|
350
350
|
# @param [Symbol] path_expr_type The type of path expression, one of: :compound_symbols, :interpolated_string,
|
351
351
|
# :interpolated_symbol, :interpolated_symbol_and_literal, :literal_and_interpolated_symbol, :string_literal.
|
352
352
|
def recipe_with_dir_path(path_expr_type)
|
353
|
-
path = {:compound_symbols => '#{node[:base_dir]}#{node[:sub_dir]}', :interpolated_string => %q{#{node['base_dir']}},
|
354
|
-
|
355
|
-
|
353
|
+
path = { :compound_symbols => '#{node[:base_dir]}#{node[:sub_dir]}', :interpolated_string => %q{#{node['base_dir']}},
|
354
|
+
:interpolated_symbol => '#{node[:base_dir]}', :interpolated_symbol_and_literal => '#{node[:base_dir]}/sub_dir',
|
355
|
+
:literal_and_interpolated_symbol => 'base_dir/#{node[:sub_dir]}', :string_literal => "/var/lib/foo" }[path_expr_type]
|
356
356
|
write_recipe %Q{
|
357
357
|
directory "#{path}" do
|
358
358
|
owner "root"
|
@@ -379,7 +379,7 @@ module FoodCritic
|
|
379
379
|
#
|
380
380
|
# @param [Symbol] length A :short or :long block, or :both
|
381
381
|
def recipe_with_ruby_block(length)
|
382
|
-
recipe =
|
382
|
+
recipe = ""
|
383
383
|
if length == :short || length == :both
|
384
384
|
recipe << %q{
|
385
385
|
ruby_block "subexpressions" do
|
@@ -429,8 +429,8 @@ module FoodCritic
|
|
429
429
|
#
|
430
430
|
# @param [Symbol] type The type of search. One of: :invalid_syntax, :valid_syntax, :with_subexpression.
|
431
431
|
def recipe_with_search(type)
|
432
|
-
search = {:invalid_syntax =>
|
433
|
-
|
432
|
+
search = { :invalid_syntax => "run_list:recipe[foo::bar]", :valid_syntax => 'run_list:recipe\[foo\:\:bar\]',
|
433
|
+
:with_subexpression => %q{roles:#{node['foo']['role']}} }[type]
|
434
434
|
write_recipe %Q{
|
435
435
|
search(:node, "#{search}") do |matching_node|
|
436
436
|
puts matching_node.to_s
|
@@ -444,24 +444,24 @@ module FoodCritic
|
|
444
444
|
# @option options [String] :role_name The name of the role declared in the role file
|
445
445
|
# @option options [String] :file_name The containing file relative to the roles directory
|
446
446
|
# @option options [Symbol] :format Either :ruby or :json. Default is :ruby
|
447
|
-
def role(options={})
|
448
|
-
options = {:format => :ruby, :dir =>
|
447
|
+
def role(options = {})
|
448
|
+
options = { :format => :ruby, :dir => "roles" }.merge(options)
|
449
449
|
content = if options[:format] == :json
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
450
|
+
%Q{
|
451
|
+
{
|
452
|
+
"chef_type": "role",
|
453
|
+
"json_class": "Chef::Role",
|
454
|
+
#{Array(options[:role_name]).map { |r| "name: #{r}," }.join("\n")}
|
455
|
+
"run_list": [
|
456
|
+
"recipe[apache2]",
|
457
|
+
]
|
458
|
+
}
|
459
|
+
}
|
460
|
+
else
|
461
|
+
%Q{
|
462
|
+
#{Array(options[:role_name]).map { |r| "name #{r}" }.join("\n")}
|
463
|
+
run_list "recipe[apache2]"
|
464
|
+
}
|
465
465
|
end
|
466
466
|
write_file "#{options[:dir]}/#{options[:file_name]}", content.strip
|
467
467
|
end
|
@@ -472,23 +472,23 @@ module FoodCritic
|
|
472
472
|
# @param [String] to_version The to version
|
473
473
|
def rule_with_version_constraint(from_version, to_version)
|
474
474
|
constraint = if from_version && to_version
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
475
|
+
%Q{
|
476
|
+
applies_to do |version|
|
477
|
+
version >= gem_version("#{from_version}") && version <= gem_version("#{to_version}")
|
478
|
+
end
|
479
|
+
}
|
480
|
+
elsif from_version
|
481
|
+
%Q{
|
482
|
+
applies_to do |version|
|
483
|
+
version >= gem_version("#{from_version}")
|
484
|
+
end
|
485
|
+
}
|
486
|
+
elsif to_version
|
487
|
+
%Q{
|
488
|
+
applies_to do |version|
|
489
|
+
version <= gem_version("#{to_version}")
|
490
|
+
end
|
491
|
+
}
|
492
492
|
end
|
493
493
|
write_rule %Q{
|
494
494
|
rule "FCTEST001", "Test Rule" do
|
@@ -505,14 +505,14 @@ module FoodCritic
|
|
505
505
|
# @param [String] str The string
|
506
506
|
# @return [String] The string or nil if 'unspecified'
|
507
507
|
def nil_if_unspecified(str)
|
508
|
-
str ==
|
508
|
+
str == "unspecified" ? nil : str
|
509
509
|
end
|
510
510
|
|
511
511
|
# Create a README with the provided content.
|
512
512
|
#
|
513
513
|
# @param [String] content The recipe content.
|
514
514
|
# @param [String] cookbook_name Optional name of the cookbook.
|
515
|
-
def write_readme(content, cookbook_name =
|
515
|
+
def write_readme(content, cookbook_name = "example")
|
516
516
|
write_file "cookbooks/#{cookbook_name}/README.md", content.strip
|
517
517
|
end
|
518
518
|
|
@@ -520,7 +520,7 @@ module FoodCritic
|
|
520
520
|
#
|
521
521
|
# @param [String] content The recipe content.
|
522
522
|
# @param [String] cookbook_name Optional name of the cookbook.
|
523
|
-
def write_recipe(content, cookbook_name =
|
523
|
+
def write_recipe(content, cookbook_name = "example")
|
524
524
|
write_file "cookbooks/#{cookbook_name}/recipes/default.rb", content.strip
|
525
525
|
end
|
526
526
|
|
@@ -535,7 +535,7 @@ module FoodCritic
|
|
535
535
|
#
|
536
536
|
# @param [String] content The attributes content.
|
537
537
|
def write_attributes(content)
|
538
|
-
write_file
|
538
|
+
write_file "cookbooks/example/attributes/default.rb", content.strip
|
539
539
|
end
|
540
540
|
|
541
541
|
# Create a definition with the provided content.
|
@@ -558,7 +558,7 @@ module FoodCritic
|
|
558
558
|
#
|
559
559
|
# @param [String] content The metadata content.
|
560
560
|
def write_metadata(content)
|
561
|
-
write_file
|
561
|
+
write_file "cookbooks/example/metadata.rb", content.strip
|
562
562
|
end
|
563
563
|
|
564
564
|
# Create a resource with the provided content.
|