halyard-puppet-lint 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +10 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +20 -0
  6. data/README.md +210 -0
  7. data/Rakefile +7 -0
  8. data/bin/puppet-lint +7 -0
  9. data/lib/puppet-lint.rb +214 -0
  10. data/lib/puppet-lint/bin.rb +79 -0
  11. data/lib/puppet-lint/checkplugin.rb +176 -0
  12. data/lib/puppet-lint/checks.rb +91 -0
  13. data/lib/puppet-lint/configuration.rb +153 -0
  14. data/lib/puppet-lint/data.rb +521 -0
  15. data/lib/puppet-lint/lexer.rb +373 -0
  16. data/lib/puppet-lint/lexer/token.rb +101 -0
  17. data/lib/puppet-lint/monkeypatches.rb +2 -0
  18. data/lib/puppet-lint/monkeypatches/string_percent.rb +52 -0
  19. data/lib/puppet-lint/monkeypatches/string_prepend.rb +13 -0
  20. data/lib/puppet-lint/optparser.rb +118 -0
  21. data/lib/puppet-lint/plugins.rb +74 -0
  22. data/lib/puppet-lint/plugins/check_classes.rb +285 -0
  23. data/lib/puppet-lint/plugins/check_comments.rb +55 -0
  24. data/lib/puppet-lint/plugins/check_conditionals.rb +65 -0
  25. data/lib/puppet-lint/plugins/check_documentation.rb +31 -0
  26. data/lib/puppet-lint/plugins/check_nodes.rb +29 -0
  27. data/lib/puppet-lint/plugins/check_resources.rb +194 -0
  28. data/lib/puppet-lint/plugins/check_strings.rb +174 -0
  29. data/lib/puppet-lint/plugins/check_variables.rb +19 -0
  30. data/lib/puppet-lint/plugins/check_whitespace.rb +170 -0
  31. data/lib/puppet-lint/tasks/puppet-lint.rb +91 -0
  32. data/lib/puppet-lint/version.rb +3 -0
  33. data/puppet-lint.gemspec +24 -0
  34. data/spec/fixtures/test/manifests/fail.pp +2 -0
  35. data/spec/fixtures/test/manifests/ignore.pp +1 -0
  36. data/spec/fixtures/test/manifests/ignore_multiple_block.pp +6 -0
  37. data/spec/fixtures/test/manifests/ignore_multiple_line.pp +2 -0
  38. data/spec/fixtures/test/manifests/ignore_reason.pp +1 -0
  39. data/spec/fixtures/test/manifests/init.pp +3 -0
  40. data/spec/fixtures/test/manifests/malformed.pp +1 -0
  41. data/spec/fixtures/test/manifests/url_interpolation.pp +12 -0
  42. data/spec/fixtures/test/manifests/warning.pp +2 -0
  43. data/spec/puppet-lint/bin_spec.rb +326 -0
  44. data/spec/puppet-lint/configuration_spec.rb +56 -0
  45. data/spec/puppet-lint/ignore_overrides_spec.rb +109 -0
  46. data/spec/puppet-lint/lexer/token_spec.rb +18 -0
  47. data/spec/puppet-lint/lexer_spec.rb +783 -0
  48. data/spec/puppet-lint/plugins/check_classes/autoloader_layout_spec.rb +105 -0
  49. data/spec/puppet-lint/plugins/check_classes/class_inherits_from_params_class_spec.rb +35 -0
  50. data/spec/puppet-lint/plugins/check_classes/inherits_across_namespaces_spec.rb +33 -0
  51. data/spec/puppet-lint/plugins/check_classes/names_containing_dash_spec.rb +45 -0
  52. data/spec/puppet-lint/plugins/check_classes/nested_classes_or_defines_spec.rb +76 -0
  53. data/spec/puppet-lint/plugins/check_classes/parameter_order_spec.rb +73 -0
  54. data/spec/puppet-lint/plugins/check_classes/right_to_left_relationship_spec.rb +25 -0
  55. data/spec/puppet-lint/plugins/check_classes/variable_scope_spec.rb +196 -0
  56. data/spec/puppet-lint/plugins/check_comments/slash_comments_spec.rb +45 -0
  57. data/spec/puppet-lint/plugins/check_comments/star_comments_spec.rb +84 -0
  58. data/spec/puppet-lint/plugins/check_conditionals/case_without_default_spec.rb +98 -0
  59. data/spec/puppet-lint/plugins/check_conditionals/selector_inside_resource_spec.rb +36 -0
  60. data/spec/puppet-lint/plugins/check_documentation/documentation_spec.rb +52 -0
  61. data/spec/puppet-lint/plugins/check_nodes/unquoted_node_name_spec.rb +146 -0
  62. data/spec/puppet-lint/plugins/check_resources/duplicate_params_spec.rb +100 -0
  63. data/spec/puppet-lint/plugins/check_resources/ensure_first_param_spec.rb +55 -0
  64. data/spec/puppet-lint/plugins/check_resources/ensure_not_symlink_target_spec.rb +89 -0
  65. data/spec/puppet-lint/plugins/check_resources/file_mode_spec.rb +113 -0
  66. data/spec/puppet-lint/plugins/check_resources/unquoted_file_mode_spec.rb +45 -0
  67. data/spec/puppet-lint/plugins/check_resources/unquoted_resource_title_spec.rb +216 -0
  68. data/spec/puppet-lint/plugins/check_strings/double_quoted_strings_spec.rb +199 -0
  69. data/spec/puppet-lint/plugins/check_strings/only_variable_string_spec.rb +114 -0
  70. data/spec/puppet-lint/plugins/check_strings/puppet_url_without_modules_spec.rb +62 -0
  71. data/spec/puppet-lint/plugins/check_strings/quoted_booleans_spec.rb +129 -0
  72. data/spec/puppet-lint/plugins/check_strings/single_quote_string_with_variables_spec.rb +17 -0
  73. data/spec/puppet-lint/plugins/check_strings/variables_not_enclosed_spec.rb +73 -0
  74. data/spec/puppet-lint/plugins/check_variables/variable_contains_dash_spec.rb +37 -0
  75. data/spec/puppet-lint/plugins/check_whitespace/2sp_soft_tabs_spec.rb +21 -0
  76. data/spec/puppet-lint/plugins/check_whitespace/80chars_spec.rb +54 -0
  77. data/spec/puppet-lint/plugins/check_whitespace/arrow_alignment_spec.rb +524 -0
  78. data/spec/puppet-lint/plugins/check_whitespace/hard_tabs_spec.rb +45 -0
  79. data/spec/puppet-lint/plugins/check_whitespace/trailing_whitespace_spec.rb +101 -0
  80. data/spec/puppet-lint_spec.rb +20 -0
  81. data/spec/spec_helper.rb +129 -0
  82. metadata +229 -0
