pdk 1.14.1 → 1.18.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +155 -2
  3. data/lib/pdk.rb +28 -19
  4. data/lib/pdk/answer_file.rb +2 -95
  5. data/lib/pdk/bolt.rb +19 -0
  6. data/lib/pdk/cli.rb +4 -5
  7. data/lib/pdk/cli/bundle.rb +5 -1
  8. data/lib/pdk/cli/config.rb +3 -1
  9. data/lib/pdk/cli/config/get.rb +3 -1
  10. data/lib/pdk/cli/console.rb +1 -1
  11. data/lib/pdk/cli/convert.rb +16 -10
  12. data/lib/pdk/cli/exec.rb +2 -1
  13. data/lib/pdk/cli/exec/command.rb +45 -4
  14. data/lib/pdk/cli/exec_group.rb +78 -43
  15. data/lib/pdk/cli/get.rb +20 -0
  16. data/lib/pdk/cli/get/config.rb +24 -0
  17. data/lib/pdk/cli/module/build.rb +1 -1
  18. data/lib/pdk/cli/module/generate.rb +1 -1
  19. data/lib/pdk/cli/new/class.rb +2 -2
  20. data/lib/pdk/cli/new/defined_type.rb +2 -2
  21. data/lib/pdk/cli/new/provider.rb +2 -2
  22. data/lib/pdk/cli/new/task.rb +2 -2
  23. data/lib/pdk/cli/new/test.rb +2 -2
  24. data/lib/pdk/cli/new/transport.rb +2 -2
  25. data/lib/pdk/cli/release.rb +192 -0
  26. data/lib/pdk/cli/release/prep.rb +39 -0
  27. data/lib/pdk/cli/release/publish.rb +40 -0
  28. data/lib/pdk/cli/remove.rb +20 -0
  29. data/lib/pdk/cli/remove/config.rb +80 -0
  30. data/lib/pdk/cli/set.rb +20 -0
  31. data/lib/pdk/cli/set/config.rb +119 -0
  32. data/lib/pdk/cli/update.rb +18 -8
  33. data/lib/pdk/cli/util.rb +7 -3
  34. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  35. data/lib/pdk/cli/validate.rb +26 -44
  36. data/lib/pdk/config.rb +265 -8
  37. data/lib/pdk/config/ini_file.rb +183 -0
  38. data/lib/pdk/config/ini_file_setting.rb +39 -0
  39. data/lib/pdk/config/namespace.rb +26 -6
  40. data/lib/pdk/config/setting.rb +3 -2
  41. data/lib/pdk/context.rb +99 -0
  42. data/lib/pdk/context/control_repo.rb +60 -0
  43. data/lib/pdk/context/module.rb +28 -0
  44. data/lib/pdk/context/none.rb +22 -0
  45. data/lib/pdk/control_repo.rb +90 -0
  46. data/lib/pdk/generate.rb +1 -0
  47. data/lib/pdk/generate/defined_type.rb +25 -32
  48. data/lib/pdk/generate/module.rb +42 -35
  49. data/lib/pdk/generate/provider.rb +16 -65
  50. data/lib/pdk/generate/puppet_class.rb +25 -31
  51. data/lib/pdk/generate/puppet_object.rb +84 -189
  52. data/lib/pdk/generate/resource_api_object.rb +55 -0
  53. data/lib/pdk/generate/task.rb +28 -46
  54. data/lib/pdk/generate/transport.rb +21 -75
  55. data/lib/pdk/module.rb +1 -1
  56. data/lib/pdk/module/build.rb +38 -25
  57. data/lib/pdk/module/convert.rb +61 -42
  58. data/lib/pdk/module/metadata.rb +1 -3
  59. data/lib/pdk/module/release.rb +254 -0
  60. data/lib/pdk/module/update.rb +24 -16
  61. data/lib/pdk/module/update_manager.rb +8 -1
  62. data/lib/pdk/report.rb +18 -12
  63. data/lib/pdk/report/event.rb +6 -3
  64. data/lib/pdk/template.rb +59 -0
  65. data/lib/pdk/template/fetcher.rb +98 -0
  66. data/lib/pdk/template/fetcher/git.rb +85 -0
  67. data/lib/pdk/template/fetcher/local.rb +28 -0
  68. data/lib/pdk/template/renderer.rb +96 -0
  69. data/lib/pdk/template/renderer/v1.rb +25 -0
  70. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -0
  71. data/lib/pdk/template/renderer/v1/renderer.rb +132 -0
  72. data/lib/pdk/template/renderer/v1/template_file.rb +102 -0
  73. data/lib/pdk/template/template_dir.rb +67 -0
  74. data/lib/pdk/tests/unit.rb +5 -0
  75. data/lib/pdk/util.rb +55 -45
  76. data/lib/pdk/util/bundler.rb +9 -9
  77. data/lib/pdk/util/changelog_generator.rb +120 -0
  78. data/lib/pdk/util/env.rb +28 -11
  79. data/lib/pdk/util/filesystem.rb +62 -2
  80. data/lib/pdk/util/git.rb +60 -8
  81. data/lib/pdk/util/json_finder.rb +84 -0
  82. data/lib/pdk/util/puppet_strings.rb +3 -3
  83. data/lib/pdk/util/puppet_version.rb +4 -5
  84. data/lib/pdk/util/ruby_version.rb +9 -6
  85. data/lib/pdk/util/template_uri.rb +60 -48
  86. data/lib/pdk/util/version.rb +4 -4
  87. data/lib/pdk/validate.rb +79 -25
  88. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  89. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  90. data/lib/pdk/validate/external_command_validator.rb +208 -0
  91. data/lib/pdk/validate/internal_ruby_validator.rb +100 -0
  92. data/lib/pdk/validate/invokable_validator.rb +215 -0
  93. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -0
  94. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -0
  95. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  96. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -0
  97. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  98. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -0
  99. data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -0
  100. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -0
  101. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  102. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -0
  103. data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -0
  104. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  105. data/lib/pdk/validate/validator.rb +118 -0
  106. data/lib/pdk/validate/validator_group.rb +104 -0
  107. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -0
  108. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  109. data/lib/pdk/version.rb +1 -1
  110. data/locales/pdk.pot +755 -319
  111. metadata +66 -24
  112. data/lib/pdk/module/templatedir.rb +0 -391
  113. data/lib/pdk/template_file.rb +0 -96
  114. data/lib/pdk/validate/base_validator.rb +0 -215
  115. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -82
  116. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -111
  117. data/lib/pdk/validate/metadata_validator.rb +0 -26
  118. data/lib/pdk/validate/puppet/puppet_epp.rb +0 -137
  119. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -64
  120. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -137
  121. data/lib/pdk/validate/puppet_validator.rb +0 -26
  122. data/lib/pdk/validate/ruby/rubocop.rb +0 -72
  123. data/lib/pdk/validate/ruby_validator.rb +0 -26
  124. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -130
  125. data/lib/pdk/validate/tasks/name.rb +0 -90
  126. data/lib/pdk/validate/tasks_validator.rb +0 -29
  127. data/lib/pdk/validate/yaml/syntax.rb +0 -125
  128. data/lib/pdk/validate/yaml_validator.rb +0 -28
