pdk 0.0.1 → 0.1.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.
data/exe/pdk ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'pdk/cli'
4
+
5
+ PDK::CLI.run(ARGV.dup)
@@ -0,0 +1,8 @@
1
+ require 'pdk/version'
2
+ require 'pdk/logger'
3
+ require 'pdk/i18n'
4
+ require 'pdk/generate'
5
+ require 'pdk/validate'
6
+ require 'pdk/report'
7
+
8
+ module PDK; end
@@ -0,0 +1,80 @@
1
+ require 'cri'
2
+
3
+ require 'pdk/cli/errors'
4
+ require 'pdk/cli/util/option_validator'
5
+ require 'pdk/cli/util/option_normalizer'
6
+ require 'pdk/logger'
7
+ require 'pdk/report'
8
+
9
+ require 'pdk/cli/new'
10
+ require 'pdk/cli/validate'
11
+ require 'pdk/cli/test'
12
+
13
+ module PDK
14
+ module CLI
15
+ def self.base_command
16
+ @base ||= Cri::Command.new.tap do |cmd|
17
+ cmd.modify do
18
+ name 'pdk'
19
+ usage _("pdk command [options]")
20
+ summary _("Puppet Development Kit")
21
+ description _("The shortest path to better modules.")
22
+
23
+ flag :h, :help, _("show help for this command") do |_, c|
24
+ puts c.help
25
+ exit 0
26
+ end
27
+
28
+ format_desc = _(
29
+ "Specify desired output format. Valid formats are '%{available_formats}'. " +
30
+ "You may also specify a file to which the formatted output will be directed, " +
31
+ "for example: '--format=junit:report.xml'. This option may be specified " +
32
+ "multiple times as long as each option specifies a distinct target file."
33
+ ) % {available_formats: PDK::Report.formats.join("', '")}
34
+
35
+ option :f, :format, format_desc, { argument: :required, multiple: true } do |values|
36
+ values.compact.each do |v|
37
+ if v.include?(':')
38
+ format = v.split(':', 2).first
39
+
40
+ PDK::CLI::Util::OptionValidator.enum(format, PDK::Report.formats)
41
+ else
42
+ PDK::CLI::Util::OptionValidator.enum(v, PDK::Report.formats)
43
+ end
44
+ end
45
+ end
46
+
47
+ flag :d, :debug, _("Enable debug output.") do |_, _|
48
+ PDK.logger.enable_debug_output
49
+ end
50
+ end
51
+
52
+ cmd.add_command(Cri::Command.new_basic_help)
53
+
54
+ cmd.add_command(PDK::CLI::New.command)
55
+ cmd.add_command(PDK::CLI::Validate.command)
56
+ cmd.add_command(PDK::CLI::Test.command)
57
+ end
58
+ end
59
+
60
+ def self.run(args)
61
+ base_command.run(args)
62
+ rescue PDK::CLI::FatalError => e
63
+ PDK.logger.fatal(e.message) if e.message
64
+
65
+ # If FatalError was raised as the result of another exception, send the
66
+ # details of that exception to the debug log. If there was no cause
67
+ # (FatalError raised on its own outside a rescue block), send the details
68
+ # of the FatalError exception to the debug log.
69
+ cause = e.cause
70
+ if cause.nil?
71
+ e.backtrace.each { |line| PDK.logger.debug(line) }
72
+ else
73
+ PDK.logger.debug("#{cause.class}: #{cause.message}")
74
+ cause.backtrace.each { |line| PDK.logger.debug(line) }
75
+ end
76
+
77
+ exit e.exit_code
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,12 @@
1
+ module PDK
2
+ module CLI
3
+ class FatalError < StandardError
4
+ attr_reader :exit_code
5
+
6
+ def initialize(msg = _("An unexpected error has occurred, try running the command again with --debug"), exit_code=1)
7
+ @exit_code = exit_code
8
+ super(msg)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,51 @@
1
+ require 'childprocess'
2
+ require 'tempfile'
3
+
4
+ module PDK
5
+ module CLI
6
+ module Exec
7
+ # TODO: decide how to handle multiple output targets when underlying tool doesn't support that
8
+ # TODO: decide what this method should return
9
+ # TODO: decide how/when to connect stdin to child process for things like pry
10
+ def self.execute(*cmd)
11
+ process = ChildProcess.build(*cmd)
12
+
13
+ process.io.stdout = Tempfile.new('stdout')
14
+ process.io.stderr = Tempfile.new('stderr')
15
+
16
+ begin
17
+ # start the process
18
+ process.start
19
+
20
+ # wait indefinitely for process to exit...
21
+ process.wait
22
+
23
+ stdout = process.io.stdout.open.read
24
+ stderr = process.io.stderr.open.read
25
+ ensure
26
+ process.io.stdout.close
27
+ process.io.stderr.close
28
+ end
29
+
30
+ {
31
+ :exit_code => process.exit_code,
32
+ :stdout => stdout,
33
+ :stderr => stderr
34
+ }
35
+ end
36
+
37
+ def self.pdk_basedir
38
+ @pdk_basedir ||= Gem.win_platform? ? 'C:/Program Files/Puppet Labs/DevelopmentKit' : '/opt/puppetlabs/sdk'
39
+ end
40
+
41
+ def self.git_bindir
42
+ @git_dir ||= File.join(pdk_basedir, 'private', 'git', 'bin')
43
+ end
44
+
45
+ def self.git(*args)
46
+ git_path = ENV['PDK_USE_SYSTEM_BINARIES'].nil? ? File.join(git_bindir, 'git') : 'git'
47
+ execute(git_path, *args)
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,28 @@
1
+ module PDK
2
+ module CLI
3
+ module Input
4
+ # Query the user for a value via STDIN.
5
+ #
6
+ # @param message [String] The message to be displayed to the user before
7
+ # accepting input.
8
+ # @param default [String] The default value to be used if the user
9
+ # provides a blank value.
10
+ #
11
+ # @return [String] The value provided by the user (or the supplied
12
+ # default value).
13
+ def self.get(message, default=nil)
14
+ print message
15
+ if default.nil?
16
+ print " [(none)]"
17
+ else
18
+ print " [#{default}]"
19
+ end
20
+
21
+ print "\n--> "
22
+ input = (STDIN.gets || '').chomp.strip
23
+ input = default if input == ''
24
+ input
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ require 'cri'
2
+ require 'pdk/cli/new/module'
3
+ require 'pdk/cli/new/class'
4
+
5
+ module PDK
6
+ module CLI
7
+ module New
8
+ def self.command
9
+ @new ||= Cri::Command.new.tap do |cmd|
10
+ cmd.modify do
11
+ name 'new'
12
+ usage _("new <type> [options]")
13
+ summary _("create a new module, etc.")
14
+ description _("Creates a new instance of <type> using the options relevant to that type of thing")
15
+
16
+ # print the help text for the 'new' sub command if no type has been
17
+ # provided.
18
+ run do |opts, args, cmd|
19
+ puts command.help
20
+ exit 1
21
+ end
22
+ end
23
+
24
+ cmd.add_command(PDK::CLI::New::Module.command)
25
+ cmd.add_command(PDK::CLI::New::PuppetClass.command)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,45 @@
1
+ require 'cri'
2
+ require 'pdk/cli/util/option_validator'
3
+
4
+ require 'pdk/generators/module'
5
+ require 'pdk/generators/puppet_class'
6
+
7
+ module PDK
8
+ module CLI
9
+ module New
10
+ class PuppetClass
11
+ include PDK::CLI::Util
12
+
13
+ def self.command
14
+ @puppet_class ||= Cri::Command.define do
15
+ name 'class'
16
+ usage _("class [options] <class_name> [parameter[:type]] [parameter[:type]] ...")
17
+ summary _("Create a new class named <class_name> using given options")
18
+
19
+ option nil, 'template-url', _("Specifies the URL to the template to use when creating the module. Defaults to the template used to create the module, otherwise %{default}") % {:default => PDK::Generate::Module::DEFAULT_TEMPLATE}, argument: :required
20
+
21
+ run do |opts, args, cmd|
22
+ class_name = args[0]
23
+ module_dir = Dir.pwd
24
+
25
+ if class_name.nil? || class_name.empty?
26
+ puts command.help
27
+ exit 1
28
+ end
29
+
30
+ unless PDK::CLI::Util::OptionValidator.is_valid_class_name?(class_name)
31
+ raise PDK::CLI::FatalError, _("'%{name}' is not a valid class name") % {name: class_name}
32
+ end
33
+
34
+ if args.length > 1
35
+ opts[:params] = args[1..-1].map { |r| PDK::CLI::Util::OptionNormalizer.parameter_specification(r) }
36
+ end
37
+
38
+ PDK::Generate::PuppetClass.new(module_dir, class_name, opts).run
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,55 @@
1
+ require 'cri'
2
+ require 'pdk/cli/util/option_validator'
3
+
4
+ require 'pdk/generators/module'
5
+
6
+ module PDK
7
+ module CLI
8
+ module New
9
+ class Module
10
+ include PDK::CLI::Util
11
+
12
+ def self.command
13
+ @module ||= Cri::Command.define do
14
+ name 'module'
15
+ usage _("module [options] <module_name> [target_dir]")
16
+ summary _("Create a new module named <module_name> using given options")
17
+
18
+ option nil, 'template-url', _("Specifies the URL to the template to use when creating the module. Defaults to %{default}") % {:default => PDK::Generate::Module::DEFAULT_TEMPLATE}, argument: :required
19
+
20
+ option nil, 'license', _("Specifies the license this module is written under. This should be a identifier from https://spdx.org/licenses/. Common values are 'Apache-2.0', 'MIT', or 'proprietary'."), argument: :required
21
+
22
+ option nil, 'vcs', _("Specifies the version control driver. Valid values: 'git', 'none'. Default: 'git'."), argument: :required
23
+
24
+ flag nil, 'skip-interview', _("When specified, skips interactive querying of metadata.")
25
+
26
+ run do |opts, args, cmd|
27
+ module_name = args[0]
28
+ target_dir = args[1]
29
+
30
+ if module_name.nil? || module_name.empty?
31
+ puts command.help
32
+ exit 1
33
+ end
34
+
35
+ unless OptionValidator.is_valid_module_name?(module_name)
36
+ error_msg = _(
37
+ "'%{module_name}' is not a valid module name.\n" +
38
+ "Module names must begin with a lowercase letter and can only include lowercase letters, digits, and underscores."
39
+ ) % {:module_name => module_name}
40
+ raise PDK::CLI::FatalError.new(error_msg)
41
+ end
42
+
43
+ opts[:name] = module_name
44
+ opts[:target_dir] = target_dir.nil? ? module_name : target_dir
45
+ opts[:vcs] ||= 'git'
46
+
47
+ PDK.logger.info(_("Creating new module: %{modname}") % {:modname => module_name})
48
+ PDK::Generate::Module.invoke(opts)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,23 @@
1
+ require 'cri'
2
+ require 'pdk/cli/tests/unit'
3
+ require 'pdk/report'
4
+
5
+
6
+ module PDK
7
+ module CLI
8
+ module Test
9
+
10
+ def self.command
11
+ @test ||= Cri::Command.new.tap do |cmd|
12
+ cmd.modify do
13
+ name 'test'
14
+ usage _("test [type] [options]")
15
+ summary _("Run tests.")
16
+ end
17
+
18
+ cmd.add_command(PDK::CLI::Test::Unit.command)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,52 @@
1
+ require 'cri'
2
+ require 'pdk/cli/util/option_validator'
3
+ require 'pdk/report'
4
+
5
+ require 'pdk/tests/unit'
6
+
7
+ module PDK
8
+ module CLI
9
+ module Test
10
+ class Unit
11
+ include PDK::CLI::Util
12
+
13
+ def self.command
14
+ @unit ||= Cri::Command.define do
15
+ name 'unit'
16
+ usage _("unit [options]")
17
+ summary _("Run unit tests.")
18
+
19
+ flag nil, :list, _("list all available unit tests and their descriptions")
20
+
21
+ option nil, :tests, _("a comma-separated list of tests to run"), argument: :required do |values|
22
+ OptionValidator.list(values)
23
+ end
24
+
25
+ option nil, :runner_options, _("options to pass through to the actual test-runner"), argument: :required
26
+
27
+ run do |opts, args, cmd|
28
+ report = nil
29
+
30
+ if opts[:list]
31
+ puts _("List of all available unit tests: (TODO)")
32
+ end
33
+
34
+ if opts[:tests]
35
+ tests = opts.fetch(:tests)
36
+ end
37
+
38
+ # Note: Reporting may be delegated to the validation tool itself.
39
+ if opts[:'report-file']
40
+ format = opts.fetch(:'report-format', PDK::Report.default_format)
41
+ report = Report.new(opts.fetch(:'report-file'), format)
42
+ end
43
+
44
+ puts _("Running unit tests: %{tests}") % {tests: tests}
45
+ PDK::Test::Unit.invoke(tests, report)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,44 @@
1
+ module PDK
2
+ module CLI
3
+ module Util
4
+ class OptionNormalizer
5
+ def self.comma_separated_list_to_array(list, options = {})
6
+ raise _("Error: expected comma separated list") unless OptionValidator.is_comma_separated_list?(list)
7
+ list.split(',').compact
8
+ end
9
+
10
+ # Parse one or more format:target pairs.
11
+ # @return [Array<Report>] An array of one or more Reports.
12
+ def self.report_formats(formats, options = {})
13
+ reports = []
14
+ formats.each do |f|
15
+ if f.include?(':')
16
+ format, target = f.split(':')
17
+ else
18
+ format, target = f, PDK::Report.default_target
19
+ end
20
+
21
+ reports << Report.new(target, format)
22
+ end
23
+
24
+ reports
25
+ end
26
+
27
+ def self.parameter_specification(value)
28
+ param_name, param_type = value.split(':', 2)
29
+ param_type = 'String' if param_type.nil?
30
+
31
+ unless PDK::CLI::Util::OptionValidator.is_valid_param_name?(param_name)
32
+ raise PDK::CLI::FatalError, _("'%{name}' is not a valid parameter name") % {name: param_name}
33
+ end
34
+
35
+ unless PDK::CLI::Util::OptionValidator.is_valid_data_type?(param_type)
36
+ raise PDK::CLI::FatalError, _("'%{type}' is not a valid data type") % {type: param_type}
37
+ end
38
+
39
+ {name: param_name, type: param_type}
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end