pdk 1.9.0 → 3.2.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.
Files changed (163) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +744 -711
  3. data/README.md +23 -21
  4. data/lib/pdk/answer_file.rb +3 -112
  5. data/lib/pdk/bolt.rb +20 -0
  6. data/lib/pdk/cli/build.rb +51 -54
  7. data/lib/pdk/cli/bundle.rb +33 -29
  8. data/lib/pdk/cli/console.rb +148 -0
  9. data/lib/pdk/cli/convert.rb +46 -37
  10. data/lib/pdk/cli/env.rb +51 -0
  11. data/lib/pdk/cli/errors.rb +4 -3
  12. data/lib/pdk/cli/exec/command.rb +285 -0
  13. data/lib/pdk/cli/exec/interactive_command.rb +109 -0
  14. data/lib/pdk/cli/exec.rb +32 -201
  15. data/lib/pdk/cli/exec_group.rb +79 -43
  16. data/lib/pdk/cli/get/config.rb +26 -0
  17. data/lib/pdk/cli/get.rb +22 -0
  18. data/lib/pdk/cli/new/class.rb +20 -22
  19. data/lib/pdk/cli/new/defined_type.rb +21 -21
  20. data/lib/pdk/cli/new/fact.rb +27 -0
  21. data/lib/pdk/cli/new/function.rb +27 -0
  22. data/lib/pdk/cli/new/module.rb +40 -29
  23. data/lib/pdk/cli/new/provider.rb +18 -18
  24. data/lib/pdk/cli/new/task.rb +23 -22
  25. data/lib/pdk/cli/new/test.rb +52 -0
  26. data/lib/pdk/cli/new/transport.rb +27 -0
  27. data/lib/pdk/cli/new.rb +15 -9
  28. data/lib/pdk/cli/release/prep.rb +39 -0
  29. data/lib/pdk/cli/release/publish.rb +46 -0
  30. data/lib/pdk/cli/release.rb +185 -0
  31. data/lib/pdk/cli/remove/config.rb +83 -0
  32. data/lib/pdk/cli/remove.rb +22 -0
  33. data/lib/pdk/cli/set/config.rb +121 -0
  34. data/lib/pdk/cli/set.rb +22 -0
  35. data/lib/pdk/cli/test/unit.rb +71 -69
  36. data/lib/pdk/cli/test.rb +9 -8
  37. data/lib/pdk/cli/update.rb +38 -21
  38. data/lib/pdk/cli/util/command_redirector.rb +13 -3
  39. data/lib/pdk/cli/util/interview.rb +25 -9
  40. data/lib/pdk/cli/util/option_normalizer.rb +6 -6
  41. data/lib/pdk/cli/util/option_validator.rb +19 -9
  42. data/lib/pdk/cli/util/spinner.rb +13 -0
  43. data/lib/pdk/cli/util/update_manager_printer.rb +82 -0
  44. data/lib/pdk/cli/util.rb +105 -48
  45. data/lib/pdk/cli/validate.rb +96 -111
  46. data/lib/pdk/cli.rb +134 -87
  47. data/lib/pdk/config/errors.rb +5 -0
  48. data/lib/pdk/config/ini_file.rb +184 -0
  49. data/lib/pdk/config/ini_file_setting.rb +35 -0
  50. data/lib/pdk/config/json.rb +35 -0
  51. data/lib/pdk/config/json_schema_namespace.rb +137 -0
  52. data/lib/pdk/config/json_schema_setting.rb +51 -0
  53. data/lib/pdk/config/json_with_schema.rb +47 -0
  54. data/lib/pdk/config/namespace.rb +362 -0
  55. data/lib/pdk/config/setting.rb +134 -0
  56. data/lib/pdk/config/task_schema.json +116 -0
  57. data/lib/pdk/config/validator.rb +31 -0
  58. data/lib/pdk/config/yaml.rb +41 -0
  59. data/lib/pdk/config/yaml_with_schema.rb +51 -0
  60. data/lib/pdk/config.rb +304 -0
  61. data/lib/pdk/context/control_repo.rb +61 -0
  62. data/lib/pdk/context/module.rb +28 -0
  63. data/lib/pdk/context/none.rb +22 -0
  64. data/lib/pdk/context.rb +98 -0
  65. data/lib/pdk/control_repo.rb +89 -0
  66. data/lib/pdk/generate/defined_type.rb +27 -33
  67. data/lib/pdk/generate/fact.rb +26 -0
  68. data/lib/pdk/generate/function.rb +49 -0
  69. data/lib/pdk/generate/module.rb +160 -153
  70. data/lib/pdk/generate/provider.rb +16 -69
  71. data/lib/pdk/generate/puppet_class.rb +27 -32
  72. data/lib/pdk/generate/puppet_object.rb +100 -159
  73. data/lib/pdk/generate/task.rb +34 -51
  74. data/lib/pdk/generate/transport.rb +34 -0
  75. data/lib/pdk/generate.rb +21 -8
  76. data/lib/pdk/logger.rb +24 -6
  77. data/lib/pdk/module/build.rb +125 -37
  78. data/lib/pdk/module/convert.rb +146 -65
  79. data/lib/pdk/module/metadata.rb +72 -71
  80. data/lib/pdk/module/release.rb +255 -0
  81. data/lib/pdk/module/update.rb +48 -37
  82. data/lib/pdk/module/update_manager.rb +75 -39
  83. data/lib/pdk/module.rb +10 -2
  84. data/lib/pdk/monkey_patches.rb +268 -0
  85. data/lib/pdk/report/event.rb +36 -48
  86. data/lib/pdk/report.rb +35 -22
  87. data/lib/pdk/template/fetcher/git.rb +84 -0
  88. data/lib/pdk/template/fetcher/local.rb +29 -0
  89. data/lib/pdk/template/fetcher.rb +100 -0
  90. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +108 -0
  91. data/lib/pdk/template/renderer/v1/renderer.rb +131 -0
  92. data/lib/pdk/template/renderer/v1/template_file.rb +100 -0
  93. data/lib/pdk/template/renderer/v1.rb +25 -0
  94. data/lib/pdk/template/renderer.rb +97 -0
  95. data/lib/pdk/template/template_dir.rb +67 -0
  96. data/lib/pdk/template.rb +52 -0
  97. data/lib/pdk/tests/unit.rb +101 -51
  98. data/lib/pdk/util/bundler.rb +44 -42
  99. data/lib/pdk/util/changelog_generator.rb +138 -0
  100. data/lib/pdk/util/env.rb +48 -0
  101. data/lib/pdk/util/filesystem.rb +139 -2
  102. data/lib/pdk/util/git.rb +108 -8
  103. data/lib/pdk/util/json_finder.rb +86 -0
  104. data/lib/pdk/util/puppet_strings.rb +125 -0
  105. data/lib/pdk/util/puppet_version.rb +71 -87
  106. data/lib/pdk/util/ruby_version.rb +49 -25
  107. data/lib/pdk/util/template_uri.rb +283 -0
  108. data/lib/pdk/util/vendored_file.rb +34 -42
  109. data/lib/pdk/util/version.rb +11 -10
  110. data/lib/pdk/util/windows/api_types.rb +74 -44
  111. data/lib/pdk/util/windows/file.rb +31 -27
  112. data/lib/pdk/util/windows/process.rb +74 -0
  113. data/lib/pdk/util/windows/string.rb +19 -12
  114. data/lib/pdk/util/windows.rb +2 -0
  115. data/lib/pdk/util.rb +111 -124
  116. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -0
  117. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -0
  118. data/lib/pdk/validate/external_command_validator.rb +213 -0
  119. data/lib/pdk/validate/internal_ruby_validator.rb +101 -0
  120. data/lib/pdk/validate/invokable_validator.rb +238 -0
  121. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +84 -0
  122. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +76 -0
  123. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  124. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +131 -0
  125. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  126. data/lib/pdk/validate/puppet/puppet_plan_syntax_validator.rb +38 -0
  127. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +135 -0
  128. data/lib/pdk/validate/puppet/puppet_validator_group.rb +22 -0
  129. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +79 -0
  130. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  131. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +83 -0
  132. data/lib/pdk/validate/tasks/tasks_name_validator.rb +45 -0
  133. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  134. data/lib/pdk/validate/validator.rb +120 -0
  135. data/lib/pdk/validate/validator_group.rb +107 -0
  136. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +86 -0
  137. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  138. data/lib/pdk/validate.rb +86 -12
  139. data/lib/pdk/version.rb +2 -2
  140. data/lib/pdk.rb +60 -10
  141. metadata +138 -100
  142. data/lib/pdk/cli/module/build.rb +0 -14
  143. data/lib/pdk/cli/module/generate.rb +0 -45
  144. data/lib/pdk/cli/module.rb +0 -14
  145. data/lib/pdk/i18n.rb +0 -4
  146. data/lib/pdk/module/templatedir.rb +0 -321
  147. data/lib/pdk/template_file.rb +0 -95
  148. data/lib/pdk/validate/base_validator.rb +0 -215
  149. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -86
  150. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -109
  151. data/lib/pdk/validate/metadata_validator.rb +0 -30
  152. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -67
  153. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -112
  154. data/lib/pdk/validate/puppet_validator.rb +0 -30
  155. data/lib/pdk/validate/ruby/rubocop.rb +0 -77
  156. data/lib/pdk/validate/ruby_validator.rb +0 -29
  157. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -126
  158. data/lib/pdk/validate/tasks/name.rb +0 -88
  159. data/lib/pdk/validate/tasks_validator.rb +0 -33
  160. data/lib/pdk/validate/yaml/syntax.rb +0 -109
  161. data/lib/pdk/validate/yaml_validator.rb +0 -31
  162. data/locales/config.yaml +0 -21
  163. data/locales/pdk.pot +0 -1291
