Skip to content

Commit ad07472

Browse files
committed
Make CLI more flexible
* Add `.scelint` defaults file support (rspec-style CLI argument defaults) * Add `--allow-reserved-words` option to skip reserved word checks on parameter names * Bump version to 0.6.0
1 parent dbd378a commit ad07472

9 files changed

Lines changed: 130 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 0.6.0 / 2026-03-11
2+
* Add `.scelint` defaults file support (rspec-style CLI argument defaults)
3+
* Add `--allow-reserved-words` option to skip reserved word checks on parameter names
4+
15
### 0.5.0 / 2026-03-11
26
* Validate parameter names
37
* Fix command-line argument processing

lib/scelint.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,9 @@ class Lint
134134
#
135135
# @param paths [Array<String>] Paths to look for SCE data in. Defaults to ['.']
136136
# @param logger [Logger] A logger to send messages to. Defaults to an instance of Logger with the log level set to INFO.
137-
def initialize(paths = ['.'], logger: Logger.new(STDOUT, level: Logger::INFO))
137+
def initialize(paths = ['.'], logger: Logger.new(STDOUT, level: Logger::INFO), allow_reserved_words: false)
138138
@log = logger
139+
@allow_reserved_words = allow_reserved_words
139140
@errors = []
140141
@warnings = []
141142
@notes = []
@@ -418,6 +419,8 @@ def check_parameter(file, check, parameter)
418419
return
419420
end
420421

422+
return if @allow_reserved_words
423+
421424
parameter.split('::').each do |part|
422425
if reserved_words.include?(part)
423426
errors << "#{file} (check '#{check}'): parameter name '#{parameter}' contains reserved word '#{part}'"

lib/scelint/cli.rb

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,21 @@ def self.exit_on_failure?
1010
true
1111
end
1212

13+
DEFAULTS_FILE = '.scelint'
14+
15+
# Load default arguments from .scelint in the current directory.
16+
# Each non-blank, non-comment line may contain one or more arguments.
17+
def self.load_defaults
18+
return [] unless File.exist?(DEFAULTS_FILE)
19+
File.readlines(DEFAULTS_FILE, chomp: true)
20+
.reject { |line| line.strip.empty? || line.strip.start_with?('#') }
21+
.flat_map(&:split)
22+
end
23+
1324
# When the first argument is not a known subcommand or an option flag,
1425
# treat all arguments as paths for the default `lint` command.
1526
def self.start(given_args = ARGV, config = {})
16-
args = given_args
27+
args = load_defaults + given_args
1728
if args.first && !args.first.start_with?('-') && !all_commands.key?(args.first)
1829
args = ['lint'] + args
1930
end
@@ -26,9 +37,10 @@ def self.start(given_args = ARGV, config = {})
2637

2738
desc 'lint PATH', 'Lint all files in PATH'
2839
option :strict, type: :boolean, aliases: '-s', default: false
40+
option :allow_reserved_words, type: :boolean, default: false
2941
def lint(*paths)
3042
paths = ['.'] if paths.nil? || paths.empty?
31-
lint = Scelint::Lint.new(paths, logger: logger)
43+
lint = Scelint::Lint.new(paths, logger: logger, allow_reserved_words: options[:allow_reserved_words])
3244

3345
count = lint.files.count
3446

lib/scelint/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Scelint
4-
VERSION = '0.5.0'
4+
VERSION = '0.6.0'
55
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
version: 2.0.0
3+
ce:
4+
12_ce1:
5+
controls:
6+
12_control1: true
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
version: 2.0.0
3+
checks:
4+
12_settings_check:
5+
type: puppet-class-parameter
6+
settings:
7+
parameter: test_module_12::settings
8+
value: true
9+
ces:
10+
- 12_ce1
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
version: 2.0.0
3+
profiles:
4+
12_profile_test:
5+
controls:
6+
12_control1: true

spec/unit/scelint/cli_spec.rb

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
let(:fixtures_dir) { File.expand_path('../../fixtures/modules', __dir__) }
88
let(:clean_module_path) { File.join(fixtures_dir, 'test_module_01') }
99
let(:warning_module_path) { File.join(fixtures_dir, 'test_module_04') }
10+
let(:reserved_word_module_path) { File.join(fixtures_dir, 'test_module_12') }
1011

1112
# Runs the CLI via .start (as a user would invoke from the command line),
1213
# captures the SystemExit status, and suppresses stdout noise from the logger.
@@ -19,6 +20,8 @@ def run_cli(args)
1920
before(:each) do
2021
# Silence logger output to keep spec output clean.
2122
allow(Logger).to receive(:new).and_return(Logger.new(File::NULL))
23+
# Prevent any real .scelint file in the working directory from affecting tests.
24+
allow(described_class).to receive(:load_defaults).and_return([])
2225
end
2326

