mirror of
https://github.com/inspec/inspec
synced 2024-11-22 20:53:11 +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)
|
def validate_reporters!(reporters)
|
||||||
return if reporters.nil?
|
return if reporters.nil?
|
||||||
|
|
||||||
# TODO: move this into a reporter plugin type system
|
# These "reporters" are actually RSpec Formatters.
|
||||||
valid_types = %w{
|
# json-rspec is our alias for RSpec's json formatter.
|
||||||
automate
|
rspec_built_in_formatters = %w{
|
||||||
cli
|
|
||||||
documentation
|
documentation
|
||||||
html
|
html
|
||||||
|
json-rspec
|
||||||
|
progress
|
||||||
|
}
|
||||||
|
|
||||||
|
# These are true reporters, but have not been migrated to be plugins yet.
|
||||||
|
unmigrated_reporters = %w{
|
||||||
|
automate
|
||||||
|
cli
|
||||||
json
|
json
|
||||||
json-automate
|
json-automate
|
||||||
json-min
|
json-min
|
||||||
json-rspec
|
|
||||||
junit
|
junit
|
||||||
progress
|
|
||||||
yaml
|
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|
|
reporters.each do |reporter_name, reporter_config|
|
||||||
raise NotImplementedError, "'#{reporter_name}' is not a valid reporter type." unless valid_types.include?(reporter_name)
|
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"
|
when "yaml"
|
||||||
reporter = Inspec::Reporters::Yaml.new(config)
|
reporter = Inspec::Reporters::Yaml.new(config)
|
||||||
else
|
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
|
end
|
||||||
|
|
||||||
# optional send_report method on reporter
|
# 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
|
||||||
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
|
# 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