@@ -0,0 +1,19 @@
1
+ # Public: Test the manifest tokens for variables that contain a dash and
2
+ # record a warning for each instance found.
3
+ PuppetLint.new_check(:variable_contains_dash) do
4
+ VARIABLE_TYPES = Set[:VARIABLE, :UNENC_VARIABLE]
5
+
6
+ def check
7
+ tokens.select { |r|
8
+ VARIABLE_TYPES.include? r.type
9
+ }.each do |token|
10
+ if token.value.gsub(/\[.+?\]/, '').match(/-/)
11
+ notify :warning, {
12
+ :message => 'variable contains a dash',
13
+ :line => token.line,
14
+ :column => token.column,
15
+ }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,170 @@
1
+ # Public: Check the raw manifest string for lines containing hard tab
2
+ # characters and record an error for each instance found.
3
+ PuppetLint.new_check(:hard_tabs) do
4
+ WHITESPACE_TYPES = Set[:INDENT, :WHITESPACE]
5
+
6
+ def check
7
+ tokens.select { |r|
8
+ WHITESPACE_TYPES.include?(r.type) && r.value.include?("\t")
9
+ }.each do |token|
10
+ notify :error, {
11
+ :message => 'tab character found',
12
+ :line => token.line,
13
+ :column => token.column,
14
+ :token => token,
15
+ }
16
+ end
17
+ end
18
+
19
+ def fix(problem)
20
+ problem[:token].value.gsub!("\t", ' ')
21
+ end
22
+ end
23
+
24
+ # Public: Check the manifest tokens for lines ending with whitespace and record
25
+ # an error for each instance found.
26
+ PuppetLint.new_check(:trailing_whitespace) do
27
+ def check
28
+ tokens.select { |token|
29
+ [:WHITESPACE, :INDENT].include?(token.type)
30
+ }.select { |token|
31
+ token.next_token.nil? || token.next_token.type == :NEWLINE
32
+ }.each do |token|
33
+ notify :error, {
34
+ :message => 'trailing whitespace found',
35
+ :line => token.line,
36
+ :column => token.column,
37
+ :token => token,
38
+ }
39
+ end
40
+ end
41
+
42
+ def fix(problem)
43
+ prev_token = problem[:token].prev_token
44
+ next_token = problem[:token].next_token
45
+ prev_token.next_token = next_token
46
+ next_token.prev_token = prev_token unless next_token.nil?
47
+ tokens.delete(problem[:token])
48
+ end
49
+ end
50
+
51
+ # Public: Test the raw manifest string for lines containing more than 80
52
+ # characters and record a warning for each instance found. The only exceptions
53
+ # to this rule are lines containing URLs and template() calls which would hurt
54
+ # readability if split.
55
+ PuppetLint.new_check(:'80chars') do
56
+ def check
57
+ manifest_lines.each_with_index do |line, idx|
58
+ unless line =~ /:\/\// || line =~ /template\(/
59
+ if line.scan(/./mu).size > 80
60
+ notify :warning, {
61
+ :message => 'line has more than 80 characters',
62
+ :line => idx + 1,
63
+ :column => 80,
64
+ }
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ # Public: Check the manifest tokens for any indentation not using 2 space soft
72
+ # tabs and record an error for each instance found.
73
+ PuppetLint.new_check(:'2sp_soft_tabs') do
74
+ def check
75
+ tokens.select { |r|
76
+ r.type == :INDENT
77
+ }.reject { |r|
78
+ r.value.length % 2 == 0
79
+ }.each do |token|
80
+ notify :error, {
81
+ :message => 'two-space soft tabs not used',
82
+ :line => token.line,
83
+ :column => token.column,
84
+ }
85
+ end
86
+ end
87
+ end
88
+
89
+ # Public: Check the manifest tokens for any arrows (=>) in a grouping ({}) that
90
+ # are not aligned with other arrows in that grouping.
91
+ PuppetLint.new_check(:arrow_alignment) do
92
+ COMMENT_TYPES = Set[:COMMENT, :SLASH_COMMENT, :MLCOMMENT]
93
+
94
+ def check
95
+ resource_indexes.each do |res_idx|
96
+ indent_depth = [0]
97
+ indent_depth_idx = 0
98
+ level_tokens = []
99
+ resource_tokens = res_idx[:tokens]
100
+ resource_tokens.reject! do |token|
101
+ COMMENT_TYPES.include? token.type
102
+ end
103
+
104
+ # If this is a single line resource, skip it
105
+ first_arrow = resource_tokens.index { |r| r.type == :FARROW }
106
+ last_arrow = resource_tokens.rindex { |r| r.type == :FARROW }
107
+ next if first_arrow.nil?
108
+ next if last_arrow.nil?
109
+ next unless resource_tokens[first_arrow..last_arrow].any? { |r| r.type == :NEWLINE }
110
+
111
+ resource_tokens.each_with_index do |token, idx|
112
+ if token.type == :FARROW
113
+ (level_tokens[indent_depth_idx] ||= []) << token
114
+ prev_indent_token = resource_tokens[0..idx].rindex { |t| t.type == :INDENT }
115
+ indent_token_length = prev_indent_token.nil? ? 0 : resource_tokens[prev_indent_token].to_manifest.length
116
+ indent_length = indent_token_length + token.prev_code_token.to_manifest.length + 2
117
+
118
+ if indent_depth[indent_depth_idx] < indent_length
119
+ indent_depth[indent_depth_idx] = indent_length
120
+ end
121
+
122
+ elsif token.type == :LBRACE
123
+ indent_depth_idx += 1
124
+ indent_depth << 0
125
+ level_tokens[indent_depth_idx] ||= []
126
+ elsif token.type == :RBRACE
127
+ level_tokens[indent_depth_idx].each do |arrow_tok|
128
+ unless arrow_tok.column == indent_depth[indent_depth_idx] || level_tokens[indent_depth_idx].size == 1
129
+ arrows_on_line = level_tokens[indent_depth_idx].select { |t| t.line == arrow_tok.line }
130
+ notify :warning, {
131
+ :message => 'indentation of => is not properly aligned',
132
+ :line => arrow_tok.line,
133
+ :column => arrow_tok.column,
134
+ :token => arrow_tok,
135
+ :indent_depth => indent_depth[indent_depth_idx],
136
+ :newline => !(arrows_on_line.index(arrow_tok) == 0),
137
+ :newline_indent => arrows_on_line.first.prev_code_token.prev_token.value,
138
+ }
139
+ end
140
+ end
141
+ indent_depth[indent_depth_idx] = 0
142
+ level_tokens[indent_depth_idx].clear
143
+ indent_depth_idx -= 1
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ def fix(problem)
150
+ new_ws_len = (problem[:indent_depth] - (problem[:newline_indent].length + problem[:token].prev_code_token.to_manifest.length + 1))
151
+ new_ws = ' ' * new_ws_len
152
+ if problem[:newline]
153
+ index = tokens.index(problem[:token].prev_code_token.prev_token)
154
+
155
+ #insert newline
156
+ tokens.insert(index, PuppetLint::Lexer::Token.new(:NEWLINE, "\n", 0, 0))
157
+
158
+ # indent the parameter to the correct depth
159
+ problem[:token].prev_code_token.prev_token.type = :INDENT
160
+ problem[:token].prev_code_token.prev_token.value = problem[:newline_indent].dup
161
+ end
162
+
163
+ if problem[:token].prev_token.type == :WHITESPACE
164
+ problem[:token].prev_token.value = new_ws
165
+ else
166
+ index = tokens.index(problem[:token].prev_token)
167
+ tokens.insert(index + 1, PuppetLint::Lexer::Token.new(:WHITESPACE, new_ws, 0, 0))
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,91 @@
1
+ require 'puppet-lint'
2
+ require 'puppet-lint/optparser'
3
+ require 'rake'
4
+ require 'rake/tasklib'
5
+
6
+ class PuppetLint
7
+ # Public: A Rake task that can be loaded and used with everything you need.
8
+ #
9
+ # Examples
10
+ #
11
+ # require 'puppet-lint'
12
+ # PuppetLint::RakeTask.new
13
+ class RakeTask < ::Rake::TaskLib
14
+ include ::Rake::DSL if defined?(::Rake::DSL)
15
+
16
+ DEFAULT_PATTERN = '**/*.pp'
17
+
18
+ attr_accessor :name
19
+ attr_accessor :pattern
20
+ attr_accessor :ignore_paths
21
+ attr_accessor :with_filename
22
+ attr_accessor :disable_checks
23
+ attr_accessor :fail_on_warnings
24
+ attr_accessor :error_level
25
+ attr_accessor :log_format
26
+ attr_accessor :with_context
27
+ attr_accessor :fix
28
+ attr_accessor :show_ignored
29
+ attr_accessor :relative
30
+
31
+ # Public: Initialise a new PuppetLint::RakeTask.
32
+ #
33
+ # args - Not used.
34
+ #
35
+ # Example
36
+ #
37
+ # PuppetLint::RakeTask.new
38
+ def initialize(*args, &task_block)
39
+ @name = args.shift || :lint
40
+ @pattern = DEFAULT_PATTERN
41
+ @with_filename = true
42
+ @disable_checks = []
43
+ @ignore_paths = []
44
+
45
+ define(args, &task_block)
46
+ end
47
+
48
+ def define(args, &task_block)
49
+ desc 'Run puppet-lint'
50
+
51
+ task_block.call(*[self, args].slice(0, task_block.arity)) if task_block
52
+
53
+ # clear any (auto-)pre-existing task
54
+ Rake::Task[@name].clear if Rake::Task.task_defined?(@name)
55
+ task @name do
56
+ PuppetLint::OptParser.build
57
+
58
+ Array(@disable_checks).each do |check|
59
+ PuppetLint.configuration.send("disable_#{check}")
60
+ end
61
+
62
+ %w{with_filename fail_on_warnings error_level log_format with_context fix show_ignored relative}.each do |config|
63
+ value = instance_variable_get("@#{config}")
64
+ PuppetLint.configuration.send("#{config}=".to_sym, value) unless value.nil?
65
+ end
66
+
67
+ if PuppetLint.configuration.ignore_paths
68
+ @ignore_paths = PuppetLint.configuration.ignore_paths
69
+ end
70
+
71
+ RakeFileUtils.send(:verbose, true) do
72
+ linter = PuppetLint.new
73
+ matched_files = FileList[@pattern]
74
+
75
+ matched_files = matched_files.exclude(*@ignore_paths)
76
+
77
+ matched_files.to_a.each do |puppet_file|
78
+ linter.file = puppet_file
79
+ linter.run
80
+ linter.print_problems
81
+ end
82
+ abort if linter.errors? || (
83
+ linter.warnings? && PuppetLint.configuration.fail_on_warnings
84
+ )
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ PuppetLint::RakeTask.new
@@ -0,0 +1,3 @@
1
+ class PuppetLint
2
+ VERSION = '1.2.0'
3
+ end
@@ -0,0 +1,24 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require 'puppet-lint/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'halyard-puppet-lint'
6
+ s.version = PuppetLint::VERSION
7
+ s.homepage = 'https://github.com/rodjek/puppet-lint/'
8
+ s.summary = 'Ensure your Puppet manifests conform with the Puppetlabs style guide'
9
+ s.description = 'Checks your Puppet manifests against the Puppetlabs
10
+ style guide and alerts you to any discrepancies.'
11
+
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
15
+ s.require_paths = ["lib"]
16
+
17
+ s.add_development_dependency 'rake', '~> 10.0'
18
+ s.add_development_dependency 'rspec', '~> 3.0'
19
+ s.add_development_dependency 'rspec-its', '~> 1.0'
20
+ s.add_development_dependency 'rspec-collection_matchers', '~> 1.0'
21
+
22
+ s.authors = ['Tim Sharpe']
23
+ s.email = 'tim@sharpe.id.au'
24
+ end
@@ -0,0 +1,2 @@
1
+ # foo
2
+ class test::foo { }
@@ -0,0 +1 @@
1
+ "test" # lint:ignore:double_quoted_strings
@@ -0,0 +1,6 @@
1
+ # lint:ignore:double_quoted_strings lint:ignore:quoted_booleans
2
+ "true"
3
+ "false"
4
+ # lint:endignore
5
+
6
+ "true"
@@ -0,0 +1,2 @@
1
+ "true" # lint:ignore:double_quoted_strings lint:ignore:quoted_booleans
2
+ "false" # lint:ignore:quoted_booleans lint:ignore:double_quoted_strings reason
@@ -0,0 +1 @@
1
+ "test" # lint:ignore:double_quoted_strings for a good reason
@@ -0,0 +1,3 @@
1
+ # foo
2
+ class test {
3
+ }
@@ -0,0 +1 @@
1
+ class { 'apacheds': master => true' }
@@ -0,0 +1,12 @@
1
+ file { 'test1':
2
+ source => 'puppet:///foo'
3
+ }
4
+ file { 'test2':
5
+ source => "puppet:///foo/${::fqdn}"
6
+ }
7
+ file { 'test3':
8
+ source => "puppet:///${::fqdn}/foo"
9
+ }
10
+ file { 'test4':
11
+ source => "puppet:///foo/${::fqdn}/bar"
12
+ }
@@ -0,0 +1,2 @@
1
+ # foo
2
+ define test::warning($foo='bar', $baz) { }
@@ -0,0 +1,326 @@
1
+ require 'spec_helper'
2
+ require 'rspec/mocks'
3
+ require 'optparse'
4
+
5
+ class CommandRun
6
+ attr_accessor :stdout, :stderr, :exitstatus
7
+
8
+ def initialize(args)
9
+ out = StringIO.new
10
+ err = StringIO.new
11
+
12
+ $stdout = out
13
+ $stderr = err
14
+
15
+ PuppetLint.configuration.defaults
16
+ @exitstatus = PuppetLint::Bin.new(args).run
17
+ PuppetLint.configuration.defaults
18
+
19
+ @stdout = out.string.strip
20
+ @stderr = err.string.strip
21
+
22
+ $stdout = STDOUT
23
+ $stderr = STDERR
24
+ end
25
+ end
26
+
27
+ describe PuppetLint::Bin do
28
+ subject do
29
+ if args.is_a? Array
30
+ sane_args = args
31
+ else
32
+ sane_args = [args]
33
+ end
34
+
35
+ CommandRun.new(sane_args)
36
+ end
37
+
38
+ context 'when running normally' do
39
+ let(:args) { 'spec/fixtures/test/manifests/init.pp' }
40
+
41
+ its(:exitstatus) { is_expected.to eq(0) }
42
+ end
43
+
44
+ context 'when running without arguments' do
45
+ let(:args) { [] }
46
+
47
+ its(:exitstatus) { is_expected.to eq(1) }
48
+ end
49
+
50
+ context 'when asked to display version' do
51
+ let(:args) { '--version' }
52
+
53
+ its(:exitstatus) { is_expected.to eq(0) }
54
+ its(:stdout) { is_expected.to eq("puppet-lint #{PuppetLint::VERSION}") }
55
+ end
56
+
57
+ context 'when passed multiple files' do
58
+ let(:args) { [
59
+ 'spec/fixtures/test/manifests/warning.pp',
60
+ 'spec/fixtures/test/manifests/fail.pp',
61
+ ] }
62
+
63
+ its(:exitstatus) { is_expected.to eq(1) }
64
+ its(:stdout) { is_expected.to eq([
65
+ "#{args[0]} - WARNING: optional parameter listed before required parameter on line 2",
66
+ "#{args[1]} - ERROR: test::foo not in autoload module layout on line 2",
67
+ ].join("\n")) }
68
+ end
69
+
70
+ context 'when passed a malformed file' do
71
+ let(:args) { 'spec/fixtures/test/manifests/malformed.pp' }
72
+
73
+ its(:exitstatus) { is_expected.to eq(1) }
74
+ its(:stdout) { is_expected.to eq('ERROR: Syntax error (try running `puppet parser validate <file>`) on line 1') }
75
+ end
76
+
77
+ context 'when limited to errors only' do
78
+ let(:args) { [
79
+ '--error-level', 'error',
80
+ 'spec/fixtures/test/manifests/warning.pp',
81
+ 'spec/fixtures/test/manifests/fail.pp',
82
+ ] }
83
+
84
+ its(:exitstatus) { is_expected.to eq(1) }
85
+ its(:stdout) { is_expected.to match(/^#{args.last} - ERROR/) }
86
+ end
87
+
88
+ context 'when limited to warnings only' do
89
+ let(:args) { [
90
+ '--error-level', 'warning',
91
+ 'spec/fixtures/test/manifests/warning.pp',
92
+ 'spec/fixtures/test/manifests/fail.pp',
93
+ ] }
94
+
95
+ its(:exitstatus) { is_expected.to eq(1) }
96
+ its(:stdout) { is_expected.to match(/WARNING/) }
97
+ its(:stdout) { is_expected.to_not match(/ERROR/) }
98
+ end
99
+
100
+ context 'when specifying a specific check to run' do
101
+ let(:args) { [
102
+ '--only-check', 'parameter_order',
103
+ 'spec/fixtures/test/manifests/warning.pp',
104
+ 'spec/fixtures/test/manifests/fail.pp',
105
+ ] }
106
+
107
+ its(:exitstatus) { is_expected.to eq(0) }
108
+ its(:stdout) { is_expected.to_not match(/ERROR/) }
109
+ its(:stdout) { is_expected.to match(/WARNING/) }
110
+ end
111
+
112
+ context 'when asked to display filenames ' do
113
+ let(:args) { ['--with-filename', 'spec/fixtures/test/manifests/fail.pp'] }
114
+
115
+ its(:exitstatus) { is_expected.to eq(1) }
116
+ its(:stdout) { is_expected.to match(%r{^spec/fixtures/test/manifests/fail\.pp -}) }
117
+ end
118
+
119
+ context 'when not asked to fail on warnings' do
120
+ let(:args) { ['spec/fixtures/test/manifests/warning.pp'] }
121
+
122
+ its(:exitstatus) { is_expected.to eq(0) }
123
+ its(:stdout) { is_expected.to match(/optional parameter/) }
124
+ end
125
+
126
+ context 'when asked to provide context to problems' do
127
+ let(:args) { [
128
+ '--with-context',
129
+ 'spec/fixtures/test/manifests/warning.pp',
130
+ ] }
131
+
132
+ its(:exitstatus) { is_expected.to eq(0) }
133
+ its(:stdout) { is_expected.to eq([
134
+ 'WARNING: optional parameter listed before required parameter on line 2',
135
+ '',
136
+ " define test::warning($foo='bar', $baz) { }",
137
+ ' ^',
138
+ ].join("\n"))
139
+ }
140
+ end
141
+
142
+ context 'when asked to fail on warnings' do
143
+ let(:args) { [
144
+ '--fail-on-warnings',
145
+ 'spec/fixtures/test/manifests/warning.pp',
146
+ ] }
147
+
148
+ its(:exitstatus) { is_expected.to eq(1) }
149
+ its(:stdout) { is_expected.to match(/optional parameter/) }
150
+ end
151
+
152
+ context 'when used with an invalid option' do
153
+ let(:args) { '--foo-bar-baz' }
154
+
155
+ its(:exitstatus) { is_expected.to eq(1) }
156
+ its(:stdout) { is_expected.to match(/invalid option/) }
157
+ end
158
+
159
+ context 'when passed a file that does not exist' do
160
+ let(:args) { 'spec/fixtures/test/manifests/enoent.pp' }
161
+
162
+ its(:exitstatus) { is_expected.to eq(1) }
163
+ its(:stdout) { is_expected.to match(/specified file does not exist/) }
164
+ end
165
+
166
+ context 'when passed a directory' do
167
+ let(:args) { 'spec/fixtures/' }
168
+
169
+ its(:exitstatus) { is_expected.to eq(1) }
170
+ its(:stdout) { is_expected.to match(/ERROR/) }
171
+ end
172
+
173
+ context 'when disabling a check' do
174
+ let(:args) { [
175
+ '--no-autoloader_layout',
176
+ 'spec/fixtures/test/manifests/fail.pp'
177
+ ] }
178
+
179
+ its(:exitstatus) { is_expected.to eq(0) }
180
+ its(:stdout) { is_expected.to eq("") }
181
+ end
182
+
183
+ context 'when changing the log format' do
184
+ context 'to print %{filename}' do
185
+ let(:args) { [
186
+ '--log-format', '%{filename}',
187
+ 'spec/fixtures/test/manifests/fail.pp'
188
+ ] }
189
+
190
+ its(:exitstatus) { is_expected.to eq(1) }
191
+ its(:stdout) { is_expected.to eq('fail.pp') }
192
+ end
193
+
194
+ context 'to print %{path}' do
195
+ let(:args) { [
196
+ '--log-format', '%{path}',
197
+ 'spec/fixtures/test/manifests/fail.pp'
198
+ ] }
199
+
200
+ its(:exitstatus) { is_expected.to eq(1) }
201
+ its(:stdout) { is_expected.to eq('spec/fixtures/test/manifests/fail.pp') }
202
+ end
203
+
204
+ context 'to print %{fullpath}' do
205
+ let(:args) { [
206
+ '--log-format', '%{fullpath}',
207
+ 'spec/fixtures/test/manifests/fail.pp'
208
+ ] }
209
+
210
+ its(:exitstatus) { is_expected.to eq(1) }
211
+ its(:stdout) {
212
+ is_expected.to match(%r{^/.+/spec/fixtures/test/manifests/fail\.pp$})
213
+ }
214
+ end
215
+
216
+ context 'to print %{linenumber}' do
217
+ let(:args) { [
218
+ '--log-format', '%{linenumber}',
219
+ 'spec/fixtures/test/manifests/fail.pp'
220
+ ] }
221
+
222
+ its(:exitstatus) { is_expected.to eq(1) }
223
+ its(:stdout) { is_expected.to eq('2') }
224
+ its(:stderr) { is_expected.to eq('DEPRECATION: Please use %{line} instead of %{linenumber}') }
225
+ end
226
+
227
+ context 'to print %{line}' do
228
+ let(:args) { [
229
+ '--log-format', '%{line}',
230
+ 'spec/fixtures/test/manifests/fail.pp'
231
+ ] }
232
+
233
+ its(:exitstatus) { is_expected.to eq(1) }
234
+ its(:stdout) { is_expected.to eq('2') }
235
+ end
236
+
237
+ context 'to print %{kind}' do
238
+ let(:args) { [
239
+ '--log-format', '%{kind}',
240
+ 'spec/fixtures/test/manifests/fail.pp'
241
+ ] }
242
+
243
+ its(:exitstatus) { is_expected.to eq(1) }
244
+ its(:stdout) { is_expected.to eq('error') }
245
+ end
246
+
247
+ context 'to print %{KIND}' do
248
+ let(:args) { [
249
+ '--log-format', '%{KIND}',
250
+ 'spec/fixtures/test/manifests/fail.pp'
251
+ ] }
252
+
253
+ its(:exitstatus) { is_expected.to eq(1) }
254
+ its(:stdout) { is_expected.to eq('ERROR') }
255
+ end
256
+
257
+ context 'to print %{check}' do
258
+ let(:args) { [
259
+ '--log-format', '%{check}',
260
+ 'spec/fixtures/test/manifests/fail.pp'
261
+ ] }
262
+
263
+ its(:exitstatus) { is_expected.to eq(1) }
264
+ its(:stdout) { is_expected.to eq('autoloader_layout') }
265
+ end
266
+
267
+ context 'to print %{message}' do
268
+ let(:args) { [
269
+ '--log-format', '%{message}',
270
+ 'spec/fixtures/test/manifests/fail.pp'
271
+ ] }
272
+
273
+ its(:exitstatus) { is_expected.to eq(1) }
274
+ its(:stdout) { is_expected.to eq('test::foo not in autoload module layout') }
275
+ end
276
+ end
277
+
278
+ context 'when hiding ignored problems' do
279
+ let(:args) { [
280
+ 'spec/fixtures/test/manifests/ignore.pp'
281
+ ] }
282
+
283
+ its(:exitstatus) { is_expected.to eq(0) }
284
+ its(:stdout) { is_expected.to_not match(/IGNORED/) }
285
+ end
286
+
287
+ context 'when showing ignored problems' do
288
+ let(:args) { [
289
+ '--show-ignored',
290
+ 'spec/fixtures/test/manifests/ignore.pp',
291
+ ] }
292
+
293
+ its(:exitstatus) { is_expected.to eq(0) }
294
+ its(:stdout) { is_expected.to match(/IGNORED/) }
295
+ end
296
+
297
+ context 'when showing ignored problems with a reason' do
298
+ let(:args) { [
299
+ '--show-ignored',
300
+ 'spec/fixtures/test/manifests/ignore_reason.pp',
301
+ ] }
302
+
303
+ its(:exitstatus) { is_expected.to eq(0) }
304
+ its(:stdout) { is_expected.to eq([
305
+ "IGNORED: double quoted string containing no variables on line 1",
306
+ " for a good reason",
307
+ ].join("\n")) }
308
+ end
309
+
310
+ context 'ignoring multiple checks on a line' do
311
+ let(:args) { [
312
+ 'spec/fixtures/test/manifests/ignore_multiple_line.pp',
313
+ ] }
314
+
315
+ its(:exitstatus) { is_expected.to eq(0) }
316
+ end
317
+
318
+ context 'ignoring multiple checks in a block' do
319
+ let(:args) { [
320
+ 'spec/fixtures/test/manifests/ignore_multiple_block.pp',
321
+ ] }
322
+
323
+ its(:exitstatus) { is_expected.to eq(0) }
324
+ its(:stdout) { is_expected.to match(/^.*line 6$/) }
325
+ end
326
+ end