@@ -0,0 +1,55 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Generate
5
+ # An abstract class for generated objects that require the Puppet Resource API Gem
6
+ #
7
+ # @abstract
8
+ class ResourceAPIObject < PuppetObject
9
+ #:nocov: This is tested in spec/acceptance/new_transport_spec.rb
10
+ # @see PDK::Generate::PuppetObject.check_preconditions
11
+ def check_preconditions
12
+ super
13
+ # Note that these preconditions are only applicable to the current (V1) template rendering layout and will need to be changed
14
+ # when additional template renderers are introduced.
15
+ #
16
+ # These preconditions can be removed once the pdk-templates are carrying the puppet-resource_api gem by default, and have switched
17
+ # the default mock_with value.
18
+ sync_path = PDK::Util.find_upwards('.sync.yml')
19
+ if sync_path.nil?
20
+ raise_precondition_error(_('.sync.yml not found'))
21
+ end
22
+ sync = YAML.load_file(sync_path)
23
+ if !sync.is_a? Hash
24
+ raise_precondition_error(_('.sync.yml contents is not a Hash'))
25
+ elsif !sync.key? 'Gemfile'
26
+ raise_precondition_error(_('Gemfile configuration not found'))
27
+ elsif !sync['Gemfile'].key? 'optional'
28
+ raise_precondition_error(_('Gemfile.optional configuration not found'))
29
+ elsif !sync['Gemfile']['optional'].key? ':development'
30
+ raise_precondition_error(_('Gemfile.optional.:development configuration not found'))
31
+ elsif sync['Gemfile']['optional'][':development'].none? { |g| g['gem'] == 'puppet-resource_api' }
32
+ raise_precondition_error(_('puppet-resource_api not found in the Gemfile config'))
33
+ elsif !sync.key? 'spec/spec_helper.rb'
34
+ raise_precondition_error(_('spec/spec_helper.rb configuration not found'))
35
+ elsif !sync['spec/spec_helper.rb'].key? 'mock_with'
36
+ raise_precondition_error(_('spec/spec_helper.rb.mock_with configuration not found'))
37
+ elsif !sync['spec/spec_helper.rb']['mock_with'] == ':rspec'
38
+ raise_precondition_error(_('spec/spec_helper.rb.mock_with not set to \':rspec\''))
39
+ end
40
+ end
41
+
42
+ # Helper method to raise an error if the Resource API is not available
43
+ #
44
+ # @api private
45
+ def raise_precondition_error(error)
46
+ raise PDK::CLI::ExitWithError, _('%{error}: Creating a %{thing_name} needs some local configuration in your module.' \
47
+ ' Please follow the docs at https://puppet.com/docs/puppet/latest/create_types_and_providers_resource_api.html') % {
48
+ thing_name: friendly_name,
49
+ error: error,
50
+ }
51
+ end
52
+ #:nocov:
53
+ end
54
+ end
55
+ end
@@ -3,44 +3,21 @@ require 'pdk'
3
3
  module PDK