@@ -0,0 +1,76 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Metadata
6
+ class MetadataSyntaxValidator < InternalRubyValidator
7
+ def name
8
+ 'metadata-syntax'
9
+ end
10
+
11
+ def pattern
12
+ contextual_pattern(['metadata.json', 'tasks/*.json'])
13
+ end
14
+
15
+ def spinner_text
16
+ format('Checking metadata syntax (%{patterns}).', patterns: pattern.join(' '))
17
+ end
18
+
19
+ def invoke(report)
20
+ super
21
+ ensure
22
+ JSON.parser = JSON::Ext::Parser if defined?(JSON::Ext::Parser)
23
+ end
24
+
25
+ def before_validation
26
+ # The pure ruby JSON parser gives much nicer parse error messages than
27
+ # the C extension at the cost of slightly slower parsing. We require it
28
+ # here and restore the C extension at the end of the method (if it was
29
+ # being used).
30
+ require 'json/pure'
31
+ JSON.parser = JSON::Pure::Parser
32
+ end
33
+
34
+ def validate_target(report, target)
35
+ unless PDK::Util::Filesystem.readable?(target)
36
+ report.add_event(
37
+ file: target,
38
+ source: name,
39
+ state: :failure,
40
+ severity: 'error',
41
+ message: 'Could not be read.'
42
+ )
43
+ return 1
44
+ end
45
+
46
+ begin
47
+ JSON.parse(PDK::Util::Filesystem.read_file(target))
48
+
49
+ report.add_event(
50
+ file: target,
51
+ source: name,
52
+ state: :passed,
53
+ severity: 'ok'
54
+ )
55
+ 0
56
+ rescue JSON::ParserError => e
57
+ # Because the message contains a raw segment of the file, we use
58
+ # String#dump here to unescape any escape characters like newlines.
59
+ # We then strip out the surrounding quotes and the exclaimation
60
+ # point that json_pure likes to put in exception messages.
61
+ sane_message = e.message.dump[/\A"(.+?)!?"\Z/, 1]
62
+
63
+ report.add_event(
64
+ file: target,
65
+ source: name,
66
+ state: :failure,
67
+ severity: 'error',
68
+ message: sane_message
69
+ )
70
+ 1
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Metadata
6
+ class MetadataValidatorGroup < ValidatorGroup
7
+ def name
8
+ 'metadata'
9
+ end
10
+
11
+ def validators
12
+ [
13
+ MetadataSyntaxValidator,
14
+ MetadataJSONLintValidator
15
+ ].freeze
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,131 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Puppet
6
+ class PuppetEPPValidator < ExternalCommandValidator
7
+ # In Puppet >= 5.3.4, the error context formatting was changed to facilitate localization
8
+ ERROR_CONTEXT = /(?:file:\s(?<file>.+?)|line:\s(?<line>.+?)|column:\s(?<column>.+?))/.freeze
9
+ # In Puppet < 5.3.3, the error context was formatted in these variations:
10
+ # - "at file_path:line_num:col_num"
11
+ # - "at file_path:line_num"
12
+ # - "at line line_num"
13
+ # - "in file_path"
14
+ ERROR_CONTEXT_LEGACY = /(?:at\sline\s(?<line>\d+)|at\s(?<file>.+?):(?<line>\d+):(?<column>\d+)|at\s(?<file>.+?):(?<line>\d+)|in\s(?<file>.+?))/.freeze
15
+
16
+ PUPPET_LOGGER_PREFIX = /^(debug|info|notice|warning|error|alert|critical):\s.+?$/i.freeze
17
+ PUPPET_SYNTAX_PATTERN = /^
18
+ (?<severity>.+?):\s
19
+ (?<message>.+?)
20
+ (?:
21
+ \s\(#{ERROR_CONTEXT}(,\s#{ERROR_CONTEXT})*\)| # attempt to match the new localisation friendly location
22
+ \s#{ERROR_CONTEXT_LEGACY}| # attempt to match the old " at file:line:column" location
23
+ $ # handle cases where the output has no location
24
+ )
25
+ $/x.freeze
26
+
27
+ def name
28
+ 'puppet-epp'
29
+ end
30
+
31
+ def cmd
32
+ 'puppet'
33
+ end
34
+
35
+ def pattern
36
+ contextual_pattern('**/*.epp')
37
+ end
38
+
39
+ def spinner_text_for_targets(_targets)
40
+ format('Checking Puppet EPP syntax (%{pattern}).', pattern: pattern.join(' '))
41
+ end
42
+
43
+ def parse_options(targets)
44
+ # Due to PDK-1266 we need to run `puppet parser validate` with an empty
45
+ # modulepath. On *nix, Ruby treats `/dev/null` as an empty directory
46
+ # however it doesn't do so with `NUL` on Windows. The workaround for
47
+ # this to ensure consistent behaviour is to create an empty temporary
48
+ # directory and use that as the modulepath.
49
+ ['epp', 'validate', '--config', null_file, '--modulepath', validate_tmpdir].concat(targets)
50
+ end
51
+
52
+ def invoke(report)
53
+ super
54
+ ensure
55
+ remove_validate_tmpdir
56
+ end
57
+
58
+ def validate_tmpdir
59
+ require 'tmpdir'
60
+
61
+ @validate_tmpdir ||= Dir.mktmpdir('puppet-epp-validate')
62
+ end
63
+
64
+ def remove_validate_tmpdir
65
+ return unless @validate_tmpdir
66
+ return unless PDK::Util::Filesystem.directory?(@validate_tmpdir)
67
+
68
+ PDK::Util::Filesystem.remove_entry_secure(@validate_tmpdir)
69
+ @validate_tmpdir = nil
70
+ end
71
+
72
+ def null_file
73
+ Gem.win_platform? ? 'NUL' : '/dev/null'
74
+ end
75
+
76
+ def parse_output(report, result, targets)
77
+ # Due to PUP-7504, we will have to programmatically construct the json
78
+ # object from the text output for now.
79
+ output = result[:stderr].split(/\r?\n/).reject(&:empty?)
80
+
81
+ results_data = []
82
+ output.each do |offense|
83
+ offense_data = parse_offense(offense)
84
+ results_data << offense_data
85
+ end
86
+
87
+ # puppet parser validate does not include files without problems in its
88
+ # output, so we need to go through the list of targets and add passing
89
+ # events to the report for any target not listed in the output.
90
+ targets.reject { |target| results_data.any? { |j| j[:file] =~ /#{target}/ } }.each do |target|
91
+ report.add_event(
92
+ file: target,
93
+ source: name,
94
+ severity: :ok,
95
+ state: :passed
96
+ )
97
+ end
98
+
99
+ results_data.each do |offense|
100
+ report.add_event(offense)
101
+ end
102
+ end
103
+
104
+ def parse_offense(offense)
105
+ sanitize_console_output(offense)
106
+
107
+ offense_data = {
108
+ source: name,
109
+ state: :failure
110
+ }
111
+
112
+ if offense.match(PUPPET_LOGGER_PREFIX)
113
+ attributes = offense.match(PUPPET_SYNTAX_PATTERN)
114
+
115
+ attributes&.names&.each do |name|
116
+ offense_data[name.to_sym] = attributes[name] unless attributes[name].nil?
117
+ end
118
+ else
119
+ offense_data[:message] = offense
120
+ end
121
+
122
+ offense_data
123
+ end
124
+
125
+ def sanitize_console_output(line)
126
+ line.gsub!(/\e\[([;\d]+)?m/, '')
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,66 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Puppet
6
+ class PuppetLintValidator < ExternalCommandValidator
7
+ def name
8
+ 'puppet-lint'
9
+ end
10
+
11
+ def cmd
12
+ 'puppet-lint'
13
+ end
14
+
15
+ def pattern
16
+ contextual_pattern('**/*.pp')
17
+ end
18
+
19
+ def spinner_text_for_targets(_targets)
20
+ format('Checking Puppet manifest style (%{pattern}).', pattern: pattern.join(' '))
21
+ end
22
+
23
+ def parse_options(targets)
24
+ cmd_options = ['--json', '--relative']
25
+
26
+ cmd_options << '--fix' if options[:auto_correct]
27
+
28
+ cmd_options.concat(targets)
29
+ end
30
+
31
+ def parse_output(report, result, targets)
32
+ begin
33
+ json_data = JSON.parse(result[:stdout]).flatten
34
+ rescue JSON::ParserError
35
+ raise PDK::Validate::ParseOutputError, result[:stdout]
36
+ end
37
+
38
+ # puppet-lint does not include files without problems in its JSON
39
+ # output, so we need to go through the list of targets and add passing
40
+ # events to the report for any target not listed in the JSON output.
41
+ targets.reject { |target| json_data.any? { |j| j['path'] == target } }.each do |target|
42
+ report.add_event(
43
+ file: target,
44
+ source: name,
45
+ severity: 'ok',
46
+ state: :passed
47
+ )
48
+ end
49
+
50
+ json_data.each do |offense|
51
+ report.add_event({
52
+ file: offense['path'],
53
+ source: name,
54
+ line: offense['line'],
55
+ column: offense['column'],
56
+ message: offense['message'],
57
+ test: offense['check'],
58
+ severity: offense['kind'] == 'fixed' ? 'corrected' : offense['kind'],
59
+ state: :failure
60
+ })
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Puppet
6
+ class PuppetPlanSyntaxValidator < PuppetSyntaxValidator
7
+ def name
8
+ 'puppet-plan-syntax'
9
+ end
10
+
11
+ def pattern
12
+ contextual_pattern('plans/**/*.pp')
13
+ end
14
+
15
+ def pattern_ignore; end
16
+
17
+ def spinner_text_for_targets(_targets)
18
+ format('Checking Puppet plan syntax (%{pattern}).', pattern: pattern.join(' '))
19
+ end
20
+
21
+ def parse_options(targets)
22
+ # Due to PDK-1266 we need to run `puppet parser validate` with an empty
23
+ # modulepath. On *nix, Ruby treats `/dev/null` as an empty directory
24
+ # however it doesn't do so with `NUL` on Windows. The workaround for
25
+ # this to ensure consistent behaviour is to create an empty temporary
26
+ # directory and use that as the modulepath.
27
+ ['parser', 'validate', '--tasks', '--config', null_file, '--modulepath', validate_tmpdir].concat(targets)
28
+ end
29
+
30
+ def validate_tmpdir
31
+ require 'tmpdir'
32
+
33
+ @validate_tmpdir ||= Dir.mktmpdir('puppet-plan-parser-validate')
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,135 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Puppet
6
+ class PuppetSyntaxValidator < ExternalCommandValidator
7
+ # In Puppet >= 5.3.4, the error context formatting was changed to facilitate localization
8
+ ERROR_CONTEXT = /(?:file:\s(?<file>.+?)|line:\s(?<line>.+?)|column:\s(?<column>.+?))/.freeze
9
+ # In Puppet < 5.3.3, the error context was formatted in these variations:
10
+ # - "at file_path:line_num:col_num"
11
+ # - "at file_path:line_num"
12
+ # - "at line line_num"
13
+ # - "in file_path"
14
+ ERROR_CONTEXT_LEGACY = /(?:at\sline\s(?<line>\d+)|at\s(?<file>.+?):(?<line>\d+):(?<column>\d+)|at\s(?<file>.+?):(?<line>\d+)|in\s(?<file>.+?))/.freeze
15
+
16
+ PUPPET_LOGGER_PREFIX = /^(debug|info|notice|warning|error|alert|critical):\s.+?$/i.freeze
17
+ PUPPET_SYNTAX_PATTERN = /^
18
+ (?<severity>.+?):\s
19
+ (?<message>.+?)
20
+ (?:
21
+ \s\(#{ERROR_CONTEXT}(,\s#{ERROR_CONTEXT})*\)| # attempt to match the new localisation friendly location
22
+ \s#{ERROR_CONTEXT_LEGACY}| # attempt to match the old " at file:line:column" location
23
+ $ # handle cases where the output has no location
24
+ )
25
+ $/x.freeze
26
+
27
+ def name
28
+ 'puppet-syntax'
29
+ end
30
+
31
+ def cmd
32
+ 'puppet'
33
+ end
34
+
35
+ def pattern
36
+ contextual_pattern('**/*.pp')
37
+ end
38
+
39
+ def pattern_ignore
40
+ contextual_pattern('plans/**/*.pp')
41
+ end
42
+
43
+ def spinner_text_for_targets(_targets)
44
+ format('Checking Puppet manifest syntax (%{pattern}).', pattern: pattern.join(' '))
45
+ end
46
+
47
+ def parse_options(targets)
48
+ # Due to PDK-1266 we need to run `puppet parser validate` with an empty
49
+ # modulepath. On *nix, Ruby treats `/dev/null` as an empty directory
50
+ # however it doesn't do so with `NUL` on Windows. The workaround for
51
+ # this to ensure consistent behaviour is to create an empty temporary
52
+ # directory and use that as the modulepath.
53
+ ['parser', 'validate', '--config', null_file, '--modulepath', validate_tmpdir].concat(targets)
54
+ end
55
+
56
+ def invoke(report)
57
+ super
58
+ ensure
59
+ remove_validate_tmpdir
60
+ end
61
+
62
+ def validate_tmpdir
63
+ require 'tmpdir'
64
+
65
+ @validate_tmpdir ||= Dir.mktmpdir('puppet-parser-validate')
66
+ end
67
+
68
+ def remove_validate_tmpdir
69
+ return unless @validate_tmpdir
70
+ return unless PDK::Util::Filesystem.directory?(@validate_tmpdir)
71
+
72
+ PDK::Util::Filesystem.remove_entry_secure(@validate_tmpdir)
73
+ @validate_tmpdir = nil
74
+ end
75
+
76
+ def null_file
77
+ Gem.win_platform? ? 'NUL' : '/dev/null'
78
+ end
79
+
80
+ def parse_output(report, result, targets)
81
+ # Due to PUP-7504, we will have to programmatically construct the json
82
+ # object from the text output for now.
83
+ output = result[:stderr].split(/\r?\n/).reject(&:empty?)
84
+
85
+ results_data = []
86
+ output.each do |offense|
87
+ offense_data = parse_offense(offense)
88
+ results_data << offense_data
89
+ end
90
+
91
+ # puppet parser validate does not include files without problems in its
92
+ # output, so we need to go through the list of targets and add passing
93
+ # events to the report for any target not listed in the output.
94
+ targets.reject { |target| results_data.any? { |j| j[:file] =~ /#{target}/ } }.each do |target|
95
+ report.add_event(
96
+ file: target,
97
+ source: name,
98
+ severity: :ok,
99
+ state: :passed
100
+ )
101
+ end
102
+
103
+ results_data.each do |offense|
104
+ report.add_event(offense)
105
+ end
106
+ end
107
+
108
+ def parse_offense(offense)
109
+ sanitize_console_output(offense)
110
+
111
+ offense_data = {
112
+ source: name,
113
+ state: :failure
114
+ }
115
+
116
+ if offense.match(PUPPET_LOGGER_PREFIX)
117
+ attributes = offense.match(PUPPET_SYNTAX_PATTERN)
118
+
119
+ attributes&.names&.each do |name|
120
+ offense_data[name.to_sym] = attributes[name] unless attributes[name].nil?
121
+ end
122
+ else
123
+ offense_data[:message] = offense
124
+ end
125
+
126
+ offense_data
127
+ end
128
+
129
+ def sanitize_console_output(line)
130
+ line.gsub!(/\e\[([;\d]+)?m/, '')
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,22 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Puppet
6
+ class PuppetValidatorGroup < ValidatorGroup
7
+ def name
8
+ 'puppet'
9
+ end
10
+
11
+ def validators
12
+ [
13
+ PuppetSyntaxValidator,
14
+ PuppetPlanSyntaxValidator,
15
+ PuppetLintValidator,
16
+ PuppetEPPValidator
17
+ ].freeze
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,79 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Ruby
6
+ class RubyRubocopValidator < ExternalCommandValidator
7
+ def allow_empty_targets?
8
+ true
9
+ end
10
+
11
+ def name
12
+ 'rubocop'
13
+ end
14
+
15
+ def cmd
16
+ 'rubocop'
17
+ end
18
+
19
+ def pattern
20
+ if context.is_a?(PDK::Context::ControlRepo)
21
+ ['Puppetfile', '**/**.rb']
22
+ else
23
+ '**/**.rb'
24
+ end
25
+ end
26
+
27
+ def spinner_text_for_targets(_targets)
28
+ format('Checking Ruby code style (%{pattern}).', pattern: pattern)
29
+ end
30
+
31
+ def parse_options(targets)
32
+ cmd_options = ['--format', 'json']
33
+
34
+ cmd_options << '--auto-correct' if options[:auto_correct]
35
+
36
+ cmd_options.concat(targets)
37
+ end
38
+
39
+ def parse_output(report, result, _targets)
40
+ return if result[:stdout].empty?
41
+
42
+ begin
43
+ json_data = JSON.parse(result[:stdout])
44
+ rescue JSON::ParserError
45
+ raise PDK::Validate::ParseOutputError, result[:stdout]
46
+ end
47
+
48
+ return unless json_data.key?('files')
49
+
50
+ json_data['files'].each do |file_info|
51
+ next unless file_info.key?('offenses')
52
+
53
+ result = {
54
+ file: file_info['path'],
55
+ source: 'rubocop'
56
+ }
57
+
58
+ if file_info['offenses'].empty?
59
+ report.add_event(result.merge(state: :passed, severity: :ok))
60
+ else
61
+ file_info['offenses'].each do |offense|
62
+ report.add_event(
63
+ result.merge(
64
+ line: offense['location']['line'],
65
+ column: offense['location']['column'],
66
+ message: offense['message'],
67
+ severity: offense['corrected'] ? 'corrected' : offense['severity'],
68
+ test: offense['cop_name'],
69
+ state: :failure
70
+ )
71
+ )
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,19 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Ruby
6
+ class RubyValidatorGroup < ValidatorGroup
7
+ def name
8
+ 'ruby'
9
+ end
10
+
11
+ def validators
12
+ [
13
+ RubyRubocopValidator
14
+ ].freeze
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,83 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Tasks
6
+ class TasksMetadataLintValidator < InternalRubyValidator
7
+ def name
8
+ 'task-metadata-lint'
9
+ end
10
+
11
+ def pattern
12
+ contextual_pattern('tasks/*.json')
13
+ end
14
+
15
+ def spinner_text
16
+ format('Checking task metadata style (%{pattern}).', pattern: pattern.join(' '))
17
+ end
18
+
19
+ def schema_file
20
+ require 'pdk/config'
21
+
22
+ path = PDK::Config.json_schema('task')
23
+ schema = PDK::Util::Filesystem.read_file(path)
24
+
25
+ JSON.parse(schema)
26
+ rescue JSON::ParserError
27
+ raise PDK::CLI::FatalError, 'Failed to parse Task Metadata Schema file.'
28
+ end
29
+
30
+ def validate_target(report, target)
31
+ unless PDK::Util::Filesystem.readable?(target)
32
+ report.add_event(
33
+ file: target,
34
+ source: name,
35
+ state: :failure,
36
+ severity: 'error',
37
+ message: 'Could not be read.'
38
+ )
39
+ return 1
40
+ end
41
+
42
+ require 'json-schema'
43
+ begin
44
+ # Need to set the JSON Parser and State Generator to the Native one to be
45
+ # compatible with the multi_json adapter.
46
+ JSON.parser = JSON::Ext::Parser if defined?(JSON::Ext::Parser)
47
+ JSON.generator = JSON::Ext::Generator if defined?(JSON::Ext::Generator)
48
+
49
+ begin
50
+ errors = JSON::Validator.fully_validate(schema_file, PDK::Util::Filesystem.read_file(target)) || []
51
+ rescue JSON::Schema::SchemaError => e
52
+ raise PDK::CLI::FatalError, format('Unable to validate Task Metadata. %{error}.', error: e.message)
53
+ end
54
+
55
+ if errors.empty?
56
+ report.add_event(
57
+ file: target,
58
+ source: name,
59
+ state: :passed,
60
+ severity: 'ok'
61
+ )
62
+ 0
63
+ else
64
+ errors.each do |error|
65
+ # strip off the trailing parts that aren't relevant
66
+ error = error.split('in schema').first if error.include? 'in schema'
67
+
68
+ report.add_event(
69
+ file: target,
70
+ source: name,
71
+ state: :failure,
72
+ severity: 'error',
73
+ message: error
74
+ )
75
+ end
76
+ 1
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end