2427
describe 'invocation without an explicit subcommand' do
@@ -85,4 +88,85 @@ def run_cli(args)
8588
expect(run_cli(['--debug', clean_module_path])).to eq(0)
8689
end
8790
end
91+
92+
describe '.scelint defaults file' do
93+
describe '.load_defaults' do
94+
before(:each) do
95+
allow(described_class).to receive(:load_defaults).and_call_original
96+
end
97+
98+
it 'returns an empty array when no .scelint file exists' do
99+
allow(File).to receive(:exist?).with(described_class::DEFAULTS_FILE).and_return(false)
100+
expect(described_class.load_defaults).to eq([])
101+
end
102+
103+
it 'returns args parsed from the file' do
104+
allow(File).to receive(:exist?).with(described_class::DEFAULTS_FILE).and_return(true)
105+
allow(File).to receive(:readlines).with(described_class::DEFAULTS_FILE, chomp: true)
106+
.and_return(['--allow-reserved-words', '--strict'])
107+
expect(described_class.load_defaults).to eq(['--allow-reserved-words', '--strict'])
108+
end
109+
110+
it 'splits multiple args on a single line' do
111+
allow(File).to receive(:exist?).with(described_class::DEFAULTS_FILE).and_return(true)
112+
allow(File).to receive(:readlines).with(described_class::DEFAULTS_FILE, chomp: true)
113+
.and_return(['--allow-reserved-words --strict'])
114+
expect(described_class.load_defaults).to eq(['--allow-reserved-words', '--strict'])
115+
end
116+
117+
it 'ignores blank lines' do
118+
allow(File).to receive(:exist?).with(described_class::DEFAULTS_FILE).and_return(true)
119+
allow(File).to receive(:readlines).with(described_class::DEFAULTS_FILE, chomp: true)
120+
.and_return(['', '--strict', ''])
121+
expect(described_class.load_defaults).to eq(['--strict'])
122+
end
123+
124+
it 'ignores comment lines' do
125+
allow(File).to receive(:exist?).with(described_class::DEFAULTS_FILE).and_return(true)
126+
allow(File).to receive(:readlines).with(described_class::DEFAULTS_FILE, chomp: true)
127+
.and_return(['# this is a comment', '--strict'])
128+
expect(described_class.load_defaults).to eq(['--strict'])
129+
end
130+
end
131+
132+
context 'when .scelint contains --allow-reserved-words' do
133+
before(:each) do
134+
allow(described_class).to receive(:load_defaults).and_return(['--allow-reserved-words'])
135+
end
136+
137+
it 'applies the flag without passing it on the command line' do
138+
expect(run_cli([reserved_word_module_path])).to eq(0)
139+
end
140+
141+
it 'can be overridden by --no-allow-reserved-words on the command line' do
142+
expect(run_cli(['--no-allow-reserved-words', reserved_word_module_path])).to eq(1)
143+
end
144+
end
145+
146+
context 'when .scelint contains --strict' do
147+
before(:each) do
148+
allow(described_class).to receive(:load_defaults).and_return(['--strict'])
149+
end
150+
151+
it 'applies --strict without passing it on the command line' do
152+
expect(run_cli([warning_module_path])).to eq(1)
153+
end
154+
end
155+
end
156+
157+
describe '--allow-reserved-words flag' do
158+
context 'when a parameter name contains a reserved word' do
159+
it 'exits 1 without --allow-reserved-words' do
160+
expect(run_cli([reserved_word_module_path])).to eq(1)
161+
end
162+
163+
it 'exits 0 with --allow-reserved-words' do
164+
expect(run_cli(['--allow-reserved-words', reserved_word_module_path])).to eq(0)
165+
end
166+
167+
it 'exits 0 with --allow-reserved-words and --strict' do
168+
expect(run_cli(['--allow-reserved-words', '--strict', reserved_word_module_path])).to eq(0)
169+
end
170+
end
171+
end
88172
end

spec/unit/scelint/lint_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
# Each test assumes 3 files, no errors, no warnings, no notes.
77
# Exceptions are listed below.
88
let(:lint_files) { { '04' => 37, '11' => 2 } }
9-
let(:lint_errors) { {} }
9+
let(:lint_errors) { { '12' => 2 } }
1010
let(:lint_warnings) { { '04' => 17 } }
1111
let(:lint_notes) { { '11' => 1 } }
1212

0 commit comments

Comments
 (0)