pdk 2.3.0 → 2.4.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 (153) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1329 -1321
  3. data/LICENSE +201 -201
  4. data/README.md +163 -163
  5. data/exe/pdk +10 -10
  6. data/lib/pdk/analytics/client/google_analytics.rb +143 -143
  7. data/lib/pdk/analytics/client/noop.rb +25 -25
  8. data/lib/pdk/analytics/util.rb +19 -19
  9. data/lib/pdk/analytics.rb +30 -30
  10. data/lib/pdk/answer_file.rb +12 -12
  11. data/lib/pdk/bolt.rb +19 -19
  12. data/lib/pdk/cli/build.rb +82 -82
  13. data/lib/pdk/cli/bundle.rb +48 -48
  14. data/lib/pdk/cli/config/get.rb +26 -26
  15. data/lib/pdk/cli/config.rb +22 -22
  16. data/lib/pdk/cli/console.rb +148 -148
  17. data/lib/pdk/cli/convert.rb +52 -52
  18. data/lib/pdk/cli/env.rb +52 -52
  19. data/lib/pdk/cli/errors.rb +25 -25
  20. data/lib/pdk/cli/exec/command.rb +293 -293
  21. data/lib/pdk/cli/exec/interactive_command.rb +114 -114
  22. data/lib/pdk/cli/exec.rb +84 -84
  23. data/lib/pdk/cli/exec_group.rb +104 -104
  24. data/lib/pdk/cli/get/config.rb +24 -24
  25. data/lib/pdk/cli/get.rb +20 -20
  26. data/lib/pdk/cli/module/build.rb +12 -12
  27. data/lib/pdk/cli/module/generate.rb +47 -47
  28. data/lib/pdk/cli/module.rb +14 -14
  29. data/lib/pdk/cli/new/class.rb +32 -32
  30. data/lib/pdk/cli/new/defined_type.rb +32 -32
  31. data/lib/pdk/cli/new/fact.rb +29 -29
  32. data/lib/pdk/cli/new/function.rb +29 -29
  33. data/lib/pdk/cli/new/module.rb +53 -53
  34. data/lib/pdk/cli/new/provider.rb +29 -29
  35. data/lib/pdk/cli/new/task.rb +34 -34
  36. data/lib/pdk/cli/new/test.rb +52 -52
  37. data/lib/pdk/cli/new/transport.rb +27 -27
  38. data/lib/pdk/cli/new.rb +21 -21
  39. data/lib/pdk/cli/release/prep.rb +39 -39
  40. data/lib/pdk/cli/release/publish.rb +50 -50
  41. data/lib/pdk/cli/release.rb +194 -194
  42. data/lib/pdk/cli/remove/config.rb +80 -80
  43. data/lib/pdk/cli/remove.rb +20 -20
  44. data/lib/pdk/cli/set/config.rb +119 -119
  45. data/lib/pdk/cli/set.rb +20 -20
  46. data/lib/pdk/cli/test/unit.rb +90 -90
  47. data/lib/pdk/cli/test.rb +11 -11
  48. data/lib/pdk/cli/update.rb +64 -64
  49. data/lib/pdk/cli/util/command_redirector.rb +27 -27
  50. data/lib/pdk/cli/util/interview.rb +72 -72
  51. data/lib/pdk/cli/util/option_normalizer.rb +55 -55
  52. data/lib/pdk/cli/util/option_validator.rb +68 -68
  53. data/lib/pdk/cli/util/spinner.rb +13 -13
  54. data/lib/pdk/cli/util/update_manager_printer.rb +82 -82
  55. data/lib/pdk/cli/util.rb +305 -305
  56. data/lib/pdk/cli/validate.rb +116 -116
  57. data/lib/pdk/cli.rb +175 -175
  58. data/lib/pdk/config/analytics_schema.json +26 -26
  59. data/lib/pdk/config/errors.rb +5 -5
  60. data/lib/pdk/config/ini_file.rb +183 -183
  61. data/lib/pdk/config/ini_file_setting.rb +39 -39
  62. data/lib/pdk/config/json.rb +34 -34
  63. data/lib/pdk/config/json_schema_namespace.rb +142 -142
  64. data/lib/pdk/config/json_schema_setting.rb +53 -53
  65. data/lib/pdk/config/json_with_schema.rb +49 -49
  66. data/lib/pdk/config/namespace.rb +354 -354
  67. data/lib/pdk/config/setting.rb +135 -135
  68. data/lib/pdk/config/validator.rb +31 -31
  69. data/lib/pdk/config/yaml.rb +46 -46
  70. data/lib/pdk/config/yaml_with_schema.rb +59 -59
  71. data/lib/pdk/config.rb +390 -390
  72. data/lib/pdk/context/control_repo.rb +60 -60
  73. data/lib/pdk/context/module.rb +28 -28
  74. data/lib/pdk/context/none.rb +22 -22
  75. data/lib/pdk/context.rb +99 -99
  76. data/lib/pdk/control_repo.rb +90 -90
  77. data/lib/pdk/generate/defined_type.rb +43 -43
  78. data/lib/pdk/generate/fact.rb +25 -25
  79. data/lib/pdk/generate/function.rb +48 -48
  80. data/lib/pdk/generate/module.rb +352 -352
  81. data/lib/pdk/generate/provider.rb +28 -28
  82. data/lib/pdk/generate/puppet_class.rb +43 -43
  83. data/lib/pdk/generate/puppet_object.rb +232 -232
  84. data/lib/pdk/generate/task.rb +68 -68
  85. data/lib/pdk/generate/transport.rb +33 -33
  86. data/lib/pdk/generate.rb +24 -24
  87. data/lib/pdk/i18n.rb +4 -4
  88. data/lib/pdk/logger.rb +45 -45
  89. data/lib/pdk/module/build.rb +322 -322
  90. data/lib/pdk/module/convert.rb +296 -296
  91. data/lib/pdk/module/metadata.rb +202 -202
  92. data/lib/pdk/module/release.rb +260 -260
  93. data/lib/pdk/module/update.rb +131 -131
  94. data/lib/pdk/module/update_manager.rb +227 -227
  95. data/lib/pdk/module.rb +30 -30
  96. data/lib/pdk/report/event.rb +370 -370
  97. data/lib/pdk/report.rb +121 -121
  98. data/lib/pdk/template/fetcher/git.rb +85 -85
  99. data/lib/pdk/template/fetcher/local.rb +28 -28
  100. data/lib/pdk/template/fetcher.rb +98 -98
  101. data/lib/pdk/template/renderer/v1/legacy_template_dir.rb +116 -116
  102. data/lib/pdk/template/renderer/v1/renderer.rb +132 -132
  103. data/lib/pdk/template/renderer/v1/template_file.rb +102 -102
  104. data/lib/pdk/template/renderer/v1.rb +25 -25
  105. data/lib/pdk/template/renderer.rb +96 -96
  106. data/lib/pdk/template/template_dir.rb +67 -67
  107. data/lib/pdk/template.rb +59 -59
  108. data/lib/pdk/tests/unit.rb +252 -252
  109. data/lib/pdk/util/bundler.rb +259 -259
  110. data/lib/pdk/util/changelog_generator.rb +137 -137
  111. data/lib/pdk/util/env.rb +47 -47
  112. data/lib/pdk/util/filesystem.rb +138 -138
  113. data/lib/pdk/util/git.rb +179 -179
  114. data/lib/pdk/util/json_finder.rb +85 -85
  115. data/lib/pdk/util/puppet_strings.rb +125 -125
  116. data/lib/pdk/util/puppet_version.rb +266 -266
  117. data/lib/pdk/util/ruby_version.rb +179 -179
  118. data/lib/pdk/util/template_uri.rb +295 -295
  119. data/lib/pdk/util/vendored_file.rb +93 -93
  120. data/lib/pdk/util/version.rb +43 -43
  121. data/lib/pdk/util/windows/api_types.rb +82 -82
  122. data/lib/pdk/util/windows/file.rb +36 -36
  123. data/lib/pdk/util/windows/process.rb +79 -79
  124. data/lib/pdk/util/windows/string.rb +16 -16
  125. data/lib/pdk/util/windows.rb +15 -15
  126. data/lib/pdk/util.rb +278 -277
  127. data/lib/pdk/validate/control_repo/control_repo_validator_group.rb +23 -23
  128. data/lib/pdk/validate/control_repo/environment_conf_validator.rb +98 -98
  129. data/lib/pdk/validate/external_command_validator.rb +208 -208
  130. data/lib/pdk/validate/internal_ruby_validator.rb +100 -100
  131. data/lib/pdk/validate/invokable_validator.rb +228 -228
  132. data/lib/pdk/validate/metadata/metadata_json_lint_validator.rb +86 -86
  133. data/lib/pdk/validate/metadata/metadata_syntax_validator.rb +78 -78
  134. data/lib/pdk/validate/metadata/metadata_validator_group.rb +20 -20
  135. data/lib/pdk/validate/puppet/puppet_epp_validator.rb +133 -133
  136. data/lib/pdk/validate/puppet/puppet_lint_validator.rb +66 -66
  137. data/lib/pdk/validate/puppet/puppet_syntax_validator.rb +137 -137
  138. data/lib/pdk/validate/puppet/puppet_validator_group.rb +21 -21
  139. data/lib/pdk/validate/ruby/ruby_rubocop_validator.rb +80 -80
  140. data/lib/pdk/validate/ruby/ruby_validator_group.rb +19 -19
  141. data/lib/pdk/validate/tasks/tasks_metadata_lint_validator.rb +88 -88
  142. data/lib/pdk/validate/tasks/tasks_name_validator.rb +50 -50
  143. data/lib/pdk/validate/tasks/tasks_validator_group.rb +20 -20
  144. data/lib/pdk/validate/validator.rb +118 -118
  145. data/lib/pdk/validate/validator_group.rb +104 -104
  146. data/lib/pdk/validate/yaml/yaml_syntax_validator.rb +95 -95
  147. data/lib/pdk/validate/yaml/yaml_validator_group.rb +19 -19
  148. data/lib/pdk/validate.rb +94 -94
  149. data/lib/pdk/version.rb +4 -4
  150. data/lib/pdk.rb +76 -76
  151. data/locales/config.yaml +21 -21
  152. data/locales/pdk.pot +2094 -2094
  153. metadata +5 -6
