module Runbook::Generators class Project < Thor::Group include ::Runbook::Generators::Base source_root File.dirname(__FILE__) def self.description "Generate a project for your runbooks" end def self.long_description <<-LONG_DESC This generator generates a project for your runbooks. It creates a project skeleton to hold your runbooks, runbook extensions, shared code, configuration, tests, and dependencies. LONG_DESC end argument :name, desc: "The name of your project, e.x. acme_runbooks" class_option :"shared-lib-dir", type: :string, desc: "Target directory for shared runbook code" class_option :test, type: :string, enum: ["rspec", "minitest"], default: "rspec", desc: %Q{Test-suite, "rspec" or "minitest"} class_option :ci, type: :string, enum: ["github", "travis", "gitlab", "circle"], default: "github", desc: %Q{CI Service, "github", "travis", "gitlab", or "circle"} def init_gem bundle_exists = "which bundle 2>&1 1>/dev/null" raise "Please ensure bundle is installed" unless system(bundle_exists) bundler_version = Gem::Version.new(Bundler::VERSION) inside(parent_options[:root]) do test = "--test #{options[:test]}" ci = "--ci #{options[:ci]}" changelog = "--no-changelog" if bundler_version >= Gem::Version.new("2.2.8") continue = ( run("bundle gem #{_name} #{test} #{ci} --rubocop #{changelog} --no-coc --no-mit") || options[:pretend] ) exit 1 unless continue end end def remove_unneeded_files dirs = [ parent_options[:root], _name, ] gemspec_file = File.join(*dirs, "#{_name}.gemspec") if File.exist?(gemspec_file) @gemspec_file_contents = File.readlines(gemspec_file) end remove_file(gemspec_file) readme = File.join(*dirs, "README.md") remove_file(readme) gemfile = File.join(*dirs, "Gemfile") if File.exist?(gemfile) @gemfile_file_contents = File.readlines(gemfile) end remove_file(gemfile) base_file = File.join(*dirs, "lib", "#{_name}.rb") remove_file(base_file) version_file_path = [ "lib", _name, "version.rb", ] version_file = File.join(*dirs, *version_file_path) remove_file(version_file) end def shared_lib_dir msg = [ "Where should shared runbook code live?", "Use `lib/#{_name}` for runbook-only projects", "Use `lib/#{_name}/runbook` for projects used for non-runbook tasks", "Shared runbook code path:", ] if options.has_key?("shared-lib-dir") @shared_lib_dir = options["shared-lib-dir"] else @shared_lib_dir = ask(msg.join("\n")) end end def create_readme target = File.join( parent_options[:root], _name, "README.md", ) template("templates/README.md.tt", target) end def create_gemfile target = File.join( parent_options[:root], _name, "Gemfile", ) template("templates/Gemfile.tt", target) # Add development dependencies from gemspec if @gemspec_file_contents gems = @gemspec_file_contents.select do |line| line =~ / spec.add_development_dependency/ end.map do |line| line.gsub(/ spec.add_development_dependency/, "gem") end.join append_to_file(target, "\n#{gems}", verbose: false) end # Add gemfile gems if @gemfile_file_contents gems = @gemfile_file_contents.select do |line| line =~ /^gem / end.join append_to_file(target, "\n#{gems}", verbose: false) end end def create_base_file target = File.join( parent_options[:root], _name, "lib", "#{_name}.rb", ) template("templates/base_file.rb.tt", target) end def modify_rakefile target = File.join( parent_options[:root], _name, "Rakefile", ) gsub_file(target, /^require "bundler\/gem_tasks"\n/, "", verbose: false) end def create_ruby_version target = File.join( parent_options[:root], _name, ".ruby-version", ) create_file(target, "ruby-#{RUBY_VERSION}\n") end def create_ruby_gemset target = File.join( parent_options[:root], _name, ".ruby-gemset", ) create_file(target, "#{_name}\n") end def create_runbookfile target = File.join( parent_options[:root], _name, "Runbookfile", ) template("templates/Runbookfile.tt", target) end def create_runbooks_directory dirs = [ parent_options[:root], _name, "runbooks", ] target = File.join(*dirs) empty_directory(target) _keep_dir(target) end def create_extensions_directory dirs = [ parent_options[:root], _name, "lib", "runbook", "extensions", ] target = File.join(*dirs) empty_directory(target) _keep_dir(target) end def create_generators_directory dirs = [ parent_options[:root], _name, "lib", "runbook", "generators", ] target = File.join(*dirs) empty_directory(target) _keep_dir(target) end def create_lib_directory dirs = [ parent_options[:root], _name, @shared_lib_dir, ] target = File.join(*dirs) empty_directory(target) _keep_dir(target) end def update_bin_console path = [ parent_options[:root], _name, "bin", "console", ] target = File.join(*path) old_require = /require "#{_name}"/ new_require = %Q(require_relative "../lib/#{_name}") new_require += "\n\nRunbook::Configuration.load_config" gsub_file(target, old_require, new_require, verbose: false) old_require = /require "#{_name}"/ new_require = %Q(require_relative "../lib/#{_name}") gsub_file(target, old_require, new_require, verbose: false) end def remove_bad_test path = [ parent_options[:root], _name, ] case options["test"] when "rspec" path << "spec" path << "#{_name}_spec.rb" when "minitest" path << "test" path << "#{_name}_test.rb" end target = File.join(*path) bad_test = / .*version.*\n.*\n end\n\n/m gsub_file(target, bad_test, "", verbose: false) end def runbook_project_overview msg = [ "", "Your runbook project was successfully created.", "Remember to run `./bin/setup` in your project to install dependencies.", "Add runbooks to the `runbooks` directory.", "Add shared code to `#{@shared_lib_dir}`.", "Execute runbooks using `bundle exec runbook exec ` from your project root.", "See the README.md for more details.", "\n", ] say(msg.join("\n")) end private def _name @name ||= name.underscore end def _keep_dir(dir) create_file(File.join(dir, ".keep"), verbose: false) end end end