pdk 1.16.0 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +24 -0
  3. data/lib/pdk.rb +25 -18
  4. data/lib/pdk/answer_file.rb +2 -93
  5. data/lib/pdk/cli.rb +1 -5
  6. data/lib/pdk/cli/config.rb +3 -1
  7. data/lib/pdk/cli/config/get.rb +3 -1
  8. data/lib/pdk/cli/convert.rb +1 -1
  9. data/lib/pdk/cli/exec/command.rb +13 -0
  10. data/lib/pdk/cli/exec_group.rb +78 -43
  11. data/lib/pdk/cli/get.rb +20 -0
  12. data/lib/pdk/cli/get/config.rb +24 -0
  13. data/lib/pdk/cli/util.rb +6 -3
  14. data/lib/pdk/cli/validate.rb +26 -44
  15. data/lib/pdk/config.rb +178 -4
  16. data/lib/pdk/config/ini_file.rb +183 -0
  17. data/lib/pdk/config/ini_file_setting.rb +39 -0
  18. data/lib/pdk/config/namespace.rb +25 -5
  19. data/lib/pdk/config/setting.rb +3 -2
  20. data/lib/pdk/context.rb +96 -0
  21. data/lib/pdk/context/control_repo.rb +60 -0
  22. data/lib/pdk/context/module.rb +28 -0
  23. data/lib/pdk/context/none.rb +22 -0
  24. data/lib/pdk/control_repo.rb +40 -0
  25. data/lib/pdk/generate/module.rb +8 -12
  26. data/lib/pdk/module/release.rb +2 -8
  27. data/lib/pdk/util.rb +35 -5
  28. data/lib/pdk/util/bundler.rb +1 -0
  29. data/lib/pdk/util/changelog_generator.rb +6 -1
  30. data/lib/pdk/util/template_uri.rb +4 -3
  31. data/lib/pdk/validate.rb +72 -25
  32. data/lib/pdk/validate/external_command_validator.rb +208 -0
  33. data/lib/pdk/validate/internal_ruby_validator.rb +100 -0
  34. data/lib/pdk/validate/invokable_validator.rb +216 -0
  35. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -0
  36. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -0
  37. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -0
  38. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -0
  39. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -0
  40. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -0
  41. data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -0
  42. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -0
  43. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -0
  44. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -0
  45. data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -0
  46. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -0
  47. data/lib/pdk/validate/validator.rb +111 -0
  48. data/lib/pdk/validate/validator_group.rb +103 -0
  49. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -0
  50. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -0
  51. data/lib/pdk/version.rb +1 -1
  52. data/locales/pdk.pot +161 -125
  53. metadata +29 -17
  54. data/lib/pdk/validate/base_validator.rb +0 -215
  55. data/lib/pdk/validate/metadata/metadata_json_lint.rb +0 -82
  56. data/lib/pdk/validate/metadata/metadata_syntax.rb +0 -111
  57. data/lib/pdk/validate/metadata_validator.rb +0 -26
  58. data/lib/pdk/validate/puppet/puppet_epp.rb +0 -135
  59. data/lib/pdk/validate/puppet/puppet_lint.rb +0 -64
  60. data/lib/pdk/validate/puppet/puppet_syntax.rb +0 -135
  61. data/lib/pdk/validate/puppet_validator.rb +0 -26
  62. data/lib/pdk/validate/ruby/rubocop.rb +0 -72
  63. data/lib/pdk/validate/ruby_validator.rb +0 -26
  64. data/lib/pdk/validate/tasks/metadata_lint.rb +0 -130
  65. data/lib/pdk/validate/tasks/name.rb +0 -90
  66. data/lib/pdk/validate/tasks_validator.rb +0 -29
  67. data/lib/pdk/validate/yaml/syntax.rb +0 -125
  68. data/lib/pdk/validate/yaml_validator.rb +0 -28
@@ -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
+ _('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,137 @@
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 = %r{(?:file:\s(?<file>.+?)|line:\s(?<line>.+?)|column:\s(?<column>.+?))}
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 = %r{(?:at\sline\s(?<line>\d+)|at\s(?<file>.+?):(?<line>\d+):(?<column>\d+)|at\s(?<file>.+?):(?<line>\d+)|in\s(?<file>.+?))}
15
+
16
+ PUPPET_LOGGER_PREFIX = %r{^(debug|info|notice|warning|error|alert|critical):\s.+?$}i
17
+ PUPPET_SYNTAX_PATTERN = %r{^
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
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
+ _('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{\r?\n}).reject { |entry| entry.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] =~ %r{#{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
+ unless attributes.nil?
120
+ attributes.names.each do |name|
121
+ offense_data[name.to_sym] = attributes[name] unless attributes[name].nil?
122
+ end
123
+ end
124
+ else
125
+ offense_data[:message] = offense
126
+ end
127
+
128
+ offense_data
129
+ end
130
+
131
+ def sanitize_console_output(line)
132
+ line.gsub!(%r{\e\[([;\d]+)?m}, '')
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,21 @@
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
+ PuppetLintValidator,
15
+ PuppetEPPValidator,
16
+ ].freeze
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,80 @@
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
+ _('Checking Ruby code style (%{pattern}).') % { pattern: pattern }
29
+ end
30
+
31
+ def parse_options(targets)
32
+ cmd_options = ['--format', 'json']
33
+
34
+ if options[:auto_correct]
35
+ cmd_options << '--auto-correct'
36
+ end
37
+
38
+ cmd_options.concat(targets)
39
+ end
40
+
41
+ def parse_output(report, result, _targets)
42
+ return if result[:stdout].empty?
43
+
44
+ begin
45
+ json_data = JSON.parse(result[:stdout])
46
+ rescue JSON::ParserError
47
+ raise PDK::Validate::ParseOutputError, result[:stdout]
48
+ end
49
+
50
+ return unless json_data.key?('files')
51
+
52
+ json_data['files'].each do |file_info|
53
+ next unless file_info.key?('offenses')
54
+ result = {
55
+ file: file_info['path'],
56
+ source: 'rubocop',
57
+ }
58
+
59
+ if file_info['offenses'].empty?
60
+ report.add_event(result.merge(state: :passed, severity: :ok))
61
+ else
62
+ file_info['offenses'].each do |offense|
63
+ report.add_event(
64
+ result.merge(
65
+ line: offense['location']['line'],
66
+ column: offense['location']['column'],
67
+ message: offense['message'],
68
+ severity: offense['corrected'] ? 'corrected' : offense['severity'],
69
+ test: offense['cop_name'],
70
+ state: :failure,
71
+ ),
72
+ )
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ 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,88 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Tasks
6
+ class TasksMetadataLintValidator < InternalRubyValidator
7
+ FORGE_SCHEMA_URL = 'https://forgeapi.puppet.com/schemas/task.json'.freeze
8
+
9
+ def name
10
+ 'task-metadata-lint'
11
+ end
12
+
13
+ def pattern
14
+ contextual_pattern('tasks/*.json')
15
+ end
16
+
17
+ def spinner_text
18
+ _('Checking task metadata style (%{pattern}).') % {
19
+ pattern: pattern.join(' '),
20
+ }
21
+ end
22
+
23
+ def schema_file
24
+ require 'pdk/util/vendored_file'
25
+
26
+ schema = PDK::Util::VendoredFile.new('task.json', FORGE_SCHEMA_URL).read
27
+
28
+ JSON.parse(schema)
29
+ rescue PDK::Util::VendoredFile::DownloadError => e
30
+ raise PDK::CLI::FatalError, e.message
31
+ rescue JSON::ParserError
32
+ raise PDK::CLI::FatalError, _('Failed to parse Task Metadata Schema file.')
33
+ end
34
+
35
+ def validate_target(report, target)
36
+ unless PDK::Util::Filesystem.readable?(target)
37
+ report.add_event(
38
+ file: target,
39
+ source: name,
40
+ state: :failure,
41
+ severity: 'error',
42
+ message: _('Could not be read.'),
43
+ )
44
+ return 1
45
+ end
46
+
47
+ require 'json-schema'
48
+ begin
49
+ # Need to set the JSON Parser and State Generator to the Native one to be
50
+ # compatible with the multi_json adapter.
51
+ JSON.parser = JSON::Ext::Parser if defined?(JSON::Ext::Parser)
52
+ JSON.generator = JSON::Ext::Generator
53
+
54
+ begin
55
+ errors = JSON::Validator.fully_validate(schema_file, PDK::Util::Filesystem.read_file(target)) || []
56
+ rescue JSON::Schema::SchemaError => e
57
+ raise PDK::CLI::FatalError, _('Unable to validate Task Metadata. %{error}.') % { error: e.message }
58
+ end
59
+
60
+ if errors.empty?
61
+ report.add_event(
62
+ file: target,
63
+ source: name,
64
+ state: :passed,
65
+ severity: 'ok',
66
+ )
67
+ return 0
68
+ else
69
+ errors.each do |error|
70
+ # strip off the trailing parts that aren't relevant
71
+ error = error.split('in schema').first if error.include? 'in schema'
72
+
73
+ report.add_event(
74
+ file: target,
75
+ source: name,
76
+ state: :failure,
77
+ severity: 'error',
78
+ message: error,
79
+ )
80
+ end
81
+ return 1
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,50 @@
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ module Tasks
6
+ class TasksNameValidator < InternalRubyValidator
7
+ INVALID_TASK_MSG = _(
8
+ 'Invalid task name. Task names must start with a lowercase letter ' \
9
+ 'and can only contain lowercase letters, numbers, and underscores.',
10
+ )
11
+
12
+ def name
13
+ 'task-name'
14
+ end
15
+
16
+ def pattern
17
+ contextual_pattern('tasks/**/*')
18
+ end
19
+
20
+ def spinner_text
21
+ _('Checking task names (%{pattern}).') % {
22
+ pattern: pattern.join(' '),
23
+ }
24
+ end
25
+
26
+ def validate_target(report, target)
27
+ task_name = File.basename(target, File.extname(target))
28
+ if PDK::CLI::Util::OptionValidator.valid_task_name?(task_name)
29
+ report.add_event(
30
+ file: target,
31
+ source: name,
32
+ state: :passed,
33
+ severity: 'ok',
34
+ )
35
+ return 0
36
+ else
37
+ report.add_event(
38
+ file: target,
39
+ source: name,
40
+ state: :failure,
41
+ severity: 'error',
42
+ message: INVALID_TASK_MSG,
43
+ )
44
+ return 1
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end