@@ -1,100 +1,100 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Validate
5
- # An abstract validator that runs ruby code internal to the PDK e.g. JSON and YAML validation, on a single file.
6
- # The validator code must run within the PDK Ruby environment as opposed to the bundled Ruby environment for a module.
7
- #
8
- # At a a minimum child classes should implment the `name`, `pattern` and `validate_target` methods
9
- #
10
- # An example concrete implementation could look like:
11
- #
12
- # module PDK
13
- # module Validate
14
- # module Tasks
15
- # class TasksNameValidator < InternalRubyValidator
16
- # def name
17
- # 'task-name'
18
- # end
19
- #
20
- # def pattern
21
- # 'tasks/**/*'
22
- # end
23
- #
24
- # def validate_target(report, target)
25
- # task_name = File.basename(target, File.extname(target))
26
- # ... ruby code ...
27
- # success ? 0 : 1
28
- # end
29
- # end
30
- # end
31
- # end
32
- # end
33
- #
34
- #
35
- # @abstract
36
- # @see PDK::Validate::InvokableValidator
37
- class InternalRubyValidator < InvokableValidator
38
- # @see PDK::Validate::Validator.prepare_invoke!
39
- def prepare_invoke!
40
- return if @prepared
41
- super
42
-
43
- # Parse the targets
44
- @targets, @skipped, @invalid = parse_targets
45
-
46
- nil
47
- end
48
-
49
- # Invokes the validator to call `validate_target` on each target
50
- # @see PDK::Validate::Validator.invoke
51
- def invoke(report)
52
- prepare_invoke!
53
-
54
- process_skipped(report, @skipped)
55
- process_invalid(report, @invalid)
56
-
57
- return 0 if @targets.empty?
58
-
59
- return_val = 0
60
-
61
- before_validation
62
-
63
- start_spinner
64
- @targets.each do |target|
65
- validation_result = validate_target(report, target)
66
- if validation_result.nil?
67
- report.add_event(
68
- file: target,
69
- source: name,
70
- state: :failure,
71
- severity: 'error',
72
- message: "Validation did not return an exit code for #{target}",
73
- )
74
- validation_result = 1
75
- end
76
- return_val = validation_result if validation_result > return_val
77
- end
78
-
79
- stop_spinner(return_val.zero?)
80
- return_val
81
- end
82
-
83
- # Validates a single target
84
- # It is the responsibility of this method to populate the report with validation messages
85
- #
86
- # @param report [PDK::Report] The report to add the events to
87
- # @param target [String] The target to validate
88
- #
89
- # @return [Integer] The exitcode of the validation. Zero indicates success. A non-zero code indicates failure
90
- # @api private
91
- # @abstract
92
- def validate_target(report, target); end
93
-
94
- # Tasks to run before validation occurs. This is run once every time `.invoke` is called
95
- # @api private
96
- # @abstract
97
- def before_validation; end
98
- end
99
- end
100
- end
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ # An abstract validator that runs ruby code internal to the PDK e.g. JSON and YAML validation, on a single file.
6
+ # The validator code must run within the PDK Ruby environment as opposed to the bundled Ruby environment for a module.
7
+ #
8
+ # At a a minimum child classes should implment the `name`, `pattern` and `validate_target` methods
9
+ #
10
+ # An example concrete implementation could look like:
11
+ #
12
+ # module PDK
13
+ # module Validate
14
+ # module Tasks
15
+ # class TasksNameValidator < InternalRubyValidator
16
+ # def name
17
+ # 'task-name'
18
+ # end
19
+ #
20
+ # def pattern
21
+ # 'tasks/**/*'
22
+ # end
23
+ #
24
+ # def validate_target(report, target)
25
+ # task_name = File.basename(target, File.extname(target))
26
+ # ... ruby code ...
27
+ # success ? 0 : 1
28
+ # end
29
+ # end
30
+ # end
31
+ # end
32
+ # end
33
+ #
34
+ #
35
+ # @abstract
36
+ # @see PDK::Validate::InvokableValidator
37
+ class InternalRubyValidator < InvokableValidator
38
+ # @see PDK::Validate::Validator.prepare_invoke!
39
+ def prepare_invoke!
40
+ return if @prepared
41
+ super
42
+
43
+ # Parse the targets
44
+ @targets, @skipped, @invalid = parse_targets
45
+
46
+ nil
47
+ end
48
+
49
+ # Invokes the validator to call `validate_target` on each target
50
+ # @see PDK::Validate::Validator.invoke
51
+ def invoke(report)
52
+ prepare_invoke!
53
+
54
+ process_skipped(report, @skipped)
55
+ process_invalid(report, @invalid)
56
+
57
+ return 0 if @targets.empty?
58
+
59
+ return_val = 0
60
+
61
+ before_validation
62
+
63
+ start_spinner
64
+ @targets.each do |target|
65
+ validation_result = validate_target(report, target)
66
+ if validation_result.nil?
67
+ report.add_event(
68
+ file: target,
69
+ source: name,
70
+ state: :failure,
71
+ severity: 'error',
72
+ message: "Validation did not return an exit code for #{target}",
73
+ )
74
+ validation_result = 1
75
+ end
76
+ return_val = validation_result if validation_result > return_val
77
+ end
78
+
79
+ stop_spinner(return_val.zero?)
80
+ return_val
81
+ end
82
+
83
+ # Validates a single target
84
+ # It is the responsibility of this method to populate the report with validation messages
85
+ #
86
+ # @param report [PDK::Report] The report to add the events to
87
+ # @param target [String] The target to validate
88
+ #
89
+ # @return [Integer] The exitcode of the validation. Zero indicates success. A non-zero code indicates failure
90
+ # @api private
91
+ # @abstract
92
+ def validate_target(report, target); end
93
+
94
+ # Tasks to run before validation occurs. This is run once every time `.invoke` is called
95
+ # @api private
96
+ # @abstract
97
+ def before_validation; end
98
+ end
99
+ end
100
+ end
@@ -1,228 +1,228 @@
1
- require 'pdk'
2
-
3
- module PDK
4
- module Validate
5
- # A base class for file based validators.
6
- # This class provides base methods and helpers to help determine the file targets to validate against.
7
- # Acutal validator implementation should inherit from other child abstract classes e.g. ExternalCommandValdiator
8
- # @see PDK::Validate::Validator
9
- # @abstract
10
- class InvokableValidator < Validator
11
- # Controls how many times the validator is invoked.
12
- #
13
- # :once - The validator will be invoked once and passed all the
14
- # targets.
15
- # :per_target - The validator will be invoked for each target
16
- # separately.
17
- # @abstract
18
- def invoke_style
19
- :once
20
- end
21
-
22
- # Whether this Validator can be invoked in this context. By default any InvokableValidator can work in any Context, except ::None
23
- # @see PDK::Validate::Validator
24
- def valid_in_context?
25
- !context.is_a?(PDK::Context::None)
26
- end
27
-
28
- # An array, or a string, of glob patterns to use to find targets
29
- # @return [Array[String], String]
30
- # @abstract
31
- def pattern; end
32
-
33
- # An array, or a string, of glob patterns to use to ignore targets
34
- # @return [Array[String], String, Nil]
35
- # @abstract
36
- def pattern_ignore; end
37
-
38
- # @see PDK::Validate::Validator.prepare_invoke!
39
- def prepare_invoke!
40
- return if @prepared
41
- super
42
-
43
- # Register the spinner
44
- spinner
45
- nil
46
- end
47
-
48
- # Parses the target strings provided from the CLI
49
- #
50
- # @param options [Hash] A Hash containing the input options from the CLI.
51
- #
52
- # @return targets [Array] An Array of Strings containing target file paths
53
- # for the validator to validate.
54
- # @return skipped [Array] An Array of Strings containing targets
55
- # that are skipped due to target not containing
56
- # any files that can be validated by the validator.
57
- # @return invalid [Array] An Array of Strings containing targets that do
58
- # not exist, and will not be run by validator.
59
- def parse_targets
60
- requested_targets = options.fetch(:targets, [])
61
- # If no targets are specified and empty targets are allowed return with an empty list.
62
- # It will be up to the validator (and whatever validation tool it uses) to determine the
63
- # targets. For example, using rubocop with no targets, will allow rubocop to determine the
64
- # target list using it's .rubocop.yml file
65
- return [[], [], []] if requested_targets.empty? && allow_empty_targets?
66
- # If no targets are specified, then we will run validations from the base context directory.
67
- targets = requested_targets.empty? ? [context.root_path] : requested_targets
68
- targets.map! { |r| r.gsub(File::ALT_SEPARATOR, File::SEPARATOR) } if File::ALT_SEPARATOR
69
-
70
- # If this validator is not valid in this context then skip all of the targets
71
- return [[], targets, []] unless valid_in_context?
72
-
73
- skipped = []
74
- invalid = []
75
- matched = targets.map { |target|
76
- if pattern.nil?
77
- target
78
- else
79
- if PDK::Util::Filesystem.directory?(target) # rubocop:disable Style/IfInsideElse
80
- target_root = context.root_path
81
- pattern_glob = Array(pattern).map { |p| PDK::Util::Filesystem.glob(File.join(target_root, p), File::FNM_DOTMATCH) }
82
- target_list = pattern_glob.flatten
83
- .select { |glob| PDK::Util::Filesystem.fnmatch(File.join(PDK::Util::Filesystem.expand_path(PDK::Util.canonical_path(target)), '*'), glob, File::FNM_DOTMATCH) }
84
- .map { |glob| Pathname.new(glob).relative_path_from(Pathname.new(context.root_path)).to_s }
85
-
86
- ignore_list = ignore_pathspec
87
- target_list = target_list.reject { |file| ignore_list.match(file) }
88
-
89
- if target_list.flatten.empty?
90
- PDK.logger.info(_('Validator \'%{validator}\' skipped for \'%{target}\'. No files matching \'%{pattern}\' found to validate.') % { validator: name, target: target, pattern: pattern })
91
-
92
- skipped << target
93
- end
94
-
95
- target_list
96
- elsif PDK::Util::Filesystem.file?(target)
97
- if Array(pattern).include? target
98
- target
99
- elsif Array(pattern).any? { |p| PDK::Util::Filesystem.fnmatch(PDK::Util::Filesystem.expand_path(p), PDK::Util::Filesystem.expand_path(target), File::FNM_DOTMATCH) }
100
- target
101
- else
102
- skipped << target
103
- next
104
- end
105
- else
106
- invalid << target
107
- next
108
- end
109
- end
110
- }.compact.flatten.uniq
111
- [matched, skipped, invalid]
112
- end
113
-
114
- # Whether the target parsing ignores "dotfiles" (e.g. .gitignore or .pdkignore) which are considered hidden files in POSIX
115
- # @return [Boolean]
116
- # @abstract
117
- def ignore_dotfiles?
118
- true
119
- end
120
-
121
- # @see PDK::Validate::Validator.spinner_text
122
- # @abstract
123
- def spinner_text
124
- _('Running %{name} validator ...') % { name: name }
125
- end
126
-
127
- # @see PDK::Validate::Validator.spinner
128
- def spinner
129
- return nil unless spinners_enabled?
130
- return @spinner unless @spinner.nil?
131
- require 'pdk/cli/util/spinner'
132
-
133
- @spinner = TTY::Spinner.new("[:spinner] #{spinner_text}", PDK::CLI::Util.spinner_opts_for_platform)
134
- end
135
-
136
- # Process any targets that were skipped by the validator and add the events to the validation report
137
- # @param report [PDK::Report] The report to add the events to
138
- # @param skipped [Array[String]] The list of skipped targets
139
- def process_skipped(report, skipped = [])
140
- skipped.each do |skipped_target|
141
- PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target does not contain any files to validate (%{pattern}).') % { validator: name, target: skipped_target, pattern: pattern })
142
- report.add_event(
143
- file: skipped_target,
144
- source: name,
145
- message: _('Target does not contain any files to validate (%{pattern}).') % { pattern: pattern },
146
- severity: :info,
147
- state: :skipped,
148
- )
149
- end
150
- end
151
-
152
- # Process any targets that were invalid by the validator and add the events to the validation report
153
- # @param report [PDK::Report] The report to add the events to
154
- # @param invalid [Array[String]] The list of invalid targets
155
- def process_invalid(report, invalid = [])
156
- invalid.each do |invalid_target|
157
- PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target file not found.') % { validator: name, target: invalid_target })
158
- report.add_event(
159
- file: invalid_target,
160
- source: name,
161
- message: _('File does not exist.'),
162
- severity: :error,
163
- state: :error,
164
- )
165
- end
166
- end
167
-
168
- # Controls how the validator behaves if not passed any targets.
169
- #
170
- # true - PDK will not pass the globbed targets to the validator command
171
- # and it will instead rely on the underlying tool to find its
172
- # own default targets.
173
- # false - PDK will pass the globbed targets to the validator command.
174
- # @abstract
175
- def allow_empty_targets?
176
- false
177
- end
178
-
179
- protected
180
-
181
- # Takes the pattern used in a module context and transforms it depending on the
182
- # context e.g. A Control Repo will use the module pattern in each module path
183
- #
184
- # @param [Array, String] The pattern when used in the module root. Does not start with '/'
185
- #
186
- # @return [Array[String]]
187
- def contextual_pattern(module_pattern)
188
- module_pattern = [module_pattern] unless module_pattern.is_a?(Array)
189
- return module_pattern unless context.is_a?(PDK::Context::ControlRepo)
190
- context.actualized_module_paths.map { |mod_path| module_pattern.map { |pat_path| mod_path + '/*/' + pat_path } }.flatten
191
- end
192
-
193
- private
194
-
195
- # Helper method to collate the default ignored paths
196
- # @return [PathSpec] Paths to ignore
197
- def ignore_pathspec
198
- ignore_pathspec = if context.is_a?(PDK::Context::Module)
199
- require 'pdk/module'
200
- PDK::Module.default_ignored_pathspec(ignore_dotfiles?)
201
- elsif context.is_a?(PDK::Context::ControlRepo)
202
- require 'pdk/control_repo'
203
- PDK::ControlRepo.default_ignored_pathspec(ignore_dotfiles?)
204
- else
205
- PathSpec.new.tap do |ps|
206
- ps.add('.*') if ignore_dotfiles?
207
- end
208
- end
209
-
210
- unless pattern_ignore.nil?
211
- Array(pattern_ignore).each do |pattern|
212
- ignore_pathspec.add(pattern)
213
- end
214
- end
215
-
216
- # block will always be [] because it is intialized in config
217
- ignore_files = PDK.config.get_within_scopes('validate.ignore')
218
- unless ignore_files.nil? || ignore_files.empty?
219
- Array(ignore_files).each do |pattern|
220
- ignore_pathspec.add(pattern)
221
- end
222
- end
223
-
224
- ignore_pathspec
225
- end
226
- end
227
- end
228
- end
1
+ require 'pdk'
2
+
3
+ module PDK
4
+ module Validate
5
+ # A base class for file based validators.
6
+ # This class provides base methods and helpers to help determine the file targets to validate against.
7
+ # Acutal validator implementation should inherit from other child abstract classes e.g. ExternalCommandValdiator
8
+ # @see PDK::Validate::Validator
9
+ # @abstract
10
+ class InvokableValidator < Validator
11
+ # Controls how many times the validator is invoked.
12
+ #
13
+ # :once - The validator will be invoked once and passed all the
14
+ # targets.
15
+ # :per_target - The validator will be invoked for each target
16
+ # separately.
17
+ # @abstract
18
+ def invoke_style
19
+ :once
20
+ end
21
+
22
+ # Whether this Validator can be invoked in this context. By default any InvokableValidator can work in any Context, except ::None
23
+ # @see PDK::Validate::Validator
24
+ def valid_in_context?
25
+ !context.is_a?(PDK::Context::None)
26
+ end
27
+
28
+ # An array, or a string, of glob patterns to use to find targets
29
+ # @return [Array[String], String]
30
+ # @abstract
31
+ def pattern; end
32
+
33
+ # An array, or a string, of glob patterns to use to ignore targets
34
+ # @return [Array[String], String, Nil]
35
+ # @abstract
36
+ def pattern_ignore; end
37
+
38
+ # @see PDK::Validate::Validator.prepare_invoke!
39
+ def prepare_invoke!
40
+ return if @prepared
41
+ super
42
+
43
+ # Register the spinner
44
+ spinner
45
+ nil
46
+ end
47
+
48
+ # Parses the target strings provided from the CLI
49
+ #
50
+ # @param options [Hash] A Hash containing the input options from the CLI.
51
+ #
52
+ # @return targets [Array] An Array of Strings containing target file paths
53
+ # for the validator to validate.
54
+ # @return skipped [Array] An Array of Strings containing targets
55
+ # that are skipped due to target not containing
56
+ # any files that can be validated by the validator.
57
+ # @return invalid [Array] An Array of Strings containing targets that do
58
+ # not exist, and will not be run by validator.
59
+ def parse_targets
60
+ requested_targets = options.fetch(:targets, [])
61
+ # If no targets are specified and empty targets are allowed return with an empty list.
62
+ # It will be up to the validator (and whatever validation tool it uses) to determine the
63
+ # targets. For example, using rubocop with no targets, will allow rubocop to determine the
64
+ # target list using it's .rubocop.yml file
65
+ return [[], [], []] if requested_targets.empty? && allow_empty_targets?
66
+ # If no targets are specified, then we will run validations from the base context directory.
67
+ targets = requested_targets.empty? ? [context.root_path] : requested_targets
68
+ targets.map! { |r| r.gsub(File::ALT_SEPARATOR, File::SEPARATOR) } if File::ALT_SEPARATOR
69
+
70
+ # If this validator is not valid in this context then skip all of the targets
71
+ return [[], targets, []] unless valid_in_context?
72
+
73
+ skipped = []
74
+ invalid = []
75
+ matched = targets.map { |target|
76
+ if pattern.nil?
77
+ target
78
+ else
79
+ if PDK::Util::Filesystem.directory?(target) # rubocop:disable Style/IfInsideElse
80
+ target_root = context.root_path
81
+ pattern_glob = Array(pattern).map { |p| PDK::Util::Filesystem.glob(File.join(target_root, p), File::FNM_DOTMATCH) }
82
+ target_list = pattern_glob.flatten
83
+ .select { |glob| PDK::Util::Filesystem.fnmatch(File.join(PDK::Util::Filesystem.expand_path(PDK::Util.canonical_path(target)), '*'), glob, File::FNM_DOTMATCH) }
84
+ .map { |glob| Pathname.new(glob).relative_path_from(Pathname.new(context.root_path)).to_s }
85
+
86
+ ignore_list = ignore_pathspec
87
+ target_list = target_list.reject { |file| ignore_list.match(file) }
88
+
89
+ if target_list.flatten.empty?
90
+ PDK.logger.info(_('Validator \'%{validator}\' skipped for \'%{target}\'. No files matching \'%{pattern}\' found to validate.') % { validator: name, target: target, pattern: pattern })
91
+
92
+ skipped << target
93
+ end
94
+
95
+ target_list
96
+ elsif PDK::Util::Filesystem.file?(target)
97
+ if Array(pattern).include? target
98
+ target
99
+ elsif Array(pattern).any? { |p| PDK::Util::Filesystem.fnmatch(PDK::Util::Filesystem.expand_path(p), PDK::Util::Filesystem.expand_path(target), File::FNM_DOTMATCH) }
100
+ target
101
+ else
102
+ skipped << target
103
+ next
104
+ end
105
+ else
106
+ invalid << target
107
+ next
108
+ end
109
+ end
110
+ }.compact.flatten.uniq
111
+ [matched, skipped, invalid]
112
+ end
113
+
114
+ # Whether the target parsing ignores "dotfiles" (e.g. .gitignore or .pdkignore) which are considered hidden files in POSIX
115
+ # @return [Boolean]
116
+ # @abstract
117
+ def ignore_dotfiles?
118
+ true
119
+ end
120
+
121
+ # @see PDK::Validate::Validator.spinner_text
122
+ # @abstract
123
+ def spinner_text
124
+ _('Running %{name} validator ...') % { name: name }
125
+ end
126
+
127
+ # @see PDK::Validate::Validator.spinner
128
+ def spinner
129
+ return nil unless spinners_enabled?
130
+ return @spinner unless @spinner.nil?
131
+ require 'pdk/cli/util/spinner'
132
+
133
+ @spinner = TTY::Spinner.new("[:spinner] #{spinner_text}", PDK::CLI::Util.spinner_opts_for_platform)
134
+ end
135
+
136
+ # Process any targets that were skipped by the validator and add the events to the validation report
137
+ # @param report [PDK::Report] The report to add the events to
138
+ # @param skipped [Array[String]] The list of skipped targets
139
+ def process_skipped(report, skipped = [])
140
+ skipped.each do |skipped_target|
141
+ PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target does not contain any files to validate (%{pattern}).') % { validator: name, target: skipped_target, pattern: pattern })
142
+ report.add_event(
143
+ file: skipped_target,
144
+ source: name,
145
+ message: _('Target does not contain any files to validate (%{pattern}).') % { pattern: pattern },
146
+ severity: :info,
147
+ state: :skipped,
148
+ )
149
+ end
150
+ end
151
+
152
+ # Process any targets that were invalid by the validator and add the events to the validation report
153
+ # @param report [PDK::Report] The report to add the events to
154
+ # @param invalid [Array[String]] The list of invalid targets
155
+ def process_invalid(report, invalid = [])
156
+ invalid.each do |invalid_target|
157
+ PDK.logger.debug(_('%{validator}: Skipped \'%{target}\'. Target file not found.') % { validator: name, target: invalid_target })
158
+ report.add_event(
159
+ file: invalid_target,
160
+ source: name,
161
+ message: _('File does not exist.'),
162
+ severity: :error,
163
+ state: :error,
164
+ )
165
+ end
166
+ end
167
+
168
+ # Controls how the validator behaves if not passed any targets.
169
+ #
170
+ # true - PDK will not pass the globbed targets to the validator command
171
+ # and it will instead rely on the underlying tool to find its
172
+ # own default targets.
173
+ # false - PDK will pass the globbed targets to the validator command.
174
+ # @abstract
175
+ def allow_empty_targets?
176
+ false
177
+ end
178
+
179
+ protected
180
+
181
+ # Takes the pattern used in a module context and transforms it depending on the
182
+ # context e.g. A Control Repo will use the module pattern in each module path
183
+ #
184
+ # @param [Array, String] The pattern when used in the module root. Does not start with '/'
185
+ #
186
+ # @return [Array[String]]
187
+ def contextual_pattern(module_pattern)
188
+ module_pattern = [module_pattern] unless module_pattern.is_a?(Array)
189
+ return module_pattern unless context.is_a?(PDK::Context::ControlRepo)
190
+ context.actualized_module_paths.map { |mod_path| module_pattern.map { |pat_path| mod_path + '/*/' + pat_path } }.flatten
191
+ end
192
+
193
+ private
194
+
195
+ # Helper method to collate the default ignored paths
196
+ # @return [PathSpec] Paths to ignore
197
+ def ignore_pathspec
198
+ ignore_pathspec = if context.is_a?(PDK::Context::Module)
199
+ require 'pdk/module'
200
+ PDK::Module.default_ignored_pathspec(ignore_dotfiles?)
201
+ elsif context.is_a?(PDK::Context::ControlRepo)
202
+ require 'pdk/control_repo'
203
+ PDK::ControlRepo.default_ignored_pathspec(ignore_dotfiles?)
204
+ else
205
+ PathSpec.new.tap do |ps|
206
+ ps.add('.*') if ignore_dotfiles?
207
+ end
208
+ end
209
+
210
+ unless pattern_ignore.nil?
211
+ Array(pattern_ignore).each do |pattern|
212
+ ignore_pathspec.add(pattern)
213
+ end
214
+ end
215
+
216
+ # block will always be [] because it is intialized in config
217
+ ignore_files = PDK.config.get_within_scopes('validate.ignore')
218
+ unless ignore_files.nil? || ignore_files.empty?
219
+ Array(ignore_files).each do |pattern|
220
+ ignore_pathspec.add(pattern)
221
+ end
222
+ end
223
+
224
+ ignore_pathspec
225
+ end
226
+ end
227
+ end
228
+ end