mirror of
https://github.com/inspec/inspec
synced 2024-11-22 12:43:07 +00:00
Basics of a working reporter plugin system
Signed-off-by: Clinton Wolfe <clintoncwolfe@gmail.com>
This commit is contained in:
parent
2e887a94af
commit
63d95b6b6b
11 changed files with 172 additions and 7 deletions
|
@ -328,21 +328,35 @@ module Inspec
|
|||
def validate_reporters!(reporters)
|
||||
return if reporters.nil?
|
||||
|
||||
# TODO: move this into a reporter plugin type system
|
||||
valid_types = %w{
|
||||
automate
|
||||
cli
|
||||
# These "reporters" are actually RSpec Formatters.
|
||||
# json-rspec is our alias for RSpec's json formatter.
|
||||
rspec_built_in_formatters = %w{
|
||||
documentation
|
||||
html
|
||||
json-rspec
|
||||
progress
|
||||
}
|
||||
|
||||
# These are true reporters, but have not been migrated to be plugins yet.
|
||||
unmigrated_reporters = %w{
|
||||
automate
|
||||
cli
|
||||
json
|
||||
json-automate
|
||||
json-min
|
||||
json-rspec
|
||||
junit
|
||||
progress
|
||||
yaml
|
||||
}
|
||||
|
||||
# Additional reporters may be loaded via plugins. They will have already been detected at
|
||||
# this point (see v2_loader.load_all in cli.rb) but they may not (and need not) be
|
||||
# activated at this point. We only care about their existance their name, for validations sake.
|
||||
plugin_reporters = Inspec::Plugin::V2::Registry.instance\
|
||||
.find_activators(plugin_type: :reporter)\
|
||||
.map(&:activator_name).map(&:to_s)
|
||||
|
||||
valid_types = rspec_built_in_formatters + unmigrated_reporters + plugin_reporters
|
||||
|
||||
reporters.each do |reporter_name, reporter_config|
|
||||
raise NotImplementedError, "'#{reporter_name}' is not a valid reporter type." unless valid_types.include?(reporter_name)
|
||||
|
||||
|
|
27
lib/inspec/plugin/v2/plugin_types/reporter.rb
Normal file
27
lib/inspec/plugin/v2/plugin_types/reporter.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
module Inspec::Plugin::V2::PluginType
|
||||
class Reporter < Inspec::Plugin::V2::PluginBase
|
||||
register_plugin_type(:reporter)
|
||||
|
||||
attr_reader :run_data
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
@run_data = config[:run_data]
|
||||
@output = ""
|
||||
end
|
||||
|
||||
def output(str, newline = true)
|
||||
@output << str
|
||||
@output << "\n" if newline
|
||||
end
|
||||
|
||||
def rendered_output
|
||||
@output
|
||||
end
|
||||
|
||||
# each reporter must implement #render
|
||||
def render
|
||||
raise NotImplementedError, "#{self.class} must implement a `#render` method to format its output."
|
||||
end
|
||||
end
|
||||
end
|
|
@ -30,7 +30,10 @@ module Inspec::Reporters
|
|||
when "yaml"
|
||||
reporter = Inspec::Reporters::Yaml.new(config)
|
||||
else
|
||||
raise NotImplementedError, "'#{name}' is not a valid reporter type."
|
||||
# If we made it here, it must be a plugin, and we know it exists (because we validated it in config.rb)
|
||||
activator = Inspec::Plugin::V2::Registry.instance.find_activator(plugin_type: :reporter, activator_name: name.to_sym)
|
||||
activator.activate!
|
||||
reporter = activator.implementation_class.new(config)
|
||||
end
|
||||
|
||||
# optional send_report method on reporter
|
||||
|
|
10
test/fixtures/config_dirs/reporter_plugin/plugins.json
vendored
Normal file
10
test/fixtures/config_dirs/reporter_plugin/plugins.json
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"plugins_config_version" : "1.0.0",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "inspec-reporter-test-fixture",
|
||||
"installation_type": "path",
|
||||
"installation_path": "test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture.rb"
|
||||
}
|
||||
]
|
||||
}
|
3
test/fixtures/plugins/inspec-reporter-test-fixture/README.md
vendored
Normal file
3
test/fixtures/plugins/inspec-reporter-test-fixture/README.md
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
# inspec-reporter-test-fixture
|
||||
|
||||
Reporter plugin used to test reporter plugin type in test/functional/plugins_test.rb
|
4
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture.rb
vendored
Normal file
4
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture.rb
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
libdir = File.dirname(__FILE__)
|
||||
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
||||
|
||||
require "inspec-reporter-test-fixture/plugin"
|
13
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture/plugin.rb
vendored
Normal file
13
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture/plugin.rb
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
require "inspec-reporter-test-fixture/version"
|
||||
|
||||
module InspecPlugins
|
||||
module ReporterTestFixture
|
||||
class Plugin < ::Inspec.plugin(2)
|
||||
plugin_name :'inspec-reporter-test-fixture'
|
||||
reporter :"test-fixture" do
|
||||
require "inspec-reporter-test-fixture/reporter"
|
||||
InspecPlugins::ReporterTestFixture::ReporterImplementation
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
25
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture/reporter.rb
vendored
Normal file
25
test/fixtures/plugins/inspec-reporter-test-fixture/lib/inspec-reporter-test-fixture/reporter.rb
vendored
Normal file
|
@ -0,0 +1,25 @@
|
|||
module InspecPlugins::ReporterTestFixture
|
||||
class ReporterImplementation < Inspec.plugin(2, :reporter)
|
||||
|
||||
# The test reporter plugin returns a single line of output, like this:
|
||||
# pXX:cYY:tZZ
|
||||
# where XX is the count of profiles
|
||||
# YY is the count of controls
|
||||
# ZZ is the count of tests
|
||||
def render
|
||||
profile_count = run_data[:profiles].count
|
||||
control_count = 0
|
||||
test_count = 0
|
||||
run_data[:profiles].each do |p|
|
||||
controls = p[:controls] || []
|
||||
control_count += controls.count
|
||||
controls.each do |c|
|
||||
tests = c[:results] || []
|
||||
test_count += tests.count
|
||||
end
|
||||
end
|
||||
|
||||
output("p#{profile_count}c#{control_count}t#{test_count}",true)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
module InspecPlugins
|
||||
module ReporterTestFixture
|
||||
VERSION = "0.1.0".freeze
|
||||
end
|
||||
end
|
|
@ -146,6 +146,28 @@ describe "input plugins" do
|
|||
end
|
||||
end
|
||||
|
||||
#=========================================================================================#
|
||||
# Reporter plugin type
|
||||
#=========================================================================================#
|
||||
describe "reporter plugins" do
|
||||
# The test reporter plugin returns a single line of output, like this:
|
||||
# pXX:cYY:tZZ
|
||||
# where XX is the count of profiles
|
||||
# YY is the count of controls
|
||||
# ZZ is the count of tests
|
||||
let(:env) { { INSPEC_CONFIG_DIR: "#{config_dir_path}/reporter_plugin" } }
|
||||
|
||||
# Test a flat profile - dependencies/profile_c is a simple one
|
||||
describe "when using a custom reporter on a profile with one control" do
|
||||
it "finds the single control" do
|
||||
cmd = "exec #{profile_path}/dependencies/profile_c --reporter test-fixture"
|
||||
run_result = run_inspec_process(cmd, env: env)
|
||||
_(run_result.stderr).must_be_empty
|
||||
_(run_result.stdout).must_include "p1c1t1"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#=========================================================================================#
|
||||
# inspec plugin command
|
||||
#=========================================================================================#
|
||||
|
|
39
test/unit/plugin/v2/api_reporter_test.rb
Normal file
39
test/unit/plugin/v2/api_reporter_test.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
require "helper"
|
||||
|
||||
require "inspec/plugin/v2"
|
||||
|
||||
describe "Reporter plugin type" do
|
||||
describe "when registering the plugin type superclass" do
|
||||
it "returns the superclass when calling the global defintion method" do
|
||||
klass = Inspec.plugin(2, :reporter)
|
||||
_(klass).must_be_kind_of Class
|
||||
_(klass).must_equal Inspec::Plugin::V2::PluginType::Reporter
|
||||
end
|
||||
|
||||
it "returns the superclass when referenced by alias" do
|
||||
klass = Inspec::Plugin::V2::PluginBase.base_class_for_type(:reporter)
|
||||
_(klass).must_be_kind_of Class
|
||||
_(klass).must_equal Inspec::Plugin::V2::PluginType::Reporter
|
||||
end
|
||||
|
||||
it "registers an activation dsl method" do
|
||||
klass = Inspec::Plugin::V2::PluginBase
|
||||
_(klass).must_respond_to :reporter
|
||||
end
|
||||
end
|
||||
|
||||
describe "when examining the specific plugin type API" do
|
||||
[
|
||||
# API instance methods
|
||||
:render, # pure virtual
|
||||
:output, # helper
|
||||
:rendered_output, # accessor
|
||||
:run_data, # accessor
|
||||
].each do |api_method|
|
||||
it "should define a '#{api_method}' method in the superclass" do
|
||||
klass = Inspec::Plugin::V2::PluginType::Reporter
|
||||
_(klass.method_defined?(api_method)).must_equal true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue