puppet-lint 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,50 +1,47 @@
1
1
  class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
2
- def test(path, data)
3
- lexer = Puppet::Parser::Lexer.new
4
- lexer.string = data
5
- tokens = lexer.fullscan
6
-
2
+ check 'right_to_left_relationship' do
7
3
  tokens.select { |r| r.first == :OUT_EDGE }.each do |token|
8
- warn "right-to-left (<-) relationship on line #{token.last[:line]}"
4
+ notify :warning, :message => "right-to-left (<-) relationship", :linenumber => token.last[:line]
9
5
  end
6
+ end
10
7
 
11
- class_indexes = []
12
- defined_type_indexes = []
13
- tokens.each_index do |token_idx|
14
- if [:DEFINE, :CLASS].include? tokens[token_idx].first
15
- header_end_idx = tokens[token_idx..-1].index { |r| r.first == :LBRACE }
16
- lparen_idx = tokens[token_idx..(header_end_idx + token_idx)].index { |r| r.first == :LPAREN }
17
- rparen_idx = tokens[token_idx..(header_end_idx + token_idx)].rindex { |r| r.first == :RPAREN }
18
-
19
- unless path == ""
20
- title_token = tokens[token_idx+1]
21
- if [:CLASSNAME, :NAME].include? title_token.first
22
- split_title = title_token.last[:value].split('::')
23
- if split_title.length > 1
24
- expected_path = "#{split_title.first}/manifests/#{split_title[1..-1].join('/')}.pp"
25
- else
26
- expected_path = "#{title_token.last[:value]}/manifests/init.pp"
27
- end
8
+ check 'autoloader_layout' do
9
+ unless path == ""
10
+ (class_indexes + defined_type_indexes).each do |class_idx|
11
+ title_token = tokens[class_idx[:start]+1]
12
+ split_title = title_token.last[:value].split('::')
13
+ if split_title.length > 1
14
+ expected_path = "#{split_title.first}/manifests/#{split_title[1..-1].join('/')}.pp"
15
+ else
16
+ expected_path = "#{title_token.last[:value]}/manifests/init.pp"
17
+ end
28
18
 
29
- unless path.end_with? expected_path
30
- error "#{title_token.last[:value]} not in autoload module layout on line #{title_token.last[:line]}"
31
- end
32
- end
19
+ unless path.end_with? expected_path
20
+ notify :error, :message => "#{title_token.last[:value]} not in autoload module layout", :linenumber => title_token.last[:line]
33
21
  end
22
+ end
23
+ end
24
+ end
25
+
26
+ check 'parameter_order' do
27
+ (class_indexes + defined_type_indexes).each do |class_idx|
28
+ token_idx = class_idx[:start]
29
+ header_end_idx = tokens[token_idx..-1].index { |r| r.first == :LBRACE }
30
+ lparen_idx = tokens[token_idx..(header_end_idx + token_idx)].index { |r| r.first == :LPAREN }
31
+ rparen_idx = tokens[token_idx..(header_end_idx + token_idx)].rindex { |r| r.first == :RPAREN }
34
32
 
35
- unless lparen_idx.nil? or rparen_idx.nil?
36
- param_tokens = tokens[lparen_idx..rparen_idx]
37
- param_tokens.each_index do |param_tokens_idx|
38
- this_token = param_tokens[param_tokens_idx]
39
- next_token = param_tokens[param_tokens_idx+1]
40
- prev_token = param_tokens[param_tokens_idx-1]
41
- if this_token.first == :VARIABLE
42
- unless next_token.nil?
43
- if next_token.first == :COMMA or next_token.first == :RPAREN
44
- unless param_tokens[0..param_tokens_idx].rindex { |r| r.first == :EQUALS }.nil?
45
- unless prev_token.nil? or prev_token.first == :EQUALS
46
- warn "optional parameter listed before required parameter on line #{this_token.last[:line]}"
47
- end
33
+ unless lparen_idx.nil? or rparen_idx.nil?
34
+ param_tokens = tokens[lparen_idx..rparen_idx]
35
+ param_tokens.each_index do |param_tokens_idx|
36
+ this_token = param_tokens[param_tokens_idx]
37
+ next_token = param_tokens[param_tokens_idx+1]
38
+ prev_token = param_tokens[param_tokens_idx-1]
39
+ if this_token.first == :VARIABLE
40
+ unless next_token.nil?
41
+ if next_token.first == :COMMA or next_token.first == :RPAREN
42
+ unless param_tokens[0..param_tokens_idx].rindex { |r| r.first == :EQUALS }.nil?
43
+ unless prev_token.nil? or prev_token.first == :EQUALS
44
+ notify :warning, :message => "optional parameter listed before required parameter", :linenumber => this_token.last[:line]
48
45
  end
