mirror of
https://github.com/inspec/inspec
synced 2024-11-26 22:50:36 +00:00
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 <jquick@chef.io>
This commit is contained in:
parent
4c3b03da19
commit
544204a44c
15 changed files with 160 additions and 157 deletions
|
@ -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'
|
|
@ -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
|
|
@ -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
|
12
lib/plugins/inspec-init/lib/inspec-init.rb
Normal file
12
lib/plugins/inspec-init/lib/inspec-init.rb
Normal file
|
@ -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
|
28
lib/plugins/inspec-init/lib/inspec-init/cli.rb
Normal file
28
lib/plugins/inspec-init/lib/inspec-init/cli.rb
Normal file
|
@ -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
|
81
lib/plugins/inspec-init/lib/inspec-init/renderer.rb
Normal file
81
lib/plugins/inspec-init/lib/inspec-init/renderer.rb
Normal file
|
@ -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
|
30
lib/plugins/inspec-init/test/functional/inspec_init_test.rb
Normal file
30
lib/plugins/inspec-init/test/functional/inspec_init_test.rb
Normal file
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -25,11 +25,11 @@ class PluginLoaderTests < MiniTest::Test
|
|||
@bundled_plugins = [
|
||||
:artifact,
|
||||
:compliance,
|
||||
:init,
|
||||
:supermarket,
|
||||
]
|
||||
@core_plugins = [
|
||||
:'inspec-habitat',
|
||||
:'inspec-init',
|
||||
]
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue