pdk 1.11.1 → 1.12.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 +34 -0
- data/lib/pdk/analytics/client/google_analytics.rb +2 -2
- data/lib/pdk/cli/bundle.rb +1 -6
- data/lib/pdk/cli/exec.rb +12 -207
- data/lib/pdk/cli/exec/command.rb +233 -0
- data/lib/pdk/cli/exec/interactive_command.rb +110 -0
- data/lib/pdk/cli/exec_group.rb +1 -1
- data/lib/pdk/cli/new.rb +1 -0
- data/lib/pdk/cli/new/transport.rb +25 -0
- data/lib/pdk/cli/util.rb +1 -1
- data/lib/pdk/cli/util/option_validator.rb +4 -0
- data/lib/pdk/config.rb +8 -1
- data/lib/pdk/config/validator.rb +1 -1
- data/lib/pdk/config/value.rb +1 -1
- data/lib/pdk/generate.rb +1 -0
- data/lib/pdk/generate/module.rb +17 -7
- data/lib/pdk/generate/provider.rb +0 -5
- data/lib/pdk/generate/puppet_object.rb +16 -3
- data/lib/pdk/generate/transport.rb +87 -0
- data/lib/pdk/module/build.rb +25 -3
- data/lib/pdk/module/metadata.rb +6 -6
- data/lib/pdk/module/templatedir.rb +4 -2
- data/lib/pdk/util/git.rb +2 -2
- data/lib/pdk/util/puppet_version.rb +1 -1
- data/lib/pdk/validate/puppet/puppet_epp.rb +137 -0
- data/lib/pdk/validate/puppet_validator.rb +2 -1
- data/lib/pdk/validate/tasks/name.rb +1 -1
- data/lib/pdk/validate/yaml/syntax.rb +2 -0
- data/lib/pdk/version.rb +1 -1
- data/locales/pdk.pot +133 -83
- metadata +7 -2
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'pdk/cli/exec/command'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module CLI
|
5
|
+
module Exec
|
6
|
+
class InteractiveCommand < Command
|
7
|
+
def initialize(*argv)
|
8
|
+
@argv = argv
|
9
|
+
|
10
|
+
# Default to running things in the system context.
|
11
|
+
@context = :system
|
12
|
+
|
13
|
+
# Extra environment vars to add to base set.
|
14
|
+
@environment = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def register_spinner(_spinner, _opts = {})
|
18
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_spinner(_message, _opts = {})
|
22
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
23
|
+
end
|
24
|
+
|
25
|
+
def timeout
|
26
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
27
|
+
end
|
28
|
+
|
29
|
+
def timeout=(_val)
|
30
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
31
|
+
end
|
32
|
+
|
33
|
+
def exec_group=(_val)
|
34
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
35
|
+
end
|
36
|
+
|
37
|
+
def execute!
|
38
|
+
@resolved_env = resolved_env_for_command
|
39
|
+
|
40
|
+
if [:module, :pwd].include?(context)
|
41
|
+
mod_root = PDK::Util.module_root
|
42
|
+
|
43
|
+
unless mod_root
|
44
|
+
raise PDK::CLI::FatalError, _('Current working directory is not part of a module. (No metadata.json was found.)')
|
45
|
+
end
|
46
|
+
|
47
|
+
unless context == :pwd || Dir.pwd == mod_root
|
48
|
+
orig_workdir = Dir.pwd
|
49
|
+
Dir.chdir(mod_root)
|
50
|
+
end
|
51
|
+
|
52
|
+
result = run_process_in_clean_env!
|
53
|
+
else
|
54
|
+
result = run_process!
|
55
|
+
end
|
56
|
+
|
57
|
+
{
|
58
|
+
interactive: true,
|
59
|
+
stdout: nil,
|
60
|
+
stderr: nil,
|
61
|
+
exit_code: result[:exit_code],
|
62
|
+
duration: result[:duration],
|
63
|
+
}
|
64
|
+
ensure
|
65
|
+
Dir.chdir(orig_workdir) if orig_workdir
|
66
|
+
end
|
67
|
+
|
68
|
+
protected
|
69
|
+
|
70
|
+
# TODO: debug logging
|
71
|
+
def run_process!
|
72
|
+
command_string = argv.join(' ')
|
73
|
+
PDK.logger.debug(_("Executing '%{command}' interactively") % { command: command_string })
|
74
|
+
|
75
|
+
if context == :module
|
76
|
+
PDK.logger.debug(_('Command environment:'))
|
77
|
+
@resolved_env.each do |var, val|
|
78
|
+
PDK.logger.debug(" #{var}: #{val}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
start_time = Time.now
|
83
|
+
|
84
|
+
system(@resolved_env, *argv)
|
85
|
+
|
86
|
+
exit_code = child_status.exitstatus
|
87
|
+
duration = Time.now - start_time
|
88
|
+
|
89
|
+
PDK.logger.debug(_("Execution of '%{command}' complete (duration: \
|
90
|
+
%{duration_in_seconds}s; exit code: %{exit_code})") %
|
91
|
+
{
|
92
|
+
command: command_string,
|
93
|
+
exit_code: exit_code,
|
94
|
+
duration_in_seconds: duration,
|
95
|
+
})
|
96
|
+
|
97
|
+
{ exit_code: exit_code, duration: duration }
|
98
|
+
end
|
99
|
+
|
100
|
+
def child_status
|
101
|
+
$CHILD_STATUS
|
102
|
+
end
|
103
|
+
|
104
|
+
def stop_spinner
|
105
|
+
raise _('This method is not implemented for PDK::CLI::Exec::InteractiveCommand')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/pdk/cli/exec_group.rb
CHANGED
data/lib/pdk/cli/new.rb
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module PDK::CLI
|
2
|
+
@new_transport_cmd = @new_cmd.define_command do
|
3
|
+
name 'transport'
|
4
|
+
usage _('transport [options] <name>')
|
5
|
+
summary _('[experimental] Create a new ruby transport named <name> using given options')
|
6
|
+
|
7
|
+
run do |opts, args, _cmd|
|
8
|
+
PDK::CLI::Util.ensure_in_module!
|
9
|
+
|
10
|
+
transport_name = args[0]
|
11
|
+
module_dir = Dir.pwd
|
12
|
+
|
13
|
+
if transport_name.nil? || transport_name.empty?
|
14
|
+
puts command.help
|
15
|
+
exit 1
|
16
|
+
end
|
17
|
+
|
18
|
+
unless Util::OptionValidator.valid_transport_name?(transport_name)
|
19
|
+
raise PDK::CLI::ExitWithError, _("'%{name}' is not a valid transport name") % { name: transport_name }
|
20
|
+
end
|
21
|
+
|
22
|
+
PDK::Generate::Transport.new(module_dir, transport_name, opts).run
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pdk/cli/util.rb
CHANGED
@@ -164,7 +164,7 @@ module PDK
|
|
164
164
|
[puppet_ver_specs, pe_ver_specs].each do |offending|
|
165
165
|
next if offending.empty?
|
166
166
|
|
167
|
-
raise PDK::CLI::ExitWithError, _('You cannot specify a %{first} and %{second} at the same time') % {
|
167
|
+
raise PDK::CLI::ExitWithError, _('You cannot specify a %{first} and %{second} at the same time.') % {
|
168
168
|
first: pup_dev_spec,
|
169
169
|
second: offending.first,
|
170
170
|
}
|
@@ -28,6 +28,10 @@ module PDK
|
|
28
28
|
# Let's assume that only strings similar to module names can actually be resolved by the puppet language.
|
29
29
|
singleton_class.send(:alias_method, :valid_provider_name?, :valid_module_name?)
|
30
30
|
|
31
|
+
# The name has to be a ruby symbol.
|
32
|
+
# While overly strict, let's apply the provider and module name rules for consistency.
|
33
|
+
singleton_class.send(:alias_method, :valid_transport_name?, :valid_provider_name?)
|
34
|
+
|
31
35
|
# Validate a Puppet namespace against the regular expression in the
|
32
36
|
# documentation: https://docs.puppet.com/puppet/4.10/lang_reserved.html#classes-and-defined-resource-types
|
33
37
|
def self.valid_namespace?(string)
|
data/lib/pdk/config.rb
CHANGED
@@ -34,7 +34,14 @@ module PDK
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.bolt_analytics_config
|
37
|
-
|
37
|
+
file = File.expand_path('~/.puppetlabs/bolt/analytics.yaml')
|
38
|
+
PDK::Config::YAML.new(file: file)
|
39
|
+
rescue PDK::Config::LoadError => e
|
40
|
+
PDK.logger.debug _('Unable to load %{file}: %{message}') % {
|
41
|
+
file: file,
|
42
|
+
message: e.message,
|
43
|
+
}
|
44
|
+
PDK::Config::YAML.new
|
38
45
|
end
|
39
46
|
|
40
47
|
def self.analytics_config_path
|
data/lib/pdk/config/validator.rb
CHANGED
data/lib/pdk/config/value.rb
CHANGED
@@ -39,7 +39,7 @@ module PDK
|
|
39
39
|
#
|
40
40
|
# @return [nil]
|
41
41
|
def validate(validator)
|
42
|
-
raise ArgumentError, _('validator must be a Hash') unless validator.is_a?(Hash)
|
42
|
+
raise ArgumentError, _('`validator` must be a Hash') unless validator.is_a?(Hash)
|
43
43
|
raise ArgumentError, _('the :proc key must contain a Proc') unless validator.key?(:proc) && validator[:proc].is_a?(Proc)
|
44
44
|
raise ArgumentError, _('the :message key must contain a String') unless validator.key?(:message) && validator[:message].is_a?(String)
|
45
45
|
|
data/lib/pdk/generate.rb
CHANGED
data/lib/pdk/generate/module.rb
CHANGED
@@ -258,17 +258,27 @@ module PDK
|
|
258
258
|
|
259
259
|
interview.add_questions(questions)
|
260
260
|
|
261
|
-
|
261
|
+
if File.file?('metadata.json')
|
262
|
+
puts _(
|
263
|
+
"\nWe need to update the metadata.json file for this module, so we\'re going to ask you %{count} " \
|
264
|
+
"questions.\n",
|
265
|
+
) % {
|
266
|
+
count: interview.num_questions,
|
267
|
+
}
|
268
|
+
else
|
269
|
+
puts _(
|
270
|
+
"\nWe need to create the metadata.json file for this module, so we\'re going to ask you %{count} " \
|
271
|
+
"questions.\n",
|
272
|
+
) % {
|
273
|
+
count: interview.num_questions,
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
262
277
|
puts _(
|
263
|
-
"\nWe need to %{action} the metadata.json file for this module, so we\'re going to ask you %{count} " \
|
264
|
-
"questions.\n" \
|
265
278
|
'If the question is not applicable to this module, accept the default option ' \
|
266
279
|
'shown after each question. You can modify any answers at any time by manually updating ' \
|
267
280
|
"the metadata.json file.\n\n",
|
268
|
-
)
|
269
|
-
count: interview.num_questions,
|
270
|
-
action: action,
|
271
|
-
}
|
281
|
+
)
|
272
282
|
|
273
283
|
answers = interview.run
|
274
284
|
|
@@ -72,11 +72,6 @@ module PDK
|
|
72
72
|
def target_type_spec_path
|
73
73
|
@target_type_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'type', object_name) + '_spec.rb'
|
74
74
|
end
|
75
|
-
|
76
|
-
# transform a object name into a ruby class name
|
77
|
-
def self.class_name_from_object_name(object_name)
|
78
|
-
object_name.to_s.split('_').map(&:capitalize).join
|
79
|
-
end
|
80
75
|
end
|
81
76
|
end
|
82
77
|
end
|
@@ -81,6 +81,13 @@ module PDK
|
|
81
81
|
nil
|
82
82
|
end
|
83
83
|
|
84
|
+
# @abstract Subclass and implement {#target_device_path}. Implementations
|
85
|
+
# of this method should return a String containing the destination path
|
86
|
+
# of the device class being generated.
|
87
|
+
def target_device_path
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
84
91
|
# Retrieves the type of the object being generated, e.g. :class,
|
85
92
|
# :defined_type, etc. This is specified in the subclass' OBJECT_TYPE
|
86
93
|
# constant.
|
@@ -99,7 +106,7 @@ module PDK
|
|
99
106
|
#
|
100
107
|
# @api public
|
101
108
|
def check_preconditions
|
102
|
-
[target_object_path, target_type_path, target_spec_path, target_type_spec_path].compact.each do |target_file|
|
109
|
+
[target_object_path, target_type_path, target_device_path, target_spec_path, target_type_spec_path].compact.each do |target_file|
|
103
110
|
next unless File.exist?(target_file)
|
104
111
|
|
105
112
|
raise PDK::CLI::ExitWithError, _("Unable to generate %{object_type}; '%{file}' already exists.") % {
|
@@ -125,6 +132,7 @@ module PDK
|
|
125
132
|
|
126
133
|
render_file(target_object_path, template_path[:object], data)
|
127
134
|
render_file(target_type_path, template_path[:type], data) if template_path[:type]
|
135
|
+
render_file(target_device_path, template_path[:device], data) if template_path[:device]
|
128
136
|
render_file(target_spec_path, template_path[:spec], data) if template_path[:spec]
|
129
137
|
render_file(target_type_spec_path, template_path[:type_spec], data) if template_path[:type_spec]
|
130
138
|
end
|
@@ -219,9 +227,9 @@ module PDK
|
|
219
227
|
# TODO: refactor to a search-and-execute form instead
|
220
228
|
return # work is done # rubocop:disable Lint/NonLocalExitFromIterator
|
221
229
|
elsif template[:allow_fallback]
|
222
|
-
PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: object_type, url: template[:
|
230
|
+
PDK.logger.debug(_('Unable to find a %{type} template in %{url}; trying next template directory.') % { type: object_type, url: template[:uri] })
|
223
231
|
else
|
224
|
-
raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: object_type, url: template[:
|
232
|
+
raise PDK::CLI::FatalError, _('Unable to find the %{type} template in %{url}.') % { type: object_type, url: template[:uri] }
|
225
233
|
end
|
226
234
|
end
|
227
235
|
end
|
@@ -279,6 +287,11 @@ module PDK
|
|
279
287
|
raise PDK::CLI::FatalError, _("'%{dir}' does not contain valid Puppet module metadata: %{msg}") % { dir: module_dir, msg: e.message }
|
280
288
|
end
|
281
289
|
end
|
290
|
+
|
291
|
+
# transform a object name into a ruby class name
|
292
|
+
def self.class_name_from_object_name(object_name)
|
293
|
+
object_name.to_s.split('_').map(&:capitalize).join
|
294
|
+
end
|
282
295
|
end
|
283
296
|
end
|
284
297
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'pdk/generate/puppet_object'
|
2
|
+
|
3
|
+
module PDK
|
4
|
+
module Generate
|
5
|
+
class Transport < PuppetObject
|
6
|
+
OBJECT_TYPE = :transport
|
7
|
+
|
8
|
+
# Prepares the data needed to render the new defined type template.
|
9
|
+
#
|
10
|
+
# @return [Hash{Symbol => Object}] a hash of information that will be
|
11
|
+
# provided to the defined type and defined type spec templates during
|
12
|
+
# rendering.
|
13
|
+
def template_data
|
14
|
+
data = {
|
15
|
+
name: object_name,
|
16
|
+
transport_class: Transport.class_name_from_object_name(object_name),
|
17
|
+
}
|
18
|
+
|
19
|
+
data
|
20
|
+
end
|
21
|
+
|
22
|
+
def raise_precondition_error(error)
|
23
|
+
raise PDK::CLI::ExitWithError, _('%{error}: Creating a transport needs some local configuration in your module.' \
|
24
|
+
' Please follow the docs at https://github.com/puppetlabs/puppet-resource_api#getting-started.') % { error: error }
|
25
|
+
end
|
26
|
+
|
27
|
+
def check_preconditions
|
28
|
+
super
|
29
|
+
# These preconditions can be removed once the pdk-templates are carrying the puppet-resource_api gem by default, and have switched
|
30
|
+
# the default mock_with value.
|
31
|
+
sync_path = PDK::Util.find_upwards('.sync.yml')
|
32
|
+
if sync_path.nil?
|
33
|
+
raise_precondition_error(_('.sync.yml not found'))
|
34
|
+
end
|
35
|
+
sync = YAML.load_file(sync_path)
|
36
|
+
if !sync.is_a? Hash
|
37
|
+
raise_precondition_error(_('.sync.yml contents is not a Hash'))
|
38
|
+
elsif !sync.key? 'Gemfile'
|
39
|
+
raise_precondition_error(_('Gemfile configuration not found'))
|
40
|
+
elsif !sync['Gemfile'].key? 'optional'
|
41
|
+
raise_precondition_error(_('Gemfile.optional configuration not found'))
|
42
|
+
elsif !sync['Gemfile']['optional'].key? ':development'
|
43
|
+
raise_precondition_error(_('Gemfile.optional.:development configuration not found'))
|
44
|
+
elsif sync['Gemfile']['optional'][':development'].none? { |g| g['gem'] == 'puppet-resource_api' }
|
45
|
+
raise_precondition_error(_('puppet-resource_api not found in the Gemfile config'))
|
46
|
+
elsif !sync.key? 'spec/spec_helper.rb'
|
47
|
+
raise_precondition_error(_('spec/spec_helper.rb configuration not found'))
|
48
|
+
elsif !sync['spec/spec_helper.rb'].key? 'mock_with'
|
49
|
+
raise_precondition_error(_('spec/spec_helper.rb.mock_with configuration not found'))
|
50
|
+
elsif !sync['spec/spec_helper.rb']['mock_with'] == ':rspec'
|
51
|
+
raise_precondition_error(_('spec/spec_helper.rb.mock_with not set to \':rspec\''))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [String] the path where the new transport will be written.
|
56
|
+
def target_object_path
|
57
|
+
@target_object_path ||= File.join(module_dir, 'lib', 'puppet', 'transport', object_name) + '.rb'
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [String] the path where the new schema will be written.
|
61
|
+
def target_type_path
|
62
|
+
@target_type_path ||= File.join(module_dir, 'lib', 'puppet', 'transport', 'schema', object_name) + '.rb'
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [String] the path where the deviceshim for the transport will be written.
|
66
|
+
def target_device_path
|
67
|
+
@target_device_path ||= File.join(module_dir, 'lib', 'puppet', 'util', 'network_device', object_name, 'device.rb')
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [String] the path where the tests for the new transport
|
71
|
+
# will be written.
|
72
|
+
def target_spec_path
|
73
|
+
@target_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'transport', object_name) + '_spec.rb'
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [String] the path where the tests for the new schema will be written.
|
77
|
+
def target_type_spec_path
|
78
|
+
@target_type_spec_path ||= File.join(module_dir, 'spec', 'unit', 'puppet', 'transport', 'schema', object_name) + '_spec.rb'
|
79
|
+
end
|
80
|
+
|
81
|
+
# transform a object name into a ruby class name
|
82
|
+
def self.class_name_from_object_name(object_name)
|
83
|
+
object_name.to_s.split('_').map(&:capitalize).join
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/pdk/module/build.rb
CHANGED
@@ -125,7 +125,7 @@ module PDK
|
|
125
125
|
end
|
126
126
|
rescue ArgumentError => e
|
127
127
|
raise PDK::CLI::ExitWithError, _(
|
128
|
-
'%{message}
|
128
|
+
'%{message} Rename the file or exclude it from the package ' \
|
129
129
|
'by adding it to the .pdkignore file in your module.',
|
130
130
|
) % { message: e.message }
|
131
131
|
end
|
@@ -220,8 +220,30 @@ module PDK
|
|
220
220
|
FileUtils.rm_f(package_file)
|
221
221
|
|
222
222
|
Dir.chdir(target_dir) do
|
223
|
-
|
224
|
-
|
223
|
+
begin
|
224
|
+
gz = Zlib::GzipWriter.new(File.open(package_file, 'wb'))
|
225
|
+
tar = Minitar::Output.new(gz)
|
226
|
+
Find.find(release_name) do |entry|
|
227
|
+
entry_meta = {
|
228
|
+
name: entry,
|
229
|
+
}
|
230
|
+
|
231
|
+
orig_mode = File.stat(entry).mode
|
232
|
+
min_mode = Minitar.dir?(entry) ? 0o755 : 0o644
|
233
|
+
|
234
|
+
entry_meta[:mode] = orig_mode | min_mode
|
235
|
+
|
236
|
+
if entry_meta[:mode] != orig_mode
|
237
|
+
PDK.logger.debug(_('Updated permissions of packaged \'%{entry}\' to %{new_mode}') % {
|
238
|
+
entry: entry,
|
239
|
+
new_mode: (entry_meta[:mode] & 0o7777).to_s(8),
|
240
|
+
})
|
241
|
+
end
|
242
|
+
|
243
|
+
Minitar.pack_file(entry_meta, tar)
|
244
|
+
end
|
245
|
+
ensure
|
246
|
+
tar.close
|
225
247
|
end
|
226
248
|
end
|
227
249
|
end
|