49
46
  end
50
47
  end
@@ -52,36 +49,24 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
52
49
  end
53
50
  end
54
51
  end
52
+ end
53
+ end
55
54
 
56
- if [:CLASS, :DEFINE].include? tokens[token_idx].first
57
- if tokens[token_idx].first == :CLASS
58
- if tokens[token_idx+2].first == :INHERITS
59
- class_name = tokens[token_idx+1].last[:value]
60
- inherited_class = tokens[token_idx+3].last[:value]
61
-
62
- unless class_name =~ /^#{inherited_class}::/
63
- warn "class inherits across namespaces on line #{tokens[token_idx].last[:line]}"
64
- end
65
- end
66
- end
55
+ check 'inherits_across_namespaces' do
56
+ class_indexes.each do |class_idx|
57
+ token_idx = class_idx[:start]
58
+ if tokens[token_idx+2].first == :INHERITS
59
+ class_name = tokens[token_idx+1].last[:value]
60
+ inherited_class = tokens[token_idx+3].last[:value]
67
61
 
68
- lbrace_count = 0
69
- tokens[token_idx+1..-1].each_index do |class_token_idx|
70
- idx = class_token_idx + token_idx
71
- if tokens[idx].first == :LBRACE
72
- lbrace_count += 1
73
- elsif tokens[idx].first == :RBRACE
74
- lbrace_count -= 1
75
- if lbrace_count == 0
76
- class_indexes << {:start => token_idx, :end => idx} if tokens[token_idx].first == :CLASS
77
- defined_type_indexes << {:start => token_idx, :end => idx} if tokens[token_idx].first == :DEFINE
78
- break
79
- end
80
- end
62
+ unless class_name =~ /^#{inherited_class}::/
63
+ notify :warning, :message => "class inherits across namespaces", :linenumber => tokens[token_idx].last[:line]
81
64
  end
82
65
  end
83
66
  end
67
+ end
84
68
 
69
+ check 'nested_classes_or_defines' do
85
70
  class_indexes.each do |class_idx|
86
71
  class_tokens = tokens[class_idx[:start]..class_idx[:end]]
87
72
  class_tokens[1..-1].each_index do |token_idx|
@@ -90,19 +75,21 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
90
75
 
91
76
  if token.first == :CLASS
92
77
  if next_token.first != :LBRACE
93
- warn "class defined inside a class on line #{token.last[:line]}"
78
+ notify :warning, :message => "class defined inside a class", :linenumber => token.last[:line]
94
79
  end
95
80
  end
96
81
 
97
82
  if token.first == :DEFINE
98
- warn "define defined inside a class on line #{token.last[:line]}"
83
+ notify :warning, :message => "define defined inside a class", :linenumber => token.last[:line]
99
84
  end
100
85
  end
101
86
  end
87
+ end
102
88
 
89
+ check 'variable_scope' do
103
90
  (class_indexes + defined_type_indexes).each do |idx|
104
91
  object_tokens = tokens[idx[:start]..idx[:end]]
105
- variables_in_scope = ['name']
92
+ variables_in_scope = ['name', 'title', 'module_name']
106
93
  referenced_variables = []
107
94
  header_end_idx = object_tokens.index { |r| r.first == :LBRACE }
108
95
  lparen_idx = object_tokens[0..header_end_idx].index { |r| r.first == :LPAREN }
@@ -137,7 +124,9 @@ class PuppetLint::Plugins::CheckClasses < PuppetLint::CheckPlugin
137
124
  referenced_variables.each do |token|
138
125
  unless token.last[:value].include? '::'
139
126
  unless variables_in_scope.include? token.last[:value]
140
- warn "top-scope variable being used without an explicit namespace on line #{token.last[:line]}"
127
+ unless token.last[:value] =~ /\d+/
128
+ notify :warning, :message => "top-scope variable being used without an explicit namespace", :linenumber => token.last[:line]
129
+ end
141
130
  end
142
131
  end
143
132
  end
@@ -1,10 +1,23 @@
1
1
  class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
2
- def test(path, data)
3
- lexer = Puppet::Parser::Lexer.new
4
- lexer.string = data
5
- tokens = lexer.fullscan
2
+ check 'selector_inside_resource' do
3
+ resource_indexes.each do |resource|
4
+ resource_tokens = tokens[resource[:start]..resource[:end]]
5
+
6
+ resource_tokens.each_index do |resource_token_idx|
7
+ if resource_tokens[resource_token_idx].first == :FARROW
8
+ if resource_tokens[resource_token_idx + 1].first == :VARIABLE
9
+ unless resource_tokens[resource_token_idx + 2].nil?
10
+ if resource_tokens[resource_token_idx + 2].first == :QMARK
11
+ notify :warning, :message => "selector inside resource block", :linenumber => resource_tokens[resource_token_idx].last[:line]
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
6
19
 
7
- resource_indexes = []
20
+ check 'case_without_default' do
8
21
  case_indexes = []
9
22
 
10
23
  tokens.each_index do |token_idx|
@@ -32,27 +45,11 @@ class PuppetLint::Plugins::CheckConditionals < PuppetLint::CheckPlugin
32
45
  end
33
46
  end
34
47
 
35
- resource_indexes.each do |resource|
36
- resource_tokens = tokens[resource[:start]..resource[:end]]
37
-
38
- resource_tokens.each_index do |resource_token_idx|
39
- if resource_tokens[resource_token_idx].first == :FARROW
40
- if resource_tokens[resource_token_idx + 1].first == :VARIABLE
41
- unless resource_tokens[resource_token_idx + 2].nil?
42
- if resource_tokens[resource_token_idx + 2].first == :QMARK
43
- warn "selector inside resource block on line #{resource_tokens[resource_token_idx].last[:line]}"
44
- end
45
- end
46
- end
47
- end
48
- end
49
- end
50
-
51
48
  case_indexes.each do |kase|
52
49
  case_tokens = tokens[kase[:start]..kase[:end]]
53
50
 
54
51
  unless case_tokens.index { |r| r.first == :DEFAULT }
55
- warn "case statement without a default case on line #{case_tokens.first.last[:line]}"
52
+ notify :warning, :message => "case statement without a default case", :linenumber => case_tokens.first.last[:line]
56
53
  end
57
54
  end
58
55
  end
@@ -2,48 +2,30 @@
2
2
  # http://docs.puppetlabs.com/guides/style_guide.html#resources
3
3
 
4
4
  class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
5
- def test(path, data)
6
- lexer = Puppet::Parser::Lexer.new
7
- lexer.string = data
8
- tokens = lexer.fullscan
9
-
10
- title_tokens = []
11
- resource_indexes = []
12
- tokens.each_index do |token_idx|
13
- if tokens[token_idx].first == :COLON
14
- # gather a list of tokens that are resource titles
15
- if tokens[token_idx-1].first == :RBRACK
16
- title_array_tokens = tokens[tokens.rindex { |r| r.first == :LBRACK }+1..token_idx-2]
17
- title_tokens += title_array_tokens.select { |token| [:STRING, :NAME].include? token.first }
18
- else
19
- if tokens[token_idx + 1].first != :LBRACE
20
- title_tokens << tokens[token_idx-1]
21
- end
22
- end
23
-
24
- # gather a list of start and end indexes for resource attribute blocks
25
- if tokens[token_idx+1].first != :LBRACE
26
- resource_indexes << {:start => token_idx+1, :end => tokens[token_idx+1..-1].index { |r| [:SEMIC, :RBRACE].include? r.first }+token_idx}
27
- end
28
- end
29
- end
30
-
5
+ check 'unquoted_resource_title' do
31
6
  title_tokens.each do |token|
32
7
  if token.first == :NAME
33
- warn "unquoted resource title on line #{token.last[:line]}"
8
+ notify :warning, :message => "unquoted resource title", :linenumber => token.last[:line]
34
9
  end
35
10
  end
11
+ end
36
12
 
13
+ check 'ensure_first_param' do
37
14
  resource_indexes.each do |resource|
38
15
  resource_tokens = tokens[resource[:start]..resource[:end]]
