openvox-lint 1.0.7 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +178 -1
- data/DOCUMENTATION.md +1392 -259
- data/README.md +53 -15
- data/lib/openvox-lint/check_plugin.rb +2 -1
- data/lib/openvox-lint/checks.rb +47 -3
- data/lib/openvox-lint/cli.rb +13 -4
- data/lib/openvox-lint/configuration.rb +2 -3
- data/lib/openvox-lint/lexer.rb +23 -9
- data/lib/openvox-lint/linter.rb +25 -1
- data/lib/openvox-lint/plugins/checks/arrow_alignment.rb +38 -0
- data/lib/openvox-lint/plugins/checks/double_quoted_strings.rb +16 -0
- data/lib/openvox-lint/plugins/checks/duplicate_params.rb +2 -2
- data/lib/openvox-lint/plugins/checks/hard_tabs.rb +7 -0
- data/lib/openvox-lint/plugins/checks/hiera3_function.rb +13 -3
- data/lib/openvox-lint/plugins/checks/legacy_facts.rb +47 -1
- data/lib/openvox-lint/plugins/checks/parameter_order.rb +2 -2
- data/lib/openvox-lint/plugins/checks/quoted_booleans.rb +21 -0
- data/lib/openvox-lint/plugins/checks/resource_reference_without_title_capital.rb +17 -2
- data/lib/openvox-lint/plugins/checks/single_quote_string_with_variables.rb +16 -0
- data/lib/openvox-lint/plugins/checks/top_scope_facts.rb +3 -1
- data/lib/openvox-lint/plugins/checks/trailing_comma.rb +20 -14
- data/lib/openvox-lint/plugins/checks/trailing_whitespace.rb +6 -0
- data/lib/openvox-lint/plugins/checks/variables_not_enclosed.rb +13 -7
- data/lib/openvox-lint/version.rb +1 -1
- data/lib/openvox-lint.rb +10 -0
- metadata +16 -12
- data/lib/openvox-lint/plugins/checks/relative_classname_inclusion.rb +0 -24
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
# Resource reference titles must start with a capital letter.
|
|
4
4
|
# e.g. File['/tmp/foo'] not file['/tmp/foo']
|
|
5
5
|
OpenvoxLint.new_check(:resource_reference_without_title_capital) do
|
|
6
|
+
# Puppet built-in functions and common stdlib functions that accept
|
|
7
|
+
# bracket/index syntax (name[...]). These are NOT resource
|
|
8
|
+
# references and must not be flagged.
|
|
9
|
+
FUNCTION_ALLOWLIST = %w[
|
|
10
|
+
split join include contain require
|
|
11
|
+
each map filter reduce select reject
|
|
12
|
+
slice flatten any all empty
|
|
13
|
+
assert_type create_resources defined dig
|
|
14
|
+
ensure_packages ensure_resource epp fail
|
|
15
|
+
fqdn_rand generate hiera hiera_array hiera_hash hiera_include
|
|
16
|
+
inline_epp inline_template lookup match md5 notice
|
|
17
|
+
realize regsubst sha1 sprintf tag template unique versioncmp
|
|
18
|
+
with
|
|
19
|
+
].freeze
|
|
20
|
+
|
|
6
21
|
def check
|
|
7
22
|
sem = semantic_tokens
|
|
8
23
|
sem.each_with_index do |tok, i|
|
|
@@ -11,8 +26,8 @@ OpenvoxLint.new_check(:resource_reference_without_title_capital) do
|
|
|
11
26
|
next unless sem[i + 1].type == :LBRACK
|
|
12
27
|
# This is name[...] which should be Name[...] for a resource reference
|
|
13
28
|
next if tok.value =~ /\A[A-Z]/
|
|
14
|
-
# Skip function calls and normal array access
|
|
15
|
-
next if
|
|
29
|
+
# Skip function calls, method calls, and normal array access
|
|
30
|
+
next if FUNCTION_ALLOWLIST.include?(tok.value)
|
|
16
31
|
notify :warning,
|
|
17
32
|
message: "resource reference '#{tok.value}' must start with a capital letter",
|
|
18
33
|
line: tok.line, column: tok.column
|
|
@@ -13,4 +13,20 @@ OpenvoxLint.new_check(:single_quote_string_with_variables) do
|
|
|
13
13
|
line: tok.line, column: tok.column
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
|
+
|
|
17
|
+
# --fix support: swap outer single quotes to double (may require manual
|
|
18
|
+
# review for literal $ or inner quotes per style exceptions).
|
|
19
|
+
def fix(problem)
|
|
20
|
+
idx = problem[:line] - 1
|
|
21
|
+
line = @manifest_lines[idx].dup
|
|
22
|
+
col = (problem[:column] || 1) - 1
|
|
23
|
+
if line[col] == "'"
|
|
24
|
+
end_col = line.index("'", col + 1)
|
|
25
|
+
if end_col
|
|
26
|
+
inner = line[(col + 1)...end_col]
|
|
27
|
+
line[col..end_col] = '"' + inner + '"'
|
|
28
|
+
@manifest_lines[idx] = line
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
16
32
|
end
|
|
@@ -6,7 +6,9 @@ OpenvoxLint.new_check(:top_scope_facts) do
|
|
|
6
6
|
def check
|
|
7
7
|
tokens.each do |tok|
|
|
8
8
|
next unless tok.type == :VARIABLE
|
|
9
|
-
|
|
9
|
+
# Strip leading $ and any trailing : left by the lexer when a
|
|
10
|
+
# variable is used as a resource title ($::fact:).
|
|
11
|
+
name = tok.value.sub(/^\$/, '').chomp(':')
|
|
10
12
|
next unless name.start_with?('::')
|
|
11
13
|
fact_name = name.sub(/\A::/, '')
|
|
12
14
|
# Skip module-qualified variables (e.g. ::mymodule::param)
|
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Resource bodies and parameter lists should end with a trailing comma.
|
|
4
|
+
#
|
|
5
|
+
# Only fires inside resource bodies (NAME { ... }) — not inside
|
|
6
|
+
# conditionals (if/unless/case), class bodies, or other brace contexts
|
|
7
|
+
# where a trailing comma is not expected.
|
|
4
8
|
OpenvoxLint.new_check(:trailing_comma) do
|
|
5
9
|
def check
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
resource_indexes.each do |res|
|
|
11
|
+
params = res[:param_tokens]
|
|
12
|
+
next if params.empty?
|
|
13
|
+
|
|
14
|
+
# Find the last non-formatting token in the resource body
|
|
15
|
+
last = params.reverse_each.find { |t| !t.formatting? }
|
|
16
|
+
next unless last
|
|
17
|
+
|
|
18
|
+
# Already has a trailing comma — nothing to do
|
|
19
|
+
next if last.type == :COMMA
|
|
20
|
+
|
|
21
|
+
# Only flag after value-like tokens (not structural tokens)
|
|
22
|
+
next unless %i[SSTRING STRING NAME VARIABLE NUMBER TRUE FALSE
|
|
23
|
+
CLASSREF RBRACK DQSTRING].include?(last.type)
|
|
24
|
+
|
|
19
25
|
notify :warning,
|
|
20
26
|
message: 'missing trailing comma after last attribute',
|
|
21
|
-
line:
|
|
27
|
+
line: last.line, column: last.column
|
|
22
28
|
end
|
|
23
29
|
end
|
|
24
30
|
end
|
|
@@ -11,4 +11,10 @@ OpenvoxLint.new_check(:trailing_whitespace) do
|
|
|
11
11
|
column: line.rstrip.length + 1
|
|
12
12
|
end
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
# --fix support: strip trailing whitespace from the offending line.
|
|
16
|
+
def fix(problem)
|
|
17
|
+
idx = problem[:line] - 1
|
|
18
|
+
@manifest_lines[idx] = @manifest_lines[idx].rstrip
|
|
19
|
+
end
|
|
14
20
|
end
|
|
@@ -2,18 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
# Variables in double-quoted strings should be enclosed in braces.
|
|
4
4
|
# e.g. "$foo" should be "${foo}"
|
|
5
|
+
#
|
|
6
|
+
# Correctly handles strings with a mix of enclosed and unenclosed
|
|
7
|
+
# variables — e.g. "$foo and ${bar}" flags the unenclosed $foo even
|
|
8
|
+
# though ${bar} is properly enclosed.
|
|
5
9
|
OpenvoxLint.new_check(:variables_not_enclosed) do
|
|
6
10
|
def check
|
|
7
11
|
tokens.each do |tok|
|
|
8
12
|
next unless tok.type == :DQSTRING || tok.type == :STRING
|
|
9
13
|
val = tok.value
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
# Scan for any $var that is NOT preceded by ${ (already enclosed).
|
|
15
|
+
# We use a negative lookbehind to skip ${...} patterns and only
|
|
16
|
+
# match bare $varname references.
|
|
17
|
+
val.scan(/(?<!\$)\$(?!\{)([a-zA-Z_][a-zA-Z0-9_:]*)/) do
|
|
18
|
+
notify :warning,
|
|
19
|
+
message: 'variable not enclosed in braces within string',
|
|
20
|
+
line: tok.line,
|
|
21
|
+
column: tok.column
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
end
|
|
19
25
|
end
|
data/lib/openvox-lint/version.rb
CHANGED
data/lib/openvox-lint.rb
CHANGED
|
@@ -29,11 +29,21 @@ module OpenvoxLint
|
|
|
29
29
|
yield(configuration)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
# Reset the global configuration singleton. Called at the start of
|
|
33
|
+
# every CLI run so that repeated invocations in the same Ruby
|
|
34
|
+
# process (Vim plugins, guard, Rake loops) start clean.
|
|
35
|
+
def reset_configuration!
|
|
36
|
+
@configuration = Configuration.new
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
def checks
|
|
33
40
|
@checks ||= {}
|
|
34
41
|
end
|
|
35
42
|
|
|
36
43
|
def new_check(name, &block)
|
|
44
|
+
if checks.key?(name)
|
|
45
|
+
$stderr.puts "openvox-lint: warning: check '#{name}' is already registered — overwriting" if ENV['OPENVOX_LINT_DEBUG']
|
|
46
|
+
end
|
|
37
47
|
klass = Class.new(CheckPlugin, &block)
|
|
38
48
|
klass.instance_variable_set(:@check_name, name)
|
|
39
49
|
checks[name] = klass
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openvox-lint
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jerald Sheets
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -53,10 +53,15 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '1.50'
|
|
55
55
|
description: |
|
|
56
|
-
openvox-lint is a linter for OpenVox and Puppet manifests.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
openvox-lint is a modern style-guide linter for OpenVox and Puppet manifests.
|
|
57
|
+
It checks your .pp files against the OpenVox Language Style Guide (the
|
|
58
|
+
current canonical reference) and catches common errors, deprecated patterns
|
|
59
|
+
(legacy facts, Hiera 3, import, etc.), strict-mode issues, and Puppet 8+ /
|
|
60
|
+
OpenVox 8.x problems. Includes real --fix support for many checks.
|
|
61
|
+
|
|
62
|
+
Fully compatible with OpenVox 8.x and Puppet 8.x. Drop-in replacement for
|
|
63
|
+
the archived puppet-lint with better Ruby 2.5+ support and OpenVox-specific
|
|
64
|
+
checks.
|
|
60
65
|
email:
|
|
61
66
|
- jsheets@xai.com
|
|
62
67
|
executables:
|
|
@@ -99,7 +104,6 @@ files:
|
|
|
99
104
|
- lib/openvox-lint/plugins/checks/parameter_order.rb
|
|
100
105
|
- lib/openvox-lint/plugins/checks/puppet_url_without_modules.rb
|
|
101
106
|
- lib/openvox-lint/plugins/checks/quoted_booleans.rb
|
|
102
|
-
- lib/openvox-lint/plugins/checks/relative_classname_inclusion.rb
|
|
103
107
|
- lib/openvox-lint/plugins/checks/resource_reference_without_title_capital.rb
|
|
104
108
|
- lib/openvox-lint/plugins/checks/selector_inside_resource.rb
|
|
105
109
|
- lib/openvox-lint/plugins/checks/single_quote_string_with_variables.rb
|
|
@@ -124,9 +128,9 @@ metadata:
|
|
|
124
128
|
homepage_uri: https://github.com/cvquesty/openvox-lint
|
|
125
129
|
source_code_uri: https://github.com/cvquesty/openvox-lint
|
|
126
130
|
bug_tracker_uri: https://github.com/cvquesty/openvox-lint/issues
|
|
127
|
-
changelog_uri: https://github.com/cvquesty/openvox-lint/blob/
|
|
131
|
+
changelog_uri: https://github.com/cvquesty/openvox-lint/blob/development/CHANGELOG.md
|
|
128
132
|
rubygems_mfa_required: 'true'
|
|
129
|
-
post_install_message:
|
|
133
|
+
post_install_message:
|
|
130
134
|
rdoc_options: []
|
|
131
135
|
require_paths:
|
|
132
136
|
- lib
|
|
@@ -142,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
142
146
|
version: '0'
|
|
143
147
|
requirements: []
|
|
144
148
|
rubygems_version: 3.0.3.1
|
|
145
|
-
signing_key:
|
|
149
|
+
signing_key:
|
|
146
150
|
specification_version: 4
|
|
147
|
-
summary: Check OpenVox/Puppet manifests against the
|
|
151
|
+
summary: Check OpenVox/Puppet manifests against the OpenVox Language Style Guide
|
|
148
152
|
test_files: []
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# Use absolute class names in include/require/contain statements.
|
|
4
|
-
OpenvoxLint.new_check(:relative_classname_inclusion) do
|
|
5
|
-
INCLUDE_FUNCS = %w[include require contain].freeze
|
|
6
|
-
|
|
7
|
-
def check
|
|
8
|
-
sem = semantic_tokens
|
|
9
|
-
sem.each_with_index do |tok, i|
|
|
10
|
-
next unless tok.type == :NAME && INCLUDE_FUNCS.include?(tok.value)
|
|
11
|
-
j = i + 1
|
|
12
|
-
next if j >= sem.length
|
|
13
|
-
name_tok = sem[j]
|
|
14
|
-
next unless name_tok.type == :NAME || name_tok.type == :SSTRING || name_tok.type == :STRING
|
|
15
|
-
class_name = name_tok.value.gsub(/['"]/, '')
|
|
16
|
-
next if class_name.start_with?('::') || class_name.empty?
|
|
17
|
-
# Single-segment names are OK (they're unambiguous)
|
|
18
|
-
next unless class_name.include?('::')
|
|
19
|
-
notify :warning,
|
|
20
|
-
message: "class name '#{class_name}' should be fully qualified (start with ::)",
|
|
21
|
-
line: name_tok.line, column: name_tok.column
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|