pdk-akerl 1.8.0.1
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 +7 -0
- data/CHANGELOG.md +826 -0
- data/LICENSE +201 -0
- data/README.md +133 -0
- data/exe/pdk +10 -0
- data/lib/pdk.rb +10 -0
- data/lib/pdk/answer_file.rb +121 -0
- data/lib/pdk/cli.rb +113 -0
- data/lib/pdk/cli/build.rb +76 -0
- data/lib/pdk/cli/bundle.rb +42 -0
- data/lib/pdk/cli/convert.rb +41 -0
- data/lib/pdk/cli/errors.rb +23 -0
- data/lib/pdk/cli/exec.rb +246 -0
- data/lib/pdk/cli/exec_group.rb +67 -0
- data/lib/pdk/cli/module.rb +14 -0
- data/lib/pdk/cli/module/build.rb +14 -0
- data/lib/pdk/cli/module/generate.rb +45 -0
- data/lib/pdk/cli/new.rb +17 -0
- data/lib/pdk/cli/new/class.rb +32 -0
- data/lib/pdk/cli/new/defined_type.rb +30 -0
- data/lib/pdk/cli/new/module.rb +41 -0
- data/lib/pdk/cli/new/provider.rb +27 -0
- data/lib/pdk/cli/new/task.rb +31 -0
- data/lib/pdk/cli/test.rb +12 -0
- data/lib/pdk/cli/test/unit.rb +88 -0
- data/lib/pdk/cli/update.rb +32 -0
- data/lib/pdk/cli/util.rb +193 -0
- data/lib/pdk/cli/util/command_redirector.rb +26 -0
- data/lib/pdk/cli/util/interview.rb +63 -0
- data/lib/pdk/cli/util/option_normalizer.rb +53 -0
- data/lib/pdk/cli/util/option_validator.rb +56 -0
- data/lib/pdk/cli/validate.rb +124 -0
- data/lib/pdk/generate.rb +11 -0
- data/lib/pdk/generate/defined_type.rb +49 -0
- data/lib/pdk/generate/module.rb +318 -0
- data/lib/pdk/generate/provider.rb +82 -0
- data/lib/pdk/generate/puppet_class.rb +48 -0
- data/lib/pdk/generate/puppet_object.rb +288 -0
- data/lib/pdk/generate/task.rb +86 -0
- data/lib/pdk/i18n.rb +4 -0
- data/lib/pdk/logger.rb +28 -0
- data/lib/pdk/module.rb +21 -0
- data/lib/pdk/module/build.rb +214 -0
- data/lib/pdk/module/convert.rb +209 -0
- data/lib/pdk/module/metadata.rb +193 -0
- data/lib/pdk/module/templatedir.rb +313 -0
- data/lib/pdk/module/update.rb +111 -0
- data/lib/pdk/module/update_manager.rb +210 -0
- data/lib/pdk/report.rb +112 -0
- data/lib/pdk/report/event.rb +357 -0
- data/lib/pdk/template_file.rb +89 -0
- data/lib/pdk/tests/unit.rb +213 -0
- data/lib/pdk/util.rb +271 -0
- data/lib/pdk/util/bundler.rb +253 -0
- data/lib/pdk/util/filesystem.rb +12 -0
- data/lib/pdk/util/git.rb +74 -0
- data/lib/pdk/util/puppet_version.rb +242 -0
- data/lib/pdk/util/ruby_version.rb +147 -0
- data/lib/pdk/util/vendored_file.rb +88 -0
- data/lib/pdk/util/version.rb +42 -0
- data/lib/pdk/util/windows.rb +13 -0
- data/lib/pdk/util/windows/api_types.rb +57 -0
- data/lib/pdk/util/windows/file.rb +36 -0
- data/lib/pdk/util/windows/string.rb +16 -0
- data/lib/pdk/validate.rb +14 -0
- data/lib/pdk/validate/base_validator.rb +209 -0
- data/lib/pdk/validate/metadata/metadata_json_lint.rb +86 -0
- data/lib/pdk/validate/metadata/metadata_syntax.rb +109 -0
- data/lib/pdk/validate/metadata_validator.rb +30 -0
- data/lib/pdk/validate/puppet/puppet_lint.rb +67 -0
- data/lib/pdk/validate/puppet/puppet_syntax.rb +112 -0
- data/lib/pdk/validate/puppet_validator.rb +30 -0
- data/lib/pdk/validate/ruby/rubocop.rb +77 -0
- data/lib/pdk/validate/ruby_validator.rb +29 -0
- data/lib/pdk/validate/tasks/metadata_lint.rb +126 -0
- data/lib/pdk/validate/tasks/name.rb +88 -0
- data/lib/pdk/validate/tasks_validator.rb +33 -0
- data/lib/pdk/version.rb +4 -0
- data/locales/config.yaml +21 -0
- data/locales/pdk.pot +1283 -0
- metadata +304 -0
data/lib/pdk/cli/util.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
module PDK
|
2
|
+
module CLI
|
3
|
+
module Util
|
4
|
+
# Ensures the calling code is being run from inside a module directory.
|
5
|
+
#
|
6
|
+
# @param opts [Hash] options to change the behavior of the check logic.
|
7
|
+
# @option opts [Boolean] :check_module_layout Set to true to check for
|
8
|
+
# stardard module folder layout if the module does not contain
|
9
|
+
# a metadata.json file.
|
10
|
+
#
|
11
|
+
# @raise [PDK::CLI::ExitWithError] if the current directory does not
|
12
|
+
# contain a Puppet module.
|
13
|
+
def ensure_in_module!(opts = {})
|
14
|
+
return unless PDK::Util.module_root.nil?
|
15
|
+
return if opts[:check_module_layout] && PDK::Util.in_module_root?
|
16
|
+
|
17
|
+
message = opts.fetch(:message, _('This command must be run from inside a valid module (no metadata.json found).'))
|
18
|
+
raise PDK::CLI::ExitWithError.new(message, opts)
|
19
|
+
end
|
20
|
+
module_function :ensure_in_module!
|
21
|
+
|
22
|
+
def spinner_opts_for_platform
|
23
|
+
windows_opts = {
|
24
|
+
success_mark: '*',
|
25
|
+
error_mark: 'X',
|
26
|
+
}
|
27
|
+
|
28
|
+
return windows_opts if Gem.win_platform?
|
29
|
+
{}
|
30
|
+
end
|
31
|
+
module_function :spinner_opts_for_platform
|
32
|
+
|
33
|
+
def prompt_for_yes(question_text, opts = {})
|
34
|
+
prompt = opts[:prompt] || TTY::Prompt.new(help_color: :cyan)
|
35
|
+
validator = proc { |value| [true, false].include?(value) || value =~ %r{\A(?:yes|y|no|n)\Z}i }
|
36
|
+
response = nil
|
37
|
+
|
38
|
+
begin
|
39
|
+
response = prompt.yes?(question_text) do |q|
|
40
|
+
q.default opts[:default] unless opts[:default].nil?
|
41
|
+
q.validate(validator, _('Answer "Y" to continue or "n" to cancel.'))
|
42
|
+
end
|
43
|
+
rescue TTY::Prompt::Reader::InputInterrupt
|
44
|
+
PDK.logger.info opts[:cancel_message] if opts[:cancel_message]
|
45
|
+
end
|
46
|
+
|
47
|
+
response
|
48
|
+
end
|
49
|
+
module_function :prompt_for_yes
|
50
|
+
|
51
|
+
def interactive?
|
52
|
+
return false if PDK.logger.debug?
|
53
|
+
return !ENV['PDK_FRONTEND'].casecmp('noninteractive').zero? if ENV['PDK_FRONTEND']
|
54
|
+
return false unless $stderr.isatty
|
55
|
+
|
56
|
+
true
|
57
|
+
end
|
58
|
+
module_function :interactive?
|
59
|
+
|
60
|
+
def module_version_check
|
61
|
+
module_pdk_ver = PDK::Util.module_pdk_version
|
62
|
+
|
63
|
+
# This means the module does not have a pdk-version tag in the metadata.json
|
64
|
+
# and will require a pdk convert.
|
65
|
+
raise PDK::CLI::ExitWithError, _('This module is not PDK compatible. Run `pdk convert` to make it compatible with your version of PDK.') if module_pdk_ver.nil?
|
66
|
+
|
67
|
+
# This checks that the version of pdk in the module's metadata is older
|
68
|
+
# than 1.3.1, which means the module will need to run pdk convert to the
|
69
|
+
# new templates.
|
70
|
+
if Gem::Version.new(module_pdk_ver) < Gem::Version.new('1.3.1')
|
71
|
+
PDK.logger.warn _('This module template is out of date. Run `pdk convert` to make it compatible with your version of PDK.')
|
72
|
+
# This checks if the version of the installed PDK is older than the
|
73
|
+
# version in the module's metadata, and advises the user to upgrade to
|
74
|
+
# their install of PDK.
|
75
|
+
elsif Gem::Version.new(PDK::VERSION) < Gem::Version.new(module_pdk_ver)
|
76
|
+
PDK.logger.warn _('This module is compatible with a newer version of PDK. Upgrade your version of PDK to ensure compatibility.')
|
77
|
+
# This checks if the version listed in the module's metadata is older
|
78
|
+
# than the installed PDK, and advises the user to run pdk update.
|
79
|
+
elsif Gem::Version.new(PDK::VERSION) > Gem::Version.new(module_pdk_ver)
|
80
|
+
PDK.logger.warn _('This module is compatible with an older version of PDK. Run `pdk update` to update it to your version of PDK.')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
module_function :module_version_check
|
84
|
+
|
85
|
+
def puppet_from_opts_or_env(opts)
|
86
|
+
use_puppet_dev = (opts || {})[:'puppet-dev'] || ENV['PDK_PUPPET_DEV']
|
87
|
+
desired_puppet_version = (opts || {})[:'puppet-version'] || ENV['PDK_PUPPET_VERSION']
|
88
|
+
desired_pe_version = (opts || {})[:'pe-version'] || ENV['PDK_PE_VERSION']
|
89
|
+
|
90
|
+
begin
|
91
|
+
puppet_env =
|
92
|
+
if use_puppet_dev
|
93
|
+
PDK::Util::PuppetVersion.puppet_dev_env
|
94
|
+
elsif desired_puppet_version
|
95
|
+
PDK::Util::PuppetVersion.find_gem_for(desired_puppet_version)
|
96
|
+
elsif desired_pe_version
|
97
|
+
PDK::Util::PuppetVersion.from_pe_version(desired_pe_version)
|
98
|
+
else
|
99
|
+
PDK::Util::PuppetVersion.from_module_metadata || PDK::Util::PuppetVersion.latest_available
|
100
|
+
end
|
101
|
+
rescue ArgumentError => e
|
102
|
+
raise PDK::CLI::ExitWithError, e.message
|
103
|
+
end
|
104
|
+
|
105
|
+
# Notify user of what Ruby version will be used.
|
106
|
+
PDK.logger.info(_('Using Ruby %{version}') % {
|
107
|
+
version: puppet_env[:ruby_version],
|
108
|
+
})
|
109
|
+
|
110
|
+
gemset = { puppet: puppet_env[:gem_version].to_s }
|
111
|
+
|
112
|
+
# Notify user of what gems are being activated.
|
113
|
+
gemset.each do |gem, version|
|
114
|
+
next if version.nil?
|
115
|
+
|
116
|
+
PDK.logger.info(_('Using %{gem} %{version}') % {
|
117
|
+
gem: gem.to_s.capitalize,
|
118
|
+
version: version,
|
119
|
+
})
|
120
|
+
end
|
121
|
+
|
122
|
+
{
|
123
|
+
gemset: gemset,
|
124
|
+
ruby_version: puppet_env[:ruby_version],
|
125
|
+
}
|
126
|
+
end
|
127
|
+
module_function :puppet_from_opts_or_env
|
128
|
+
|
129
|
+
def validate_puppet_version_opts(opts)
|
130
|
+
puppet_ver_specs = []
|
131
|
+
puppet_ver_specs << '--puppet-version option' if opts[:'puppet-version']
|
132
|
+
puppet_ver_specs << 'PDK_PUPPET_VERSION environment variable' if ENV['PDK_PUPPET_VERSION'] && !ENV['PDK_PUPPET_VERSION'].empty?
|
133
|
+
|
134
|
+
pe_ver_specs = []
|
135
|
+
pe_ver_specs << '--pe-version option' if opts[:'pe-version']
|
136
|
+
pe_ver_specs << 'PDK_PE_VERSION environment variable' if ENV['PDK_PE_VERSION'] && !ENV['PDK_PE_VERSION'].empty?
|
137
|
+
|
138
|
+
puppet_dev_specs = []
|
139
|
+
puppet_dev_specs << '--puppet-dev flag' if opts[:'puppet-dev']
|
140
|
+
puppet_dev_specs << 'PDK_PUPPET_DEV environment variable' if ENV['PDK_PUPPET_DEV'] && !ENV['PDK_PUPPET_DEV'].empty?
|
141
|
+
|
142
|
+
puppet_dev_specs.each do |pup_dev_spec|
|
143
|
+
[puppet_ver_specs, pe_ver_specs].each do |offending|
|
144
|
+
next if offending.empty?
|
145
|
+
|
146
|
+
raise PDK::CLI::ExitWithError, _('You cannot specify a %{first} and %{second} at the same time') % {
|
147
|
+
first: pup_dev_spec,
|
148
|
+
second: offending.first,
|
149
|
+
}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
puppet_ver_specs.each do |pup_ver_spec|
|
154
|
+
next if pe_ver_specs.empty?
|
155
|
+
|
156
|
+
offending = [pup_ver_spec, pe_ver_specs[0]].sort
|
157
|
+
|
158
|
+
raise PDK::CLI::ExitWithError, _('You cannot specify a %{first} and %{second} at the same time.') % {
|
159
|
+
first: offending[0],
|
160
|
+
second: offending[1],
|
161
|
+
}
|
162
|
+
end
|
163
|
+
|
164
|
+
if puppet_dev_specs.size == 2
|
165
|
+
warning_str = 'Puppet dev flag from command line: "--puppet-dev" '
|
166
|
+
warning_str += 'overrides value from environment: "PDK_PUPPET_DEV=true". You should not specify both.'
|
167
|
+
|
168
|
+
PDK.logger.warn(_(warning_str) % {
|
169
|
+
pup_ver_opt: opts[:'puppet-dev'],
|
170
|
+
pup_ver_env: ENV['PDK_PUPPET_DEV'],
|
171
|
+
})
|
172
|
+
elsif puppet_ver_specs.size == 2
|
173
|
+
warning_str = 'Puppet version option from command line: "--puppet-version=%{pup_ver_opt}" '
|
174
|
+
warning_str += 'overrides value from environment: "PDK_PUPPET_VERSION=%{pup_ver_env}". You should not specify both.'
|
175
|
+
|
176
|
+
PDK.logger.warn(_(warning_str) % {
|
177
|
+
pup_ver_opt: opts[:'puppet-version'],
|
178
|
+
pup_ver_env: ENV['PDK_PUPPET_VERSION'],
|
179
|
+
})
|
180
|
+
elsif pe_ver_specs.size == 2
|
181
|
+
warning_str = 'Puppet Enterprise version option from command line: "--pe-version=%{pe_ver_opt}" '
|
182
|
+
warning_str += 'overrides value from environment: "PDK_PE_VERSION=%{pe_ver_env}". You should not specify both.'
|
183
|
+
|
184
|
+
PDK.logger.warn(_(warning_str) % {
|
185
|
+
pup_ver_opt: opts[:'pe-version'],
|
186
|
+
pup_ver_env: ENV['PDK_PE_VERSION'],
|
187
|
+
})
|
188
|
+
end
|
189
|
+
end
|
190
|
+
module_function :validate_puppet_version_opts
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module CLI
|
5
|
+
module Util
|
6
|
+
class CommandRedirector < TTY::Prompt::AnswersCollector
|
7
|
+
attr_accessor :command
|
8
|
+
|
9
|
+
def pastel
|
10
|
+
@pastel ||= Pastel.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def target_command(cmd)
|
14
|
+
@command = cmd
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
@prompt.puts _('Did you mean \'%{command}\'?') % { command: pastel.bold(@command) }
|
19
|
+
@prompt.yes?('-->')
|
20
|
+
rescue TTY::Prompt::Reader::InputInterrupt
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'tty-prompt'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module CLI
|
5
|
+
module Util
|
6
|
+
class Interview < TTY::Prompt::AnswersCollector
|
7
|
+
def pastel
|
8
|
+
@pastel ||= Pastel.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_questions(questions)
|
12
|
+
questions.each do |question|
|
13
|
+
add_question(question)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_question(options = {})
|
18
|
+
(@questions ||= {})[options[:name]] = options
|
19
|
+
end
|
20
|
+
|
21
|
+
def num_questions
|
22
|
+
(@questions ||= {}).count
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
i = 1
|
27
|
+
num_questions = @questions.count
|
28
|
+
@questions.each do |question_name, question|
|
29
|
+
@name = question_name
|
30
|
+
@prompt.print pastel.bold(_('[Q %{current_number}/%{questions_total}]') % { current_number: i, questions_total: num_questions }) + ' '
|
31
|
+
@prompt.puts pastel.bold(question[:question])
|
32
|
+
@prompt.puts question[:help] if question.key?(:help)
|
33
|
+
if question.key?(:choices)
|
34
|
+
multi_select(_('-->'), per_page: question[:choices].count) do |q|
|
35
|
+
q.enum ')'
|
36
|
+
q.default(*question[:default]) if question.key?(:default)
|
37
|
+
|
38
|
+
question[:choices].each do |text, metadata|
|
39
|
+
q.choice text, metadata
|
40
|
+
end
|
41
|
+
end
|
42
|
+
else
|
43
|
+
ask(_('-->')) do |q|
|
44
|
+
q.required(question.fetch(:required, false))
|
45
|
+
|
46
|
+
if question.key?(:validate_pattern)
|
47
|
+
q.validate(question[:validate_pattern], question[:validate_message])
|
48
|
+
end
|
49
|
+
|
50
|
+
q.default(question[:default]) if question.key?(:default)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
i += 1
|
54
|
+
@prompt.puts ''
|
55
|
+
end
|
56
|
+
@answers
|
57
|
+
rescue TTY::Prompt::Reader::InputInterrupt
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module PDK
|
2
|
+
module CLI
|
3
|
+
module Util
|
4
|
+
class OptionNormalizer
|
5
|
+
def self.comma_separated_list_to_array(list, _options = {})
|
6
|
+
raise _('Error: expected comma separated list') unless OptionValidator.comma_separated_list?(list)
|
7
|
+
list.split(',').compact
|
8
|
+
end
|
9
|
+
|
10
|
+
# Parse one or more format:target pairs into report format
|
11
|
+
# specifications.
|
12
|
+
#
|
13
|
+
# Each specification is a Hash with two values:
|
14
|
+
# :method => The name of the method to call on the PDK::Report object
|
15
|
+
# to render the report.
|
16
|
+
# :target => The target to write the report to. This can be either an
|
17
|
+
# IO object that implements #write, or a String filename
|
18
|
+
# that will be opened for writing.
|
19
|
+
#
|
20
|
+
# If the target given is "stdout" or "stderr", this will convert those
|
21
|
+
# strings into the appropriate IO object.
|
22
|
+
#
|
23
|
+
# @return [Array<Hash{Symbol=>Object}>] An array of one or more report
|
24
|
+
# format specifications
|
25
|
+
def self.report_formats(formats)
|
26
|
+
formats.map do |f|
|
27
|
+
format, target = f.split(':', 2)
|
28
|
+
|
29
|
+
begin
|
30
|
+
OptionValidator.enum(format, PDK::Report.formats)
|
31
|
+
rescue ArgumentError
|
32
|
+
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid report format (%{valid})") % {
|
33
|
+
name: format,
|
34
|
+
valid: PDK::Report.formats.join(', '),
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
case target
|
39
|
+
when 'stdout'
|
40
|
+
target = $stdout
|
41
|
+
when 'stderr'
|
42
|
+
target = $stderr
|
43
|
+
when nil
|
44
|
+
target = PDK::Report.default_target
|
45
|
+
end
|
46
|
+
|
47
|
+
{ method: "write_#{format}".to_sym, target: target }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module PDK
|
2
|
+
module CLI
|
3
|
+
module Util
|
4
|
+
class OptionValidator
|
5
|
+
def self.comma_separated_list?(list, _options = {})
|
6
|
+
(list =~ %r{^[\w\-]+(?:,[\w\-]+)+$}) ? true : false
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.enum(val, valid_entries, _options = {})
|
10
|
+
vals = val.is_a?(Array) ? val : [val]
|
11
|
+
invalid_entries = vals.reject { |e| valid_entries.include?(e) }
|
12
|
+
|
13
|
+
unless invalid_entries.empty?
|
14
|
+
raise ArgumentError, _('Error: the following values are invalid: %{invalid_entries}') % { invalid_entries: invalid_entries }
|
15
|
+
end
|
16
|
+
|
17
|
+
val
|
18
|
+
end
|
19
|
+
|
20
|
+
# Validate the module name against the regular expression in the
|
21
|
+
# documentation: https://docs.puppet.com/puppet/4.10/modules_fundamentals.html#allowed-module-names
|
22
|
+
def self.valid_module_name?(string)
|
23
|
+
!(string =~ %r{\A[a-z][a-z0-9_]*\Z}).nil?
|
24
|
+
end
|
25
|
+
singleton_class.send(:alias_method, :valid_task_name?, :valid_module_name?)
|
26
|
+
|
27
|
+
# https://puppet.com/docs/puppet/5.3/custom_types.html#creating-a-type only says the name has to be a ruby symbol.
|
28
|
+
# Let's assume that only strings similar to module names can actually be resolved by the puppet language.
|
29
|
+
singleton_class.send(:alias_method, :valid_provider_name?, :valid_module_name?)
|
30
|
+
|
31
|
+
# Validate a Puppet namespace against the regular expression in the
|
32
|
+
# documentation: https://docs.puppet.com/puppet/4.10/lang_reserved.html#classes-and-defined-resource-types
|
33
|
+
def self.valid_namespace?(string)
|
34
|
+
return false if (string || '').split('::').last == 'init'
|
35
|
+
|
36
|
+
!(string =~ %r{\A([a-z][a-z0-9_]*)(::[a-z][a-z0-9_]*)*\Z}).nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
singleton_class.send(:alias_method, :valid_class_name?, :valid_namespace?)
|
40
|
+
singleton_class.send(:alias_method, :valid_defined_type_name?, :valid_namespace?)
|
41
|
+
|
42
|
+
# Validate that a class/defined type parameter matches the regular
|
43
|
+
# expression in the documentation: https://docs.puppet.com/puppet/4.10/lang_reserved.html#parameters
|
44
|
+
# The parameter should also not be a reserved word or overload
|
45
|
+
# a metaparameter.
|
46
|
+
def self.valid_param_name?(string)
|
47
|
+
reserved_words = %w[trusted facts server_facts title name].freeze
|
48
|
+
metaparams = %w[alias audit before loglevel noop notify require schedule stage subscribe tag].freeze
|
49
|
+
return false if reserved_words.include?(string) || metaparams.include?(string)
|
50
|
+
|
51
|
+
!(string =~ %r{\A[a-z][a-zA-Z0-9_]*\Z}).nil?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'pdk/util/bundler'
|
2
|
+
|
3
|
+
module PDK::CLI
|
4
|
+
@validate_cmd = @base_cmd.define_command do
|
5
|
+
name 'validate'
|
6
|
+
usage _('validate [validators] [options] [targets]')
|
7
|
+
summary _('Run static analysis tests.')
|
8
|
+
description _(
|
9
|
+
"Run metadata, Puppet, Ruby, or Tasks validation.\n\n" \
|
10
|
+
'[validators] is an optional comma-separated list of validators to use. ' \
|
11
|
+
'If not specified, all validators are used. ' \
|
12
|
+
"Note that when using PowerShell, the list of validators must be enclosed in single quotes.\n\n" \
|
13
|
+
'[targets] is an optional space-separated list of files or directories to be validated. ' \
|
14
|
+
'If not specified, validators are run against all applicable files in the module.',
|
15
|
+
)
|
16
|
+
|
17
|
+
PDK::CLI.puppet_version_options(self)
|
18
|
+
PDK::CLI.puppet_dev_option(self)
|
19
|
+
flag nil, :list, _('List all available validators.')
|
20
|
+
flag :a, 'auto-correct', _('Automatically correct problems where possible.')
|
21
|
+
flag nil, :parallel, _('Run validations in parallel.')
|
22
|
+
|
23
|
+
run do |opts, args, _cmd|
|
24
|
+
if args == ['help']
|
25
|
+
PDK::CLI.run(['validate', '--help'])
|
26
|
+
exit 0
|
27
|
+
end
|
28
|
+
|
29
|
+
validator_names = PDK::Validate.validators.map { |v| v.name }
|
30
|
+
validators = PDK::Validate.validators
|
31
|
+
targets = []
|
32
|
+
|
33
|
+
if opts[:list]
|
34
|
+
PDK.logger.info(_('Available validators: %{validator_names}') % { validator_names: validator_names.join(', ') })
|
35
|
+
exit 0
|
36
|
+
end
|
37
|
+
|
38
|
+
PDK::CLI::Util.validate_puppet_version_opts(opts)
|
39
|
+
|
40
|
+
PDK::CLI::Util.ensure_in_module!(
|
41
|
+
message: _('Code validation can only be run from inside a valid module directory'),
|
42
|
+
log_level: :info,
|
43
|
+
)
|
44
|
+
|
45
|
+
PDK::CLI::Util.module_version_check
|
46
|
+
|
47
|
+
if args[0]
|
48
|
+
# This may be a single validator, a list of validators, or a target.
|
49
|
+
if Util::OptionValidator.comma_separated_list?(args[0])
|
50
|
+
# This is a comma separated list. Treat each item as a validator.
|
51
|
+
|
52
|
+
vals = Util::OptionNormalizer.comma_separated_list_to_array(args[0])
|
53
|
+
validators = PDK::Validate.validators.select { |v| vals.include?(v.name) }
|
54
|
+
|
55
|
+
invalid = vals.reject { |v| validator_names.include?(v) }
|
56
|
+
invalid.each do |v|
|
57
|
+
PDK.logger.warn(_("Unknown validator '%{v}'. Available validators: %{validators}.") % { v: v, validators: validator_names.join(', ') })
|
58
|
+
end
|
59
|
+
else
|
60
|
+
# This is a single item. Check if it's a known validator, or otherwise treat it as a target.
|
61
|
+
val = PDK::Validate.validators.find { |v| args[0] == v.name }
|
62
|
+
if val
|
63
|
+
validators = [val]
|
64
|
+
else
|
65
|
+
targets = [args[0]]
|
66
|
+
# We now know that no validators were passed, so let the user know we're using all of them by default.
|
67
|
+
PDK.logger.info(_('Running all available validators...'))
|
68
|
+
end
|
69
|
+
end
|
70
|
+
else
|
71
|
+
PDK.logger.info(_('Running all available validators...'))
|
72
|
+
end
|
73
|
+
|
74
|
+
# Subsequent arguments are targets.
|
75
|
+
targets.concat(args[1..-1]) if args.length > 1
|
76
|
+
|
77
|
+
report = PDK::Report.new
|
78
|
+
report_formats = if opts[:format]
|
79
|
+
PDK::CLI::Util::OptionNormalizer.report_formats(opts[:format])
|
80
|
+
else
|
81
|
+
[{
|
82
|
+
method: PDK::Report.default_format,
|
83
|
+
target: PDK::Report.default_target,
|
84
|
+
}]
|
85
|
+
end
|
86
|
+
|
87
|
+
options = targets.empty? ? {} : { targets: targets }
|
88
|
+
options[:auto_correct] = true if opts.key?(:'auto-correct')
|
89
|
+
|
90
|
+
# Ensure that the bundled gems are up to date and correct Ruby is activated before running any validations.
|
91
|
+
puppet_env = PDK::CLI::Util.puppet_from_opts_or_env(opts)
|
92
|
+
PDK::Util::PuppetVersion.fetch_puppet_dev if opts.key?(:'puppet-dev')
|
93
|
+
PDK::Util::RubyVersion.use(puppet_env[:ruby_version])
|
94
|
+
|
95
|
+
options.merge!(puppet_env[:gemset])
|
96
|
+
|
97
|
+
PDK::Util::Bundler.ensure_bundle!(puppet_env[:gemset])
|
98
|
+
|
99
|
+
exit_code = 0
|
100
|
+
if opts[:parallel]
|
101
|
+
exec_group = PDK::CLI::ExecGroup.new(_('Validating module using %{num_of_threads} threads' % { num_of_threads: validators.count }), opts)
|
102
|
+
|
103
|
+
validators.each do |validator|
|
104
|
+
exec_group.register do
|
105
|
+
validator.invoke(report, options.merge(exec_group: exec_group))
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
exit_code = exec_group.exit_code
|
110
|
+
else
|
111
|
+
validators.each do |validator|
|
112
|
+
validator_exit_code = validator.invoke(report, options.dup)
|
113
|
+
exit_code = validator_exit_code if validator_exit_code != 0
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
report_formats.each do |format|
|
118
|
+
report.send(format[:method], format[:target])
|
119
|
+
end
|
120
|
+
|
121
|
+
exit exit_code
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|