39
16
  ensure_attr_index = resource_tokens.index { |token| token.first == :NAME and token.last[:value] == 'ensure' }
40
17
  unless ensure_attr_index.nil?
41
18
  if ensure_attr_index > 1
42
19
  ensure_attr_line_no = resource_tokens[ensure_attr_index].last[:line]
43
- warn "ensure found on line #{ensure_attr_line_no} but it's not the first attribute"
20
+ notify :warning, :message => "ensure found on line but it's not the first attribute", :linenumber => ensure_attr_line_no
44
21
  end
45
22
  end
23
+ end
24
+ end
46
25
 
26
+ check 'unquoted_file_mode' do
27
+ resource_indexes.each do |resource|
28
+ resource_tokens = tokens[resource[:start]..resource[:end]]
47
29
  resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
48
30
  if resource_type_token.last[:value] == "file"
49
31
  resource_tokens.each_index do |resource_token_idx|
@@ -51,15 +33,43 @@ class PuppetLint::Plugins::CheckResources < PuppetLint::CheckPlugin
51
33
  if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
52
34
  value_token = resource_tokens[resource_token_idx + 2]
53
35
  if value_token.first == :NAME
54
- warn "unquoted file mode on line #{value_token.last[:line]}"
36
+ notify :warning, :message => "unquoted file mode", :linenumber => value_token.last[:line]
55
37
  end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ check '4digit_file_mode' do
45
+ resource_indexes.each do |resource|
46
+ resource_tokens = tokens[resource[:start]..resource[:end]]
47
+ resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
48
+ if resource_type_token.last[:value] == "file"
49
+ resource_tokens.each_index do |resource_token_idx|
50
+ attr_token = resource_tokens[resource_token_idx]
51
+ if attr_token.first == :NAME and attr_token.last[:value] == 'mode'
52
+ value_token = resource_tokens[resource_token_idx + 2]
56
53
  if value_token.last[:value] !~ /\d{4}/ and value_token.first != :VARIABLE
57
- warn "mode should be represented as a 4 digit octal value on line #{value_token.last[:line]}"
54
+ notify :warning, :message => "mode should be represented as a 4 digit octal value", :linenumber => value_token.last[:line]
58
55
  end
59
- elsif attr_token.first == :NAME and attr_token.last[:value] == 'ensure'
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ check 'ensure_not_symlink_target' do
63
+ resource_indexes.each do |resource|
64
+ resource_tokens = tokens[resource[:start]..resource[:end]]
65
+ resource_type_token = tokens[tokens[0..resource[:start]].rindex { |r| r.first == :LBRACE } - 1]
66
+ if resource_type_token.last[:value] == "file"
67
+ resource_tokens.each_index do |resource_token_idx|
68
+ attr_token = resource_tokens[resource_token_idx]
69
+ if attr_token.first == :NAME and attr_token.last[:value] == 'ensure'
60
70
  value_token = resource_tokens[resource_token_idx + 2]
61
71
  if value_token.last[:value].start_with? '/'
62
- warn "symlink target specified in ensure attr on line #{value_token.last[:line]}"
72
+ notify :warning, :message => "symlink target specified in ensure attr", :linenumber => value_token.last[:line]
63
73
  end
64
74
  end
65
75
  end
@@ -14,27 +14,35 @@ class PuppetLint::Plugins::CheckStrings < PuppetLint::CheckPlugin
14
14
  end
15
15
  end
16
16
 
17
- def test(path, data)
18
- l = Puppet::Parser::Lexer.new
19
- l.string = data
20
- tokens = l.fullscan
21
-
17
+ check 'double_quoted_strings' do
22
18
  tokens.each_index do |token_idx|
23
19
  token = tokens[token_idx]
24
20
 
25
21
  if token.first == :STRING
26
22
  unless token.last[:value].include? "\t" or token.last[:value].include? "\n"
27
- warn "double quoted string containing no variables on line #{token.last[:line]}"
23
+ notify :warning, :message => "double quoted string containing no variables", :linenumber => token.last[:line]
28
24
  end
29
25
  end
26
+ end
27
+ end
28
+
29
+ check 'only_variable_string' do
30
+ tokens.each_index do |token_idx|
31
+ token = tokens[token_idx]
30
32
 
