lib/pdk/generators/module.rb in pdk-0.2.0 vs lib/pdk/generators/module.rb in pdk-0.3.0

- old
+ new

@@ -1,45 +1,33 @@ require 'etc' require 'pathname' require 'fileutils' +require 'tty-prompt' require 'pdk' require 'pdk/logger' require 'pdk/module/metadata' require 'pdk/module/templatedir' require 'pdk/cli/exec' -require 'pdk/cli/input' +require 'pdk/cli/util/interview' require 'pdk/util' require 'pdk/util/version' module PDK module Generate class Module DEFAULT_TEMPLATE = 'https://github.com/puppetlabs/pdk-module-template'.freeze def self.invoke(opts = {}) - defaults = { - 'name' => "#{Etc.getlogin}-#{opts[:name]}", - 'version' => '0.1.0', - 'dependencies' => [ - { 'name' => 'puppetlabs-stdlib', 'version_requirement' => '>= 4.13.1 < 5.0.0' }, - ], - } - - defaults['license'] = opts[:license] if opts.key? :license target_dir = File.expand_path(opts[:target_dir]) if File.exist?(target_dir) raise PDK::CLI::FatalError, _("The destination directory '%{dir}' already exists") % { dir: target_dir } end - metadata = PDK::Module::Metadata.new(defaults) + metadata = prepare_metadata(opts) - module_interview(metadata, opts) unless opts[:'skip-interview'] # @todo Build way to get info by answers file - - metadata.update!('pdk-version' => PDK::Util::Version.version_string) - temp_target_dir = PDK::Util.make_tmpdir_name('pdk-module-target') prepare_module_directory(temp_target_dir) template_url = opts.fetch(:'template-url', DEFAULT_TEMPLATE) @@ -61,10 +49,35 @@ end FileUtils.mv(temp_target_dir, target_dir) end + def self.prepare_metadata(opts) + username = Etc.getlogin.gsub(%r{[^0-9a-z]}i, '') + username = 'username' if username == '' + if Etc.getlogin != username + PDK.logger.warn(_('Your username is not a valid Forge username, proceeding with the username %{username}' % { username: username })) + end + + defaults = { + 'name' => "#{username}-#{opts[:name]}", + 'version' => '0.1.0', + 'dependencies' => [ + { 'name' => 'puppetlabs-stdlib', 'version_requirement' => '>= 4.13.1 < 5.0.0' }, + ], + } + defaults['license'] = opts[:license] if opts.key? :license + + metadata = PDK::Module::Metadata.new(defaults) + + module_interview(metadata, opts) unless opts[:'skip-interview'] # @todo Build way to get info by answers file + + metadata.update!('pdk-version' => PDK::Util::Version.version_string) + + metadata + end + def self.prepare_module_directory(target_dir) [ File.join(target_dir, 'manifests'), File.join(target_dir, 'templates'), ].each do |dir| @@ -75,66 +88,101 @@ end end end def self.module_interview(metadata, opts = {}) - puts _( - 'We need to create a metadata.json file for this module. Please answer the ' \ - 'following questions; if the question is not applicable to this module, feel free ' \ - 'to leave it blank.', - ) + questions = [ + { + name: 'name', + question: _('What is your Puppet Forge username?'), + help: _('This will be used when uploading your module to the Forge. You can opt out of this at any time.'), + required: true, + validate_pattern: %r{\A[a-z0-9]+\Z}i, + validate_message: _('Forge usernames can only contain lowercase letters and numbers'), + default: metadata.data['author'], + }, + { + name: 'version', + question: _('What version is this module?'), + help: _('Puppet uses Semantic Versioning (semver.org) to version modules.'), + required: true, + validate_pattern: %r{\A[0-9]+\.[0-9]+\.[0-9]+}, + validate_message: _('Semantic Version numbers must be in the form MAJOR.MINOR.PATCH'), + default: metadata.data['version'], + }, + { + name: 'author', + question: _('Who wrote this module?'), + help: _('The person who gets credit for creating the module. '), + required: true, + default: metadata.data['author'], + }, + { + name: 'license', + question: _('What license does this module code fall under?'), + help: _('This should be an identifier from https://spdk.org/licenses/. Common values are "Apache-2.0", "MIT", or "proprietary".'), + required: true, + default: metadata.data['license'], + }, + { + name: 'summary', + question: _('How would you describe this module in a single sentence?'), + help: _('To help other Puppet users understand what the module does.'), + required: true, + default: metadata.data['summary'], + }, + { + name: 'source', + question: _("Where is this modules's source code repository?"), + help: _('Usually a GitHub URL'), + required: true, + default: metadata.data['source'], + }, + { + name: 'project_page', + question: _('Where can others go to learn more about this module?'), + help: _('A web site that offers full information about your module.'), + default: metadata.data['project_page'], + }, + { + name: 'issues_url', + question: _('Where can others go to file issues about this module?'), + help: _('A web site with a public bug tracker for your module.'), + default: metadata.data['issues_url'], + }, + ] - begin - puts '' - forge_user = PDK::CLI::Input.get(_('What is your Puppet Forge username?'), metadata.data['author']) - metadata.update!('name' => "#{forge_user}-#{opts[:name]}") - rescue StandardError => e - PDK.logger.error(_("We're sorry, we could not parse your module name: %{message}") % { message: e.message }) - retry - end + prompt = TTY::Prompt.new - begin - puts "\n" + _('Puppet uses Semantic Versioning (semver.org) to version modules.') - module_version = PDK::CLI::Input.get(_('What version is this module?'), metadata.data['version']) - metadata.update!('version' => module_version) - rescue StandardError => e - PDK.logger.error(_("We're sorry, we could not parse that as a Semantic Version: %{message}") % { message: e.message }) - retry - end + interview = PDK::CLI::Util::Interview.new(prompt) - puts '' - module_author = PDK::CLI::Input.get(_('Who wrote this module?'), metadata.data['author']) - metadata.update!('author' => module_author) + questions.reject! { |q| q[:name] == 'license' } if opts.key?(:license) - unless opts.key?(:license) - puts '' - module_license = PDK::CLI::Input.get(_('What license does this module code fall under?'), metadata.data['license']) - metadata.update!('license' => module_license) - end + interview.add_questions(questions) - puts '' - module_summary = PDK::CLI::Input.get(_('How would you describe this module in a single sentence?'), metadata.data['summary']) - metadata.update!('summary' => module_summary) + puts _( + "\nWe need to create a metadata.json file for this module, so we're going to ask you %{count} quick questions.\n" \ + "If the question is not applicable to this module, just leave the answer blank.\n\n", + ) % { count: interview.num_questions } - puts '' - module_source = PDK::CLI::Input.get(_("Where is this module's source code repository?"), metadata.data['source']) - metadata.update!('source' => module_source) + answers = interview.run - puts '' - module_page = PDK::CLI::Input.get(_('Where can others go to learn more about this module?'), metadata.data['project_page']) - metadata.update!('project_page' => module_page) + if answers.nil? + puts _('Interview cancelled, aborting...') + exit 0 + end - puts '' - module_issues = PDK::CLI::Input.get(_('Where can others go to file issues about this module?'), metadata.data['issues_url']) - metadata.update!('issues_url' => module_issues) + answers['name'] = "#{answers['name']}-#{opts[:name]}" + metadata.update!(answers) - puts puts '-' * 40 + puts _('SUMMARY') + puts '-' * 40 puts metadata.to_json puts '-' * 40 puts - unless PDK::CLI::Input.get(_('About to generate this module; continue?'), 'Y') =~ %r{^y(es)?$}i # rubocop:disable Style/GuardClause + unless prompt.yes?(_('About to generate this module; continue?')) # rubocop:disable Style/GuardClause puts _('Aborting...') exit 0 end end end