4
4
  module Generate
5
5
  class Task < PuppetObject
6
- OBJECT_TYPE = :task
6
+ def friendly_name
7
+ 'Task'
8
+ end
7
9
 
8
- # Prepares the data needed to render the new task template.
9
- #
10
- # @return [Hash{Symbol => Object}] a hash of information that will be
11
- # provided to the task template during rendering. Additionally, this hash
12
- # (with the :name key removed) makes up the task metadata.
13
- def template_data
10
+ def template_files
11
+ return {} if spec_only?
14
12
  {
15
- name: object_name,
16
- puppet_task_version: 1,
17
- supports_noop: false,
18
- description: options.fetch(:description, 'A short description of this task'),
19
- parameters: {},
13
+ 'task.erb' => File.join('tasks', task_name + '.sh'),
20
14
  }
21
15
  end
22
16
 
23
- # Calculates the path to the file where the new task will be written.
24
- #
25
- # @return [String] the path to the task file.
26
- def target_object_path
27
- @target_object_path ||= File.join(module_dir, 'tasks', "#{task_name}.sh")
28
- end
29
-
30
- # Calculates the path to the file where the tests for the new task will
31
- # be written.
32
- #
33
- # @return [nil] as there is currently no test framework for Tasks.
34
- def target_spec_path
35
- nil
36
- end
37
-
38
- def run
39
- check_if_task_already_exists
40
-
41
- super
42
-
43
- write_task_metadata
17
+ def template_data
18
+ {
19
+ name: object_name,
20
+ }
44
21
  end
45
22
 
46
23
  # Checks that the task has not already been defined with a different
@@ -48,30 +25,26 @@ module PDK
48
25
  #
49
26
  # @raise [PDK::CLI::ExitWithError] if files with the same name as the
50
27
  # task exist in the <module>/tasks/ directory
51
- #
52
- # @api private
53
- def check_if_task_already_exists
28
+ def check_preconditions
29
+ super
30
+
54
31
  error = _("A task named '%{name}' already exists in this module; defined in %{file}")
55
32
  allowed_extensions = %w[.md .conf]
56
33
 
57
- Dir.glob(File.join(module_dir, 'tasks', "#{task_name}.*")).each do |file|
34
+ PDK::Util::Filesystem.glob(File.join(context.root_path, 'tasks', task_name + '.*')).each do |file|
58
35
  next if allowed_extensions.include?(File.extname(file))
59
36
 
60
37
  raise PDK::CLI::ExitWithError, error % { name: task_name, file: file }
61
38
  end
62
39
  end
63
40
 
64
- # Writes the <module>/tasks/<task_name>.json metadata file for the task.
65
- #
66
- # @api private
67
- def write_task_metadata
68
- write_file(File.join(module_dir, 'tasks', "#{task_name}.json")) do
69
- task_metadata = template_data.dup
70
- task_metadata.delete(:name)
71
- JSON.pretty_generate(task_metadata)
72
- end
41
+ def non_template_files
42
+ task_metadata_file = File.join('tasks', task_name + '.json')
43
+ { task_metadata_file => JSON.pretty_generate(task_metadata) }
73
44
  end
74
45
 
46
+ private
47
+
75
48
  # Calculates the file name of the task files ('init' if the task has the
76
49
  # same name as the module, otherwise use the specified task name).
77
50
  #
@@ -81,6 +54,15 @@ module PDK
81
54
  def task_name
82
55
  (object_name == module_name) ? 'init' : object_name
83
56
  end
57
+
58
+ def task_metadata
59
+ {
60
+ puppet_task_version: 1,
61
+ supports_noop: false,
62
+ description: options.fetch(:description, 'A short description of this task'),
63
+ parameters: {},
64
+ }
65
+ end
84
66
  end
85
67
  end
86
68
  end
@@ -2,85 +2,31 @@ require 'pdk'
2
2
 
3
3
  module PDK
4
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'
5
+ class Transport < ResourceAPIObject
6
+ def friendly_name
7
+ 'Resource API Transport'.freeze
58
8
  end
59
9
 
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'
10
+ def template_files
11
+ # Note : Due to how the V1 templates work, the names of the source template files may be mismatched to
12
+ # their destination, e.g. transport_type.erb is really a transport schema
13
+ files = {
14
+ 'transport_spec.erb' => File.join('spec', 'unit', 'puppet', 'transport', object_name) + '_spec.rb',
15
+ 'transport_type_spec.erb' => File.join('spec', 'unit', 'puppet', 'transport', 'schema', object_name) + '_spec.rb',
16
+ }
17
+ return files if spec_only?
18
+ files.merge(
19
+ 'transport.erb' => File.join('lib', 'puppet', 'transport', object_name) + '.rb',
20
+ 'transport_device.erb' => File.join('lib', 'puppet', 'util', 'network_device', object_name, 'device.rb'),
21
+ 'transport_type.erb' => File.join('lib', 'puppet', 'transport', 'schema', object_name) + '.rb',
22
+ )
79
23
  end
80
24
 
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
25
+ def template_data
26
+ {
27
+ name: object_name,
28
+ transport_class: class_name_from_object_name(object_name),
29
+ }
84
30
  end
85
31
  end
86
32
  end
@@ -3,7 +3,7 @@ module PDK
3
3
  autoload :Build, 'pdk/module/build'
4
4
  autoload :Convert, 'pdk/module/convert'
5
5
  autoload :Metadata, 'pdk/module/metadata'
6
- autoload :TemplateDir, 'pdk/module/templatedir'
6
+ autoload :Release, 'pdk/module/release'
7
7
  autoload :UpdateManager, 'pdk/module/update_manager'
8
8
  autoload :Update, 'pdk/module/update'
9
9
 
@@ -11,8 +11,8 @@ module PDK
11
11
  attr_reader :target_dir
12
12
 
13
13
  def initialize(options = {})
14
- @module_dir = File.expand_path(options[:module_dir] || Dir.pwd)
15
- @target_dir = File.expand_path(options[:'target-dir'] || File.join(module_dir, 'pkg'))
14
+ @module_dir = PDK::Util::Filesystem.expand_path(options[:module_dir] || Dir.pwd)
15
+ @target_dir = PDK::Util::Filesystem.expand_path(options[:'target-dir'] || File.join(module_dir, 'pkg'))
16
16
  end
17
17
 
18
18
  # Read and parse the values from metadata.json for the module that is
@@ -47,7 +47,7 @@ module PDK
47
47
  # Verify if there is an existing package in the target directory and prompts
48
48
  # the user if they want to overwrite it.
49
49
  def package_already_exists?
50
- File.exist? package_file
50
+ PDK::Util::Filesystem.exist?(package_file)
51
51
  end
52
52
 
53
53
  # Check if the module is PDK Compatible. If not, then prompt the user if
@@ -67,20 +67,16 @@ module PDK
67
67
  #
68
68
  # If the directory already exists, remove it first.
69
69
  def create_build_dir
70
- require 'fileutils'
71
-
72
70
  cleanup_build_dir
73
71
 
74
- FileUtils.mkdir_p(build_dir)
72
+ PDK::Util::Filesystem.mkdir_p(build_dir)
75
73
  end