31
33
  if token.first == :DQPRE and token.last[:value] == ""
32
34
  if tokens[token_idx + 1].first == :VARIABLE
33
35
  if tokens[token_idx + 2].first == :DQPOST and tokens[token_idx + 2].last[:value] == ""
34
- warn "string containing only a variable on line #{tokens[token_idx + 1].last[:line]}"
36
+ notify :warning, :message => "string containing only a variable", :linenumber => tokens[token_idx + 1].last[:line]
35
37
  end
36
38
  end
37
39
  end
40
+ end
41
+ end
42
+
43
+ check 'variables_not_enclosed' do
44
+ tokens.each_index do |token_idx|
45
+ token = tokens[token_idx]
38
46
 
39
47
  if token.first == :DQPRE
40
48
  end_of_string_idx = tokens[token_idx..-1].index { |r| r.first == :DQPOST }
@@ -42,31 +50,39 @@ class PuppetLint::Plugins::CheckStrings < PuppetLint::CheckPlugin
42
50
  if t.first == :VARIABLE
43
51
  line = data.split("\n")[t.last[:line] - 1]
44
52
  if line.is_a? String and line.include? "$#{t.last[:value]}"
45
- warn "variable not enclosed in {} on line #{t.last[:line]}"
53
+ notify :warning, :message => "variable not enclosed in {}", :linenumber => t.last[:line]
46
54
  end
47
55
  end
48
56
  end
49
57
  end
58
+ end
59
+ end
50
60
 
51
- if token.first == :DQPRE
52
- end_of_string_idx = tokens[token_idx..-1].index { |r| r.first == :DQPOST }
53
- tokens[token_idx..end_of_string_idx].each do |t|
54
- if t.first == :VARIABLE and t.last[:value].match(/-/)
55
- warn "variable contains a dash on line #{t.last[:line]}"
56
- end
57
- end
58
- end
61
+ check 'single_quote_string_with_variables' do
62
+ tokens.each_index do |token_idx|
63
+ token = tokens[token_idx]
59
64
 
60
65
  if token.first == :SSTRING
61
66
  contents = token.last[:value]
62
67
  line_no = token.last[:line]
63
68
 
64
69
  if contents.include? '${'
65
- error "single quoted string containing a variable found on line #{token.last[:line]}"
70
+ notify :error, :message => "single quoted string containing a variable found", :linenumber => token.last[:line]
66
71
  end
72
+ end
73
+ end
74
+ end
75
+
76
+ check 'quoted_booleans' do
77
+ tokens.each_index do |token_idx|
78
+ token = tokens[token_idx]
79
+
80
+ if token.first == :SSTRING
81
+ contents = token.last[:value]
82
+ line_no = token.last[:line]
67
83
 
68
84
  if ['true', 'false'].include? contents
69
- warn "quoted boolean value found on line #{token.last[:line]}"
85
+ notify :warning, :message => "quoted boolean value found", :linenumber => token.last[:line]
70
86
  end
71
87
  end
72
88
  end
@@ -1,9 +1,5 @@
1
1
  class PuppetLint::Plugins::CheckVariables < PuppetLint::CheckPlugin
2
- def test(path, data)
3
- lexer = Puppet::Parser::Lexer.new
4
- lexer.string = data
5
- tokens = lexer.fullscan
6
-
2
+ check 'variable_contains_dash' do
7
3
  tokens.each_index do |token_idx|
8
4
  token = tokens[token_idx]
9
5
 
@@ -11,7 +7,16 @@ class PuppetLint::Plugins::CheckVariables < PuppetLint::CheckPlugin
11
7
  variable = token.last[:value]
12
8
  line_no = token.last[:line]
13
9
  if variable.match(/-/)
14
- warn "Variable contains a dash on line #{line_no}"
10
+ notify :warning, :message => "variable contains a dash", :linenumber => line_no
11
+ end
12
+ end
13
+
14
+ if token.first == :DQPRE
15
+ end_of_string_idx = tokens[token_idx..-1].index { |r| r.first == :DQPOST }
16
+ tokens[token_idx..end_of_string_idx].each do |t|
17
+ if t.first == :VARIABLE and t.last[:value].match(/-/)
18
+ notify :warning, :message => "variable contains a dash", :linenumber => t.last[:line]
19
+ end
15
20
  end
16
21
  end
17
22
  end