puppet-lint-use_ensure_packages-check 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 429d64b939da27bc66f50a566fd01afbc3a0822a
4
+ data.tar.gz: 7f06639bcb642f4ad70590b2de8d486ce64970cf
5
+ SHA512:
6
+ metadata.gz: 13062a56166ba14cea81eac802baf04104c1af6d8bce6cffb489ef85b89ba3fe06906b01c830df7ad5c880a1c78fa4b8b38b5c2800a4695b83869a05b8bba78b
7
+ data.tar.gz: 06a37b1250c9c3d13570b9bd886698aa475111dc5a5131e2d8d0bb89d6fa19d76b5d53d5b76d1f0fd289781813e6b5c52d7d3ba3db61e5fc7e4e8b0331f993fe
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # puppet-lint use ensure_packages check
2
+
3
+ [![Build Status](https://travis-ci.org/ninech/puppet-lint-use_ensure_packages-check.svg?branch=master)](https://travis-ci.org/ninech/puppet-lint-use_ensure_packages-check)
4
+
5
+ ## Installation
6
+
7
+ To use this plugin, add the following like to the Gemfile in your Puppet code
8
+ base and run `bundle install`.
9
+
10
+ ```ruby
11
+ gem 'puppet-lint-use_ensure_packages-check'
12
+ ```
13
+
14
+ ## Usage
15
+
16
+ This plugin provides a new check to `puppet-lint`.
17
+
18
+ ### use_ensure_packages
19
+
20
+ **--fix support: yes**
21
+
22
+ This check will raise a error for constructs like the following.
23
+
24
+ ```
25
+ if ! defined(Package['foo']) {
26
+ package { 'foo': }
27
+ }
28
+ ```
29
+
30
+ And offer you the option to rewrite it to use ensure_packages with the **--fix**
31
+ option. This would be transformed into the following.
32
+
33
+ ```
34
+ ensure_packages(['foo'])
35
+ ```
@@ -0,0 +1,167 @@
1
+ PuppetLint.new_check(:use_ensure_packages) do
2
+ TYPE_SEQUENCE_START = [
3
+ # if ! defined ( Package[NAME])
4
+ :IF, :NOT, :NAME, :LPAREN, :CLASSREF, :LBRACK, :SSTRING, :RBRACK, :RPAREN,
5
+ # { package {NAME:
6
+ :LBRACE, :NAME, :LBRACE, :SSTRING, :COLON
7
+ ].freeze
8
+ TYPE_SEQUENCE_END = [
9
+ # } }
10
+ :RBRACE, :RBRACE
11
+ ].freeze
12
+ VALUE_SEQUENCE = { 2 => 'defined', 4 => 'Package', 10 => 'package' }.freeze
13
+ NAME_INDEX = 6
14
+
15
+ OPTINAL_CONTENT = [
16
+ { # ensure => installed
17
+ sequence: [:NAME, :FARROW, :NAME],
18
+ values: { 0 => 'ensure', 2 => 'installed' }
19
+ },
20
+ { # ensure => installed;
21
+ sequence: [:NAME, :FARROW, :NAME, :SEMIC],
22
+ values: { 0 => 'ensure', 2 => 'installed' }
23
+ },
24
+ { # ensure => present
25
+ sequence: [:NAME, :FARROW, :NAME],
26
+ values: { 0 => 'ensure', 2 => 'present' }
27
+ },
28
+ { # ensure => present;
29
+ sequence: [:NAME, :FARROW, :NAME, :SEMIC],
30
+ values: { 0 => 'ensure', 2 => 'present' }
31
+ }
32
+ ].freeze
33
+
34
+ FORMATTING_TOKENS = PuppetLint::Lexer::FORMATTING_TOKENS
35
+
36
+ def check
37
+ if_indexes.each do |cond|
38
+ next if check_if(cond)
39
+
40
+ notify :warning,
41
+ message: 'ensure_packages should be used',
42
+ line: cond[:tokens].first.line,
43
+ column: cond[:tokens].first.column
44
+ end
45
+ end
46
+
47
+ def check_if(cond)
48
+ tokens = filter_code_tokens(cond[:tokens])
49
+
50
+ # Test start of patterns
51
+ return true unless match_tokens(tokens, TYPE_SEQUENCE_START, VALUE_SEQUENCE)
52
+
53
+ # Test end of pattern
54
+ return true unless match_tokens(tokens.last(2), TYPE_SEQUENCE_END, {})
55
+
56
+ tokens = tokens.slice(Range.new(TYPE_SEQUENCE_START.size,
57
+ -TYPE_SEQUENCE_END.size - 1))
58
+
59
+ return false if tokens.empty?
60
+
61
+ return true unless OPTINAL_CONTENT.index do |c|
62
+ match_tokens(tokens, c[:sequence], c[:values])
63
+ end
64
+
65
+ false
66
+ end
67
+
68
+ def match_tokens(tokens, type, value)
69
+ tokens.first(type.size).map(&:type) == type &&
70
+ value.values == value.keys.map { |i| tokens[i].value }
71
+ end
72
+
73
+ def fix(problem)
74
+ cond = if_indexes.select do |c|
75
+ c[:tokens].first.line == problem[:line] &&
76
+ c[:tokens].first.column == problem[:column]
77
+ end.first
78
+
79
+ package_name = filter_code_tokens(cond[:tokens])[NAME_INDEX].value
80
+
81
+ remove_tokens(cond[:start], cond[:end])
82
+
83
+ new_tokens = ensure_packages_tokens(package_name)
84
+
85
+ insert_tokens(cond[:start], new_tokens)
86
+
87
+ PuppetLint::Data.tokens = tokens
88
+
89
+ merge_if_possible(cond[:start])
90
+ end
91
+
92
+ def merge_if_possible(idx)
93
+ target = find_function('ensure_packages').keep_if do |func|
94
+ func[:tokens].last.next_code_token == tokens[idx] &&
95
+ func[:tokens].last.next_code_token != func[:tokens].first
96
+ end
97
+
98
+ return if target.empty?
99
+
100
+ # Count non :SSTRING, :COMMA tokens to ensure there are no parameters
101
+ return unless 5 == filter_code_tokens(target.first[:tokens]).count do |t|
102
+ ![:SSTRING, :COMMA].include?(t.type)
103
+ end
104
+
105
+ start_idx = tokens.first(idx).rindex { |t| t.type == :SSTRING } + 1
106
+
107
+ remove_tokens(start_idx, idx + 2)
108
+ insert_tokens(start_idx, [PuppetLint::Lexer::Token.new(:COMMA, ',', 0, 0)])
109
+ end
110
+
111
+ def find_function(name)
112
+ PuppetLint::Data.function_indexes.keep_if do |func|
113
+ func[:tokens].first.type == :NAME &&
114
+ func[:tokens].first.value == name
115
+ end
116
+ end
117
+
118
+ def tokens_idx(obj)
119
+ tokens.index(obj)
120
+ end
121
+
122
+ def remove_tokens(from, to)
123
+ num = to - from + 1
124
+ tokens.slice!(from, num)
125
+ fix_linked_list
126
+ end
127
+
128
+ def insert_tokens(idx, new_tokens)
129
+ tokens.insert(idx, *new_tokens)
130
+ fix_linked_list
131
+ end
132
+
133
+ def ensure_packages_tokens(name)
134
+ [
135
+ PuppetLint::Lexer::Token.new(:NAME, 'ensure_packages', nil, nil),
136
+ PuppetLint::Lexer::Token.new(:LPAREN, '(', nil, nil),
137
+ PuppetLint::Lexer::Token.new(:LBRACK, '[', nil, nil),
138
+ PuppetLint::Lexer::Token.new(:SSTRING, name, nil, nil),
139
+ PuppetLint::Lexer::Token.new(:RBRACK, ']', nil, nil),
140
+ PuppetLint::Lexer::Token.new(:RPAREN, ')', nil, nil)
141
+ ]
142
+ end
143
+
144
+ def fix_linked_list
145
+ tokens.each_cons(2) do |a, b|
146
+ a.next_token = b
147
+ b.prev_token = a
148
+ end
149
+
150
+ filter_formating_tokens(tokens).each_cons(2) do |a, b|
151
+ a.next_code_token = b
152
+ b.prev_code_token = a
153
+ end
154
+ end
155
+
156
+ def filter_code_tokens(tokens)
157
+ tokens.delete_if { |token| FORMATTING_TOKENS.key? token.type }
158
+ end
159
+
160
+ def filter_formating_tokens(tokens)
161
+ tokens.select { |token| !FORMATTING_TOKENS.key? token.type }
162
+ end
163
+
164
+ def if_indexes
165
+ PuppetLint::Data.definition_indexes(:IF)
166
+ end
167
+ end
@@ -0,0 +1,205 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'use_ensure_packages' do
4
+ context 'with fix disabled' do
5
+ context 'if not defined package' do
6
+ let(:code) do
7
+ "if ! defined (Package['foo']) {
8
+ package {'foo': }
9
+ }"
10
+ end
11
+
12
+ it 'should detect the problem' do
13
+ expect(problems).to have(1).problems
14
+ end
15
+ end
16
+
17
+ context 'if not defined package ensure installed' do
18
+ let(:code) do
19
+ "if ! defined (Package['foo']) {
20
+ package {'foo': ensure => installed }
21
+ }"
22
+ end
23
+
24
+ it 'should detect the problem' do
25
+ expect(problems).to have(1).problems
26
+ end
27
+ end
28
+
29
+ context 'if not defined package ensure installed' do
30
+ let(:code) do
31
+ "if ! defined (Package['foo']) {
32
+ package {'foo': ensure => installed; }
33
+ }"
34
+ end
35
+
36
+ it 'should detect the problem' do
37
+ expect(problems).to have(1).problems
38
+ end
39
+ end
40
+
41
+ context 'if not defined package ensure installed' do
42
+ let(:code) do
43
+ "if ! defined (Package['foo']) {
44
+ package {'foo': ensure => present }
45
+ }"
46
+ end
47
+
48
+ it 'should detect the problem' do
49
+ expect(problems).to have(1).problems
50
+ end
51
+ end
52
+
53
+ context 'if not defined package ensure installed' do
54
+ let(:code) do
55
+ "if ! defined (Package['foo']) {
56
+ package {'foo': ensure => present; }
57
+ }"
58
+ end
59
+
60
+ it 'should detect the problem' do
61
+ expect(problems).to have(1).problems
62
+ end
63
+ end
64
+
65
+ context 'if not defined package twice' do
66
+ let(:code) do
67
+ "if ! defined (Package['foo']) {
68
+ package {'foo': }
69
+ }
70
+ use { 'foo': }
71
+ if ! defined (Package['bar']) {
72
+ package {'bar': }
73
+ }"
74
+ end
75
+
76
+ it 'should detect the problem' do
77
+ expect(problems).to have(2).problems
78
+ end
79
+ end
80
+
81
+ context 'if not defined file' do
82
+ let(:code) do
83
+ "if ! defined (File['foo']) {
84
+ File {'foo': }
85
+ }"
86
+ end
87
+
88
+ it 'should not detect any problem' do
89
+ expect(problems).to have(0).problems
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'with fix enabled' do
95
+ before do
96
+ PuppetLint.configuration.fix = true
97
+ end
98
+
99
+ after do
100
+ PuppetLint.configuration.fix = false
101
+ end
102
+
103
+ context 'if not defined package' do
104
+ let(:code) do
105
+ "if ! defined (Package['foo']) {
106
+ package {'foo': }
107
+ }"
108
+ end
109
+ let(:expected_code) do
110
+ "ensure_packages(['foo'])"
111
+ end
112
+
113
+ it 'should solve the problem' do
114
+ expect(manifest).to eq(expected_code)
115
+ end
116
+ end
117
+
118
+ context 'if not defined package ensure installed' do
119
+ let(:code) do
120
+ "if ! defined (Package['foo']) {
121
+ package {'foo': ensure => installed }
122
+ }"
123
+ end
124
+ let(:expected_code) do
125
+ "ensure_packages(['foo'])"
126
+ end
127
+
128
+ it 'should solve the problem' do
129
+ expect(manifest).to eq(expected_code)
130
+ end
131
+ end
132
+
133
+ context 'if not defined package twice' do
134
+ let(:code) do
135
+ "if ! defined (Package['foo']) {
136
+ package {'foo': }
137
+ }
138
+ use { 'foo': }
139
+ if ! defined (Package['bar']) {
140
+ package {'bar': }
141
+ }"
142
+ end
143
+ let(:expected_code) do
144
+ "ensure_packages(['foo'])
145
+ use { 'foo': }
146
+ ensure_packages(['bar'])"
147
+ end
148
+
149
+ it 'should solve the problem' do
150
+ expect(manifest).to eq(expected_code)
151
+ end
152
+ end
153
+
154
+ context 'merge generated ensure_packages statements' do
155
+ let(:code) do
156
+ "if ! defined (Package['foo']) {
157
+ package {'foo': }
158
+ }
159
+ if ! defined (Package['bar']) {
160
+ package {'bar': }
161
+ }"
162
+ end
163
+ let(:expected_code) do
164
+ "ensure_packages(['foo','bar'])"
165
+ end
166
+
167
+ it 'should solve the problem' do
168
+ expect(manifest).to eq(expected_code)
169
+ end
170
+ end
171
+
172
+ context 'merge to pre existing ensure_packages' do
173
+ let(:code) do
174
+ "ensure_packages(['foo'])
175
+ if ! defined (Package['bar']) {
176
+ package {'bar': }
177
+ }"
178
+ end
179
+ let(:expected_code) do
180
+ "ensure_packages(['foo','bar'])"
181
+ end
182
+
183
+ it 'should solve the problem' do
184
+ expect(manifest).to eq(expected_code)
185
+ end
186
+ end
187
+
188
+ context 'do not merge to pre existing ensure_packages with arguments' do
189
+ let(:code) do
190
+ "ensure_packages(['foo'], {'ensure' => 'present'})
191
+ if ! defined (Package['bar']) {
192
+ package {'bar': }
193
+ }"
194
+ end
195
+ let(:expected_code) do
196
+ "ensure_packages(['foo'], {'ensure' => 'present'})
197
+ ensure_packages(['bar'])"
198
+ end
199
+
200
+ it 'should solve the problem' do
201
+ expect(manifest).to eq(expected_code)
202
+ end
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,12 @@
1
+ require 'puppet-lint'
2
+ require 'simplecov'
3
+ require 'simplecov-console'
4
+
5
+ PuppetLint::Plugins.load_spec_helper
6
+
7
+ SimpleCov.formatter = SimpleCov::Formatter::Console
8
+ SimpleCov.start do
9
+ add_filter '/spec'
10
+ add_filter '.bundle'
11
+ add_filter '/vendor'
12
+ end
metadata ADDED
@@ -0,0 +1,162 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: puppet-lint-use_ensure_packages-check
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Marius Rieder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: puppet-lint
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '3.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '3.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-its
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec-collection_matchers
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-json_expectations
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov-console
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: " A puppet-lint plugin to check that contains if ! defined (Package
126
+ statements.\n"
127
+ email: marius.rieder@nine.ch
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - README.md
133
+ - lib/puppet-lint/plugins/check_use_ensure_packages.rb
134
+ - spec/puppet-lint/plugins/check_use_ensure_packages_spec.rb
135
+ - spec/spec_helper.rb
136
+ homepage: https://github.com/ninech/puppet-lint-use_ensure_packages-check
137
+ licenses:
138
+ - MIT
139
+ metadata: {}
140
+ post_install_message:
141
+ rdoc_options: []
142
+ require_paths:
143
+ - lib
144
+ required_ruby_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ requirements: []
155
+ rubyforge_project:
156
+ rubygems_version: 2.5.1
157
+ signing_key:
158
+ specification_version: 4
159
+ summary: A puppet-lint plugin for "if !defined(Package" syntax.
160
+ test_files:
161
+ - spec/puppet-lint/plugins/check_use_ensure_packages_spec.rb
162
+ - spec/spec_helper.rb