76
74
 
77
75
  # Remove the temporary build directory and all its contents from disk.
78
76
  #
79
77
  # @return nil.
80
78
  def cleanup_build_dir
81
- require 'fileutils'
82
-
83
- FileUtils.rm_rf(build_dir, secure: true)
79
+ PDK::Util::Filesystem.rm_rf(build_dir, secure: true)
84
80
  end
85
81
 
86
82
  # Combine the module name and version into a Forge-compatible dash
@@ -115,18 +111,19 @@ module PDK
115
111
  # @return nil.
116
112
  def stage_path(path)
117
113
  require 'pathname'
118
- require 'fileutils'
119
114
 
120
115
  relative_path = Pathname.new(path).relative_path_from(Pathname.new(module_dir))
121
116
  dest_path = File.join(build_dir, relative_path)
122
117
 
123
- if File.directory?(path)
124
- FileUtils.mkdir_p(dest_path, mode: File.stat(path).mode)
125
- elsif File.symlink?(path)
118
+ validate_path_encoding!(relative_path.to_path)
119
+
120
+ if PDK::Util::Filesystem.directory?(path)
121
+ PDK::Util::Filesystem.mkdir_p(dest_path, mode: PDK::Util::Filesystem.stat(path).mode)
122
+ elsif PDK::Util::Filesystem.symlink?(path)
126
123
  warn_symlink(path)
127
124
  else
128
125
  validate_ustar_path!(relative_path.to_path)
129
- FileUtils.cp(path, dest_path, preserve: true)
126
+ PDK::Util::Filesystem.cp(path, dest_path, preserve: true)
130
127
  end
131
128
  rescue ArgumentError => e
132
129
  raise PDK::CLI::ExitWithError, _(
@@ -142,7 +139,7 @@ module PDK
142
139
  #
143
140
  # @return [Boolean] true if the path matches and should be ignored.
144
141
  def ignored_path?(path)
145
- path = path.to_s + '/' if File.directory?(path)
142
+ path = path.to_s + '/' if PDK::Util::Filesystem.directory?(path)
146
143
 
147
144
  !ignored_files.match_paths([path], module_dir).empty?
148
145
  end
@@ -217,6 +214,27 @@ module PDK
217
214
  ) % { path: path }
218
215
  end
219
216
 
217
+ # Checks if the path contains any non-ASCII characters.
218
+ #
219
+ # Java will throw an error when it encounters a path containing
220
+ # characters that are not supported by the hosts locale. In order to
221
+ # maximise compatibility we limit the paths to contain only ASCII
222
+ # characters, which should be part of any locale character set.
223
+ #
224
+ # @param path [String] the relative path to be added to the tar file.
225
+ #
226
+ # @raise [ArgumentError] if the path contains non-ASCII characters.
227
+ #
228
+ # @return [nil]
229
+ def validate_path_encoding!(path)
230
+ return unless path =~ %r{[^\x00-\x7F]}
231
+
232
+ raise ArgumentError, _(
233
+ "'%{path}' can only include ASCII characters in its path or " \
234
+ 'filename in order to be compatible with a wide range of hosts.',
235
+ ) % { path: path }
236
+ end
237
+
220
238
  # Creates a gzip compressed tarball of the build directory.
221
239
  #
222
240
  # If the destination package already exists, it will be removed before
@@ -224,23 +242,22 @@ module PDK
224
242
  #
225
243
  # @return nil.
226
244
  def build_package
227
- require 'fileutils'
228
245
  require 'zlib'
229
246
  require 'minitar'
230
247
  require 'find'
231
248
 
232
- FileUtils.rm_f(package_file)
249
+ PDK::Util::Filesystem.rm_f(package_file)
233
250
 
234
251
  Dir.chdir(target_dir) do
235
252
  begin
236
- gz = Zlib::GzipWriter.new(File.open(package_file, 'wb'))
253
+ gz = Zlib::GzipWriter.new(File.open(package_file, 'wb')) # rubocop:disable PDK/FileOpen
237
254
  tar = Minitar::Output.new(gz)
238
255
  Find.find(release_name) do |entry|
239
256
  entry_meta = {
240
257
  name: entry,
241
258
  }
242
259
 
243
- orig_mode = File.stat(entry).mode
260
+ orig_mode = PDK::Util::Filesystem.stat(entry).mode
244
261
  min_mode = Minitar.dir?(entry) ? 0o755 : 0o644
245
262
 
246
263
  entry_meta[:mode] = orig_mode | min_mode
@@ -272,7 +289,7 @@ module PDK
272
289
  File.join(module_dir, '.pdkignore'),
273
290
  File.join(module_dir, '.pmtignore'),
274
291
  File.join(module_dir, '.gitignore'),
275
- ].find { |file| File.file?(file) && File.readable?(file) }
292
+ ].find { |file| PDK::Util::Filesystem.file?(file) && PDK::Util::Filesystem.readable?(file) }
276
293
  end
277
294
 
278
295
  # Instantiate a new PathSpec class and populate it with the pattern(s) of
@@ -288,11 +305,7 @@ module PDK
288
305
  ignored = if ignore_file.nil?
289
306
  PathSpec.new
290
307
  else
291
- fd = File.open(ignore_file, 'rb:UTF-8')
292
- data = fd.read
293
- fd.close
294
-
295
- PathSpec.new(data)
308
+ PathSpec.new(PDK::Util::Filesystem.read_file(ignore_file, open_args: 'rb:UTF-8'))
296
309
  end
297
310
 
298
311
  if File.realdirpath(target_dir).start_with?(File.realdirpath(module_dir))
@@ -3,13 +3,16 @@ require 'pdk'
3
3
  module PDK
4
4
  module Module
5
5
  class Convert
6
- def self.invoke(options)
7
- new(options).run
6
+ def self.invoke(module_dir, options)
7
+ new(module_dir, options).run
8
8
  end
9
9
 
10
+ attr_reader :module_dir
11
+
10
12
  attr_reader :options
11
13
 
12
- def initialize(options = {})
14
+ def initialize(module_dir, options = {})
15
+ @module_dir = module_dir
13
16
  @options = options
14
17
  end
15
18
 
@@ -23,6 +26,7 @@ module PDK
23
26
  unless update_manager.changes?
24
27
  if adding_tests?
25
28
  add_tests!
29
+ print_result 'Convert completed'
26
30
  else
27
31
  require 'pdk/report'
28
32
 
@@ -50,18 +54,15 @@ module PDK
50
54
  return unless continue
51
55
  end
52
56
 
53
- # Remove these files straight away as these changes are not something that the user needs to review.
54
- if needs_bundle_update?
55
- update_manager.unlink_file('Gemfile.lock')
56
- update_manager.unlink_file(File.join('.bundle', 'config'))
57
- end
57
+ # Remove these files straight away as these changes are not something
58
+ # that the user needs to review.
59
+ update_manager.unlink_file('Gemfile.lock')
60
+ update_manager.unlink_file(File.join('.bundle', 'config'))
58
61
 
59
62
  update_manager.sync_changes!
60
63
 
61
- if needs_bundle_update?
62
- require 'pdk/util/bundler'
63
- PDK::Util::Bundler.ensure_bundle!
64
- end
64
+ require 'pdk/util/bundler'
65
+ PDK::Util::Bundler.ensure_bundle!
65
66
 
66
67
  add_tests! if adding_tests?
67
68
 
@@ -85,42 +86,59 @@ module PDK
85
86
  end
86
87
 
87
88
  def missing_tests?
88
- test_generators.any? { |gen| gen.can_run? }
89
+ !available_test_generators.empty?
89
90
  end
90
91
 
91
- def test_generators
92
+ def available_test_generators
93
+ # Only select generators which can run and have no pre-existing files
94
+ test_generators.select do |gen|
95
+ if gen.can_run?
96
+ gen.template_files.none? { |_, dst_path| PDK::Util::Filesystem.exist?(File.join(gen.context.root_path, dst_path)) }
97
+ else
98
+ false
99
+ end
100
+ end
101
+ end
102
+
103
+ def test_generators(context = PDK.context)
92
104
  return @test_generators unless @test_generators.nil?
93
105
  require 'pdk/util/puppet_strings'
94
106
 
95
107
  test_gens = PDK::Util::PuppetStrings.all_objects.map do |generator, objects|
96
108
  (objects || []).map do |obj|
97
- generator.new(Dir.pwd, obj['name'], spec_only: true)
109
+ generator.new(context, obj['name'], spec_only: true)
98
110
  end
99
111
  end
100
112
 
101
113
  @test_generators = test_gens.flatten
