From 544204a44c66ad3df9211fcf56c3fba3b6893058 Mon Sep 17 00:00:00 2001 From: Jared Quick Date: Tue, 18 Sep 2018 15:54:33 -0400 Subject: [PATCH] Move inspec init to v2 plugins (#3407) * Move inspec init to v2 plugins. * Revert inspec run command env change. * Allow prefix and env for run_inspec_process. * Update unit tests to use new functionality. Signed-off-by: Jared Quick --- lib/bundles/inspec-init.rb | 12 --- lib/bundles/inspec-init/cli.rb | 39 --------- lib/bundles/inspec-init/renderer.rb | 79 ------------------ .../inspec-init/README.md | 0 lib/plugins/inspec-init/lib/inspec-init.rb | 12 +++ .../inspec-init/lib/inspec-init/cli.rb | 28 +++++++ .../inspec-init/lib/inspec-init/renderer.rb | 81 +++++++++++++++++++ .../inspec-init/templates/profile/README.md | 0 .../templates/profile/controls/example.rb | 0 .../inspec-init/templates/profile/inspec.yml | 0 .../templates/profile/libraries/.gitkeep | 0 .../test/functional/inspec_init_test.rb | 30 +++++++ lib/plugins/shared/core_plugin_test_helper.rb | 11 ++- test/functional/inspec_init_test.rb | 23 ------ test/unit/plugin/v2/loader_test.rb | 2 +- 15 files changed, 160 insertions(+), 157 deletions(-) delete mode 100644 lib/bundles/inspec-init.rb delete mode 100644 lib/bundles/inspec-init/cli.rb delete mode 100644 lib/bundles/inspec-init/renderer.rb rename lib/{bundles => plugins}/inspec-init/README.md (100%) create mode 100644 lib/plugins/inspec-init/lib/inspec-init.rb create mode 100644 lib/plugins/inspec-init/lib/inspec-init/cli.rb create mode 100644 lib/plugins/inspec-init/lib/inspec-init/renderer.rb rename lib/{bundles => plugins/inspec-init/lib}/inspec-init/templates/profile/README.md (100%) rename lib/{bundles => plugins/inspec-init/lib}/inspec-init/templates/profile/controls/example.rb (100%) rename lib/{bundles => plugins/inspec-init/lib}/inspec-init/templates/profile/inspec.yml (100%) rename lib/{bundles => plugins/inspec-init/lib}/inspec-init/templates/profile/libraries/.gitkeep (100%) create mode 100644 lib/plugins/inspec-init/test/functional/inspec_init_test.rb delete mode 100644 test/functional/inspec_init_test.rb diff --git a/lib/bundles/inspec-init.rb b/lib/bundles/inspec-init.rb deleted file mode 100644 index 929524957..000000000 --- a/lib/bundles/inspec-init.rb +++ /dev/null @@ -1,12 +0,0 @@ -# encoding: utf-8 -# author: Christoph Hartmann -# author: Dominik Richter - -libdir = File.dirname(__FILE__) -$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir) - -module Init - autoload :Profile, 'inspec-init/profile' -end - -require 'inspec-init/cli' diff --git a/lib/bundles/inspec-init/cli.rb b/lib/bundles/inspec-init/cli.rb deleted file mode 100644 index 79c6f9bfe..000000000 --- a/lib/bundles/inspec-init/cli.rb +++ /dev/null @@ -1,39 +0,0 @@ -# encoding: utf-8 - -require 'pathname' -require_relative 'renderer' -require 'inspec/base_cli' - -module Init - class CLI < Inspec::BaseCLI - namespace 'init' - - # TODO: find another solution, once https://github.com/erikhuda/thor/issues/261 is fixed - def self.banner(command, _namespace = nil, _subcommand = false) - "#{basename} #{subcommand_prefix} #{command.usage}" - end - - def self.subcommand_prefix - namespace - end - - # Look in the 'template' directory, and register a subcommand - # for each template directory found there. - template_dir = File.join(File.dirname(__FILE__), 'templates') - Dir.glob(File.join(template_dir, '*')) do |template| - template_name = Pathname.new(template).relative_path_from(Pathname.new(template_dir)).to_s - - # register command for the template - desc "#{template_name} NAME", "Create a new #{template_name}" - option :overwrite, type: :boolean, default: false, - desc: 'Overwrites existing directory' - define_method template_name.to_sym do |name_for_new_structure| - renderer = Init::Renderer.new(self, options) - renderer.render_with_values(template_name, name: name_for_new_structure) - end - end - end - - # register the subcommand to Inspec CLI registry - Inspec::Plugins::CLI.add_subcommand(Init::CLI, 'init', 'init TEMPLATE ...', 'Scaffolds a new project', {}) -end diff --git a/lib/bundles/inspec-init/renderer.rb b/lib/bundles/inspec-init/renderer.rb deleted file mode 100644 index 83377bfdf..000000000 --- a/lib/bundles/inspec-init/renderer.rb +++ /dev/null @@ -1,79 +0,0 @@ -require 'fileutils' -require 'erb' - -module Init - class Renderer - # Creates a renderer able to render the given template type - # 1. iterate over all files - # 2. read content in erb - # 3. write to full_destination_root_path - - attr_reader :overwrite_mode, :ui - def initialize(cli_ui, cli_options = {}) - @ui = cli_ui - @overwrite_mode = cli_options['overwrite'] - end - - # rubocop: disable Metrics/AbcSize - def render_with_values(template_type, template_values = {}) - # look for template directory - base_dir = File.join(File.dirname(__FILE__), 'templates', template_type) - # prepare glob for all subdirectories and files - template_glob = File.join(base_dir, '**', '{*,.*}') - # Use the name attribute to define the path to the profile. - profile_path = template_values[:name] - # Use slashes (\, /) to split up the name into an Array then use the last entry - # to reset the name of the profile. - template_values[:name] = template_values[:name].split(%r{\\|\/}).last - # Generate the full full_destination_root_path path on disk - full_destination_root_path = Pathname.new(Dir.pwd).join(profile_path) - ui.plain_text "Create new #{template_type} at #{ui.mark_text(full_destination_root_path)}" - - # check that the directory does not exist - if File.exist?(full_destination_root_path) && !overwrite_mode - ui.plain_text "#{ui.mark_text(full_destination_root_path)} exists already, use --overwrite" - ui.exit(1) - end - - # ensure that full_destination_root_path directory is available - FileUtils.mkdir_p(full_destination_root_path) - - # iterate over files and write to full_destination_root_path - Dir.glob(template_glob) do |file| - relative_destination_item_path = Pathname.new(file).relative_path_from(Pathname.new(base_dir)) - full_destination_item_path = Pathname.new(full_destination_root_path).join(relative_destination_item_path) - if File.directory?(file) - ui.li "Create directory #{ui.mark_text(relative_destination_item_path)}" - FileUtils.mkdir_p(full_destination_item_path) - elsif File.file?(file) - ui.li "Create file #{ui.mark_text(relative_destination_item_path)}" - # read & render content - content = render(File.read(file), template_values) - # write file content - File.write(full_destination_item_path, content) - else - ui.plain_text "Ignore #{file}, because its not an file or directoy" - end - end - end - # rubocop: enable Metrics/AbcSize - - # This is a render helper to bind hash values to a ERB template - # ERB provides result_with_hash in ruby 2.5.0+, which does exactly this - def render(template_content, hash) - # create a new binding class - cls = Class.new do - hash.each do |key, value| - define_method key.to_sym do - value - end - end - # expose binding - define_method :bind do - binding - end - end - ERB.new(template_content).result(cls.new.bind) - end - end -end diff --git a/lib/bundles/inspec-init/README.md b/lib/plugins/inspec-init/README.md similarity index 100% rename from lib/bundles/inspec-init/README.md rename to lib/plugins/inspec-init/README.md diff --git a/lib/plugins/inspec-init/lib/inspec-init.rb b/lib/plugins/inspec-init/lib/inspec-init.rb new file mode 100644 index 000000000..3601e9690 --- /dev/null +++ b/lib/plugins/inspec-init/lib/inspec-init.rb @@ -0,0 +1,12 @@ +module InspecPlugins + module Init + class Plugin < Inspec.plugin(2) + plugin_name :'inspec-init' + + cli_command :init do + require_relative 'inspec-init/cli' + InspecPlugins::Init::CLI + end + end + end +end diff --git a/lib/plugins/inspec-init/lib/inspec-init/cli.rb b/lib/plugins/inspec-init/lib/inspec-init/cli.rb new file mode 100644 index 000000000..c447819c3 --- /dev/null +++ b/lib/plugins/inspec-init/lib/inspec-init/cli.rb @@ -0,0 +1,28 @@ +# encoding: utf-8 + +require 'pathname' +require_relative 'renderer' + +module InspecPlugins + module Init + class CLI < Inspec.plugin(2, :cli_command) + subcommand_desc 'init SUBCOMMAND', 'Initialize InSpec objects' + + # Look in the 'template' directory, and register a subcommand + # for each template directory found there. + template_dir = File.join(File.dirname(__FILE__), 'templates') + Dir.glob(File.join(template_dir, '*')) do |template| + template_name = Pathname.new(template).relative_path_from(Pathname.new(template_dir)).to_s + + # register command for the template + desc "#{template_name} NAME", "Create a new #{template_name}" + option :overwrite, type: :boolean, default: false, + desc: 'Overwrites existing directory' + define_method template_name.to_sym do |name_for_new_structure| + renderer = InspecPlugins::Init::Renderer.new(self, options) + renderer.render_with_values(template_name, name: name_for_new_structure) + end + end + end + end +end diff --git a/lib/plugins/inspec-init/lib/inspec-init/renderer.rb b/lib/plugins/inspec-init/lib/inspec-init/renderer.rb new file mode 100644 index 000000000..28b38fb47 --- /dev/null +++ b/lib/plugins/inspec-init/lib/inspec-init/renderer.rb @@ -0,0 +1,81 @@ +require 'fileutils' +require 'erb' + +module InspecPlugins + module Init + class Renderer + # Creates a renderer able to render the given template type + # 1. iterate over all files + # 2. read content in erb + # 3. write to full_destination_root_path + + attr_reader :overwrite_mode, :ui + def initialize(cli_ui, cli_options = {}) + @ui = cli_ui + @overwrite_mode = cli_options['overwrite'] + end + + # rubocop: disable Metrics/AbcSize + def render_with_values(template_type, template_values = {}) + # look for template directory + base_dir = File.join(File.dirname(__FILE__), 'templates', template_type) + # prepare glob for all subdirectories and files + template_glob = File.join(base_dir, '**', '{*,.*}') + # Use the name attribute to define the path to the profile. + profile_path = template_values[:name] + # Use slashes (\, /) to split up the name into an Array then use the last entry + # to reset the name of the profile. + template_values[:name] = template_values[:name].split(%r{\\|\/}).last + # Generate the full full_destination_root_path path on disk + full_destination_root_path = Pathname.new(Dir.pwd).join(profile_path) + ui.plain_text "Create new #{template_type} at #{ui.mark_text(full_destination_root_path)}" + + # check that the directory does not exist + if File.exist?(full_destination_root_path) && !overwrite_mode + ui.plain_text "#{ui.mark_text(full_destination_root_path)} exists already, use --overwrite" + ui.exit(1) + end + + # ensure that full_destination_root_path directory is available + FileUtils.mkdir_p(full_destination_root_path) + + # iterate over files and write to full_destination_root_path + Dir.glob(template_glob) do |file| + relative_destination_item_path = Pathname.new(file).relative_path_from(Pathname.new(base_dir)) + full_destination_item_path = Pathname.new(full_destination_root_path).join(relative_destination_item_path) + if File.directory?(file) + ui.li "Create directory #{ui.mark_text(relative_destination_item_path)}" + FileUtils.mkdir_p(full_destination_item_path) + elsif File.file?(file) + ui.li "Create file #{ui.mark_text(relative_destination_item_path)}" + # read & render content + content = render(File.read(file), template_values) + # write file content + File.write(full_destination_item_path, content) + else + ui.plain_text "Ignore #{file}, because its not an file or directoy" + end + end + end + # rubocop: enable Metrics/AbcSize + + # This is a render helper to bind hash values to a ERB template + # ERB provides result_with_hash in ruby 2.5.0+, which does exactly this + def render(template_content, hash) + # create a new binding class + cls = Class.new do + hash.each do |key, value| + define_method key.to_sym do + value + end + end + # expose binding + define_method :bind do + binding + end + end + ERB.new(template_content).result(cls.new.bind) + end + end + end +end diff --git a/lib/bundles/inspec-init/templates/profile/README.md b/lib/plugins/inspec-init/lib/inspec-init/templates/profile/README.md similarity index 100% rename from lib/bundles/inspec-init/templates/profile/README.md rename to lib/plugins/inspec-init/lib/inspec-init/templates/profile/README.md diff --git a/lib/bundles/inspec-init/templates/profile/controls/example.rb b/lib/plugins/inspec-init/lib/inspec-init/templates/profile/controls/example.rb similarity index 100% rename from lib/bundles/inspec-init/templates/profile/controls/example.rb rename to lib/plugins/inspec-init/lib/inspec-init/templates/profile/controls/example.rb diff --git a/lib/bundles/inspec-init/templates/profile/inspec.yml b/lib/plugins/inspec-init/lib/inspec-init/templates/profile/inspec.yml similarity index 100% rename from lib/bundles/inspec-init/templates/profile/inspec.yml rename to lib/plugins/inspec-init/lib/inspec-init/templates/profile/inspec.yml diff --git a/lib/bundles/inspec-init/templates/profile/libraries/.gitkeep b/lib/plugins/inspec-init/lib/inspec-init/templates/profile/libraries/.gitkeep similarity index 100% rename from lib/bundles/inspec-init/templates/profile/libraries/.gitkeep rename to lib/plugins/inspec-init/lib/inspec-init/templates/profile/libraries/.gitkeep diff --git a/lib/plugins/inspec-init/test/functional/inspec_init_test.rb b/lib/plugins/inspec-init/test/functional/inspec_init_test.rb new file mode 100644 index 000000000..266692d52 --- /dev/null +++ b/lib/plugins/inspec-init/test/functional/inspec_init_test.rb @@ -0,0 +1,30 @@ +# encoding: utf-8 + +require_relative '../../../shared/core_plugin_test_helper.rb' + +class InitCli < MiniTest::Test + include CorePluginFunctionalHelper + + def test_generating_inspec_profile + Dir.mktmpdir do |dir| + profile = File.join(dir, 'test-profile') + out = run_inspec_process("init profile test-profile", prefix: "cd #{dir} &&") + assert_equal 0, out.exit_status + assert_includes out.stdout, 'Create new profile at' + assert_includes out.stdout, profile + assert_includes Dir.entries(profile).join, 'inspec.yml' + assert_includes Dir.entries(profile).join, 'README.md' + end + end + + def test_profile_with_slash_name + Dir.mktmpdir do |dir| + profile = dir + '/test/deeper/profile' + out = run_inspec_process("init profile test/deeper/profile", prefix: "cd #{dir} &&") + assert_equal 0, out.exit_status + assert_equal true, File.exist?(profile) + profile = YAML.load_file("#{profile}/inspec.yml") + assert_equal 'profile', profile['name'] + end + end +end diff --git a/lib/plugins/shared/core_plugin_test_helper.rb b/lib/plugins/shared/core_plugin_test_helper.rb index a4a0c065f..a3fbf9df4 100644 --- a/lib/plugins/shared/core_plugin_test_helper.rb +++ b/lib/plugins/shared/core_plugin_test_helper.rb @@ -33,9 +33,14 @@ module CorePluginFunctionalHelper require 'train' TRAIN_CONNECTION = Train.create('local', command_runner: :generic).connection - def run_inspec_process(command_line, env = {}) - env_prefix = env.to_a.map { |assignment| "#{assignment[0]}=#{assignment[1]}" }.join(' ') - TRAIN_CONNECTION.run_command("#{env_prefix} #{inspec_bin_path} #{command_line}") + def run_inspec_process(command_line, opts = {}) + prefix = '' + if opts.key?(:prefix) + prefix = opts[:prefix] + elsif opts.key?(:env) + prefix = opts[:env].to_a.map { |assignment| "#{assignment[0]}=#{assignment[1]}" }.join(' ') + end + TRAIN_CONNECTION.run_command("#{prefix} #{inspec_bin_path} #{command_line}") end end diff --git a/test/functional/inspec_init_test.rb b/test/functional/inspec_init_test.rb deleted file mode 100644 index 187955063..000000000 --- a/test/functional/inspec_init_test.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'functional/helper' -require 'fileutils' -require 'tmpdir' -require 'yaml' - -describe 'inspec init' do - include FunctionalHelper - - tmpdir = Dir.tmpdir - - describe 'inspec init profile with/slash' do - it 'names profile with string after last slash' do - slash_profile = "#{tmpdir}/inspecwith/slash" - out = inspec("init profile #{slash_profile}") - out.exit_status.must_equal 0 - File.exist?(slash_profile).must_equal true - profile = YAML.load_file("#{slash_profile}/inspec.yml") - profile['name'].must_equal 'slash' - end - end - - Dir.glob("#{tmpdir}/inspecwith*").each {|i| FileUtils.remove_entry_secure(i) } -end diff --git a/test/unit/plugin/v2/loader_test.rb b/test/unit/plugin/v2/loader_test.rb index 78cb56779..da587cce2 100644 --- a/test/unit/plugin/v2/loader_test.rb +++ b/test/unit/plugin/v2/loader_test.rb @@ -25,11 +25,11 @@ class PluginLoaderTests < MiniTest::Test @bundled_plugins = [ :artifact, :compliance, - :init, :supermarket, ] @core_plugins = [ :'inspec-habitat', + :'inspec-init', ] end