pdk-akerl 1.8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|