102
114
  end
103
115
 
104
- def add_tests!
105
- test_generators.each do |gen|
106
- gen.run if gen.can_run?
116
+ def stage_tests!(manager)
117
+ available_test_generators.each do |gen|
118
+ gen.stage_changes(manager)
107
119
  end
120
+ manager
108
121
  end
109
122
 
110
- def needs_bundle_update?
111
- update_manager.changed?('Gemfile')
123
+ def add_tests!
124
+ update_manager.clear!
125
+ stage_tests!(update_manager)
126
+
127
+ if update_manager.changes?
128
+ update_manager.sync_changes!
129
+ print_summary
130
+ else
131
+ PDK::Report.default_target.puts(_('No test changes required.'))
132
+ end
112
133
  end
113
134
 
114
- def stage_changes!
115
- require 'pdk/module/templatedir'
135
+ def stage_changes!(context = PDK.context)
116
136
  require 'pdk/util/filesystem'
117
137
 
118
- metadata_path = 'metadata.json'
119
-
120
- PDK::Module::TemplateDir.new(template_uri, nil, true) do |templates|
121
- new_metadata = update_metadata(metadata_path, templates.metadata)
122
- templates.module_metadata = new_metadata.data unless new_metadata.nil?
138
+ metadata_path = File.join(module_dir, 'metadata.json')
123
139
 
140
+ PDK::Template.with(template_uri, context) do |template_dir|
141
+ new_metadata = update_metadata(metadata_path, template_dir.metadata)
124
142
  if options[:noop] && new_metadata.nil?
125
143
  update_manager.add_file(metadata_path, '')
126
144
  elsif PDK::Util::Filesystem.file?(metadata_path)
@@ -129,21 +147,26 @@ module PDK
129
147
  update_manager.add_file(metadata_path, new_metadata.to_json)
130
148
  end
131
149
 
132
- templates.render do |file_path, file_content, file_status|
150
+ # new_metadata == nil when creating a new module but with --noop@
151
+ module_name = new_metadata.nil? ? 'new-module' : new_metadata.data['name']
152
+ metadata_for_render = new_metadata.nil? ? {} : new_metadata.data
153
+
154
+ template_dir.render_new_module(module_name, metadata_for_render) do |relative_file_path, file_content, file_status|
155
+ absolute_file_path = File.join(module_dir, relative_file_path)
133
156
  case file_status
134
157
  when :unmanage
135
- PDK.logger.debug(_("skipping '%{path}'") % { path: file_path })
158
+ PDK.logger.debug(_("skipping '%{path}'") % { path: absolute_file_path })
136
159
  when :delete
137
- update_manager.remove_file(file_path)
160
+ update_manager.remove_file(absolute_file_path)
138
161
  when :init
139
- if convert? && !PDK::Util::Filesystem.exist?(file_path)
140
- update_manager.add_file(file_path, file_content)
162
+ if convert? && !PDK::Util::Filesystem.exist?(absolute_file_path)
163
+ update_manager.add_file(absolute_file_path, file_content)
141
164
  end
142
165
  when :manage
143
- if PDK::Util::Filesystem.exist?(file_path)
144
- update_manager.modify_file(file_path, file_content)
166
+ if PDK::Util::Filesystem.exist?(absolute_file_path)
167
+ update_manager.modify_file(absolute_file_path, file_content)
145
168
  else
146
- update_manager.add_file(file_path, file_content)
169
+ update_manager.add_file(absolute_file_path, file_content)
147
170
  end
148
171
  end
149
172
  end
@@ -251,13 +274,9 @@ module PDK
251
274
  def full_report(path)
252
275
  require 'pdk/report'
253
276
 
254
- File.open(path, 'w') do |f|
255
- f.write("/* Report generated by PDK at #{Time.now} */")
256
- update_manager.changes[:modified].each do |_, diff|
257
- f.write("\n\n\n" + diff)
258
- end
259
- f.write("\n")
260
- end
277
+ report = ["/* Report generated by PDK at #{Time.now} */"]
278
+ report.concat(update_manager.changes[:modified].map { |_, diff| "\n\n\n#{diff}" })
279
+ PDK::Util::Filesystem.write_file(path, report.join)
261
280
  PDK::Report.default_target.puts(_("\nYou can find a report of differences in %{path}.\n\n") % { path: path })
262
281
  end
263
282