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