diff --git a/lib/inspec/config.rb b/lib/inspec/config.rb index 70c67b1ec..50a1f7489 100644 --- a/lib/inspec/config.rb +++ b/lib/inspec/config.rb @@ -341,6 +341,7 @@ module Inspec # Tracked on https://github.com/inspec/inspec/issues/3667 inspec_reporters_that_are_not_yet_plugins = %w{ automate + cli json json-automate junit @@ -354,12 +355,7 @@ module Inspec .find_activators(plugin_type: :reporter)\ .map(&:activator_name).map(&:to_s) - # Include CLI explicitly, because it is the default reporter and will usually not be - # present on the command line, and thus its plugin will not appear on the list. - valid_types = rspec_built_in_formatters + \ - inspec_reporters_that_are_not_yet_plugins + \ - plugin_reporters + \ - [ "cli" ] + valid_types = rspec_built_in_formatters + inspec_reporters_that_are_not_yet_plugins + 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) diff --git a/lib/inspec/reporters.rb b/lib/inspec/reporters.rb index 6d3991b67..9d8398a01 100644 --- a/lib/inspec/reporters.rb +++ b/lib/inspec/reporters.rb @@ -1,4 +1,5 @@ require "inspec/reporters/base" +require "inspec/reporters/cli" require "inspec/reporters/json" require "inspec/reporters/json_automate" require "inspec/reporters/junit" @@ -11,6 +12,8 @@ module Inspec::Reporters name, config = reporter.dup config[:run_data] = run_data case name + when "cli" + reporter = Inspec::Reporters::CLI.new(config) when "json" reporter = Inspec::Reporters::Json.new(config) # This reporter is only used for Chef internal. We reserve the diff --git a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter.rb b/lib/inspec/reporters/cli.rb similarity index 75% rename from lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter.rb rename to lib/inspec/reporters/cli.rb index bda3191c0..6ed979c20 100644 --- a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter.rb +++ b/lib/inspec/reporters/cli.rb @@ -1,8 +1,5 @@ -require "forwardable" - -module InspecPlugins::CliReporter - class Reporter < Inspec.plugin(2, :reporter) - +module Inspec::Reporters + class CLI < Base case RUBY_PLATFORM when /windows|mswin|msys|mingw|cygwin/ # Most currently available Windows terminals have poor support @@ -43,15 +40,11 @@ module InspecPlugins::CliReporter MULTI_TEST_CONTROL_SUMMARY_MAX_LEN = 60 - def self.run_data_schema_constraints - "~> 0.0" - end - def render - run_data.profiles.each do |profile| - if profile.status == "skipped" - platform = run_data.platform - output("Skipping profile: '#{profile.name}' on unsupported platform: '#{platform.name}/#{platform.release}'.") + run_data[:profiles].each do |profile| + if profile[:status] == "skipped" + platform = run_data[:platform] + output("Skipping profile: '#{profile[:name]}' on unsupported platform: '#{platform[:name]}/#{platform[:release]}'.") next end @control_count = 0 @@ -77,9 +70,9 @@ module InspecPlugins::CliReporter def print_profile_header(profile) header = { "Profile" => format_profile_name(profile), - "Version" => profile.version || "(not specified)", + "Version" => profile[:version] || "(not specified)", } - header["Target"] = run_data.platform.target unless run_data.platform.target.nil? + header["Target"] = run_data[:platform][:target] unless run_data[:platform][:target].nil? header["Target ID"] = @config["target_id"] unless @config["target_id"].nil? pad = header.keys.max_by(&:length).length + 1 @@ -91,8 +84,8 @@ module InspecPlugins::CliReporter def print_standard_control_results(profile) standard_controls_from_profile(profile).each do |control_from_profile| - control = ControlForCliDisplay.new(control_from_profile) - next if control.results.empty? + control = Control.new(control_from_profile) + next if control.results.nil? output(format_control_header(control)) control.results.each do |result| @@ -105,8 +98,8 @@ module InspecPlugins::CliReporter def print_anonymous_control_results(profile) anonymous_controls_from_profile(profile).each do |control_from_profile| - control = ControlForCliDisplay.new(control_from_profile) - next if control.results.empty? + control = Control.new(control_from_profile) + next if control.results.nil? output(format_control_header(control)) control.results.each do |result| @@ -117,10 +110,10 @@ module InspecPlugins::CliReporter end def format_profile_name(profile) - if profile.title.nil? - (profile.name || "unknown").to_s + if profile[:title].nil? + (profile[:name] || "unknown").to_s else - "#{profile.title} (#{profile.name || "unknown"})" + "#{profile[:title]} (#{profile[:name] || "unknown"})" end end @@ -136,16 +129,16 @@ module InspecPlugins::CliReporter def format_result(control, result, type) impact = control.impact_string_for_result(result) - message = if result.status == "skipped" - result.skip_message + message = if result[:status] == "skipped" + result[:skip_message] elsif type == :anonymous - result.expectation_message + result[:expectation_message] else - result.code_desc + result[:code_desc] end # append any failure details to the message if they exist - message += "\n#{result.message}" if result.message + message += "\n#{result[:message]}" if result[:message] format_message( color: impact, @@ -177,7 +170,9 @@ module InspecPlugins::CliReporter def all_unique_controls @unique_controls ||= begin - run_data.profiles.flat_map(&:controls).uniq + run_data[:profiles].flat_map do |profile| + profile[:controls] + end.uniq end end @@ -187,12 +182,12 @@ module InspecPlugins::CliReporter passed = 0 all_unique_controls.each do |control| - next if control.id.start_with? "(generated from " - next if control.results.empty? + next if control[:id].start_with? "(generated from " + next unless control[:results] - if control.results.any? { |r| r.status == "failed" } + if control[:results].any? { |r| r[:status] == "failed" } failed += 1 - elsif control.results.any? { |r| r.status == "skipped" } + elsif control[:results].any? { |r| r[:status] == "skipped" } skipped += 1 else passed += 1 @@ -216,12 +211,12 @@ module InspecPlugins::CliReporter passed = 0 all_unique_controls.each do |control| - next if control.results.empty? + next unless control[:results] - control.results.each do |result| - if result.status == "failed" + control[:results].each do |result| + if result[:status] == "failed" failed += 1 - elsif result.status == "skipped" + elsif result[:status] == "skipped" skipped += 1 else passed += 1 @@ -278,30 +273,42 @@ module InspecPlugins::CliReporter end def standard_controls_from_profile(profile) - profile.controls.reject { |c| is_anonymous_control?(c) } + profile[:controls].reject { |c| is_anonymous_control?(c) } end def anonymous_controls_from_profile(profile) - profile.controls.select { |c| is_anonymous_control?(c) && !c[:results].nil? } + profile[:controls].select { |c| is_anonymous_control?(c) && !c[:results].nil? } end def is_anonymous_control?(control) - control.id.start_with?("(generated from ") + control[:id].start_with?("(generated from ") end def indent_lines(message, indentation) message.lines.map { |line| " " * indentation + line }.join end - class ControlForCliDisplay + class Control + attr_reader :data - extend Forwardable + def initialize(control_hash) + @data = control_hash + end - attr_reader :control_obj - def_delegators :@control_obj, :id, :impact, :results, :title + def id + data[:id] + end - def initialize(control_obj) - @control_obj = control_obj + def title + data[:title] + end + + def results + data[:results] + end + + def impact + data[:impact] end def anonymous? @@ -310,9 +317,9 @@ module InspecPlugins::CliReporter def title_for_report # if this is an anonymous control, just grab the resource title from any result entry - return results.first.resource_title if anonymous? + return results.first[:resource_title] if anonymous? - title_for_report = "#{id}: #{title || results.first.resource_title}" + title_for_report = "#{id}: #{title || results.first[:resource_title]}" # we will not add any additional data to the title if there's only # zero or one test for this control. @@ -330,9 +337,9 @@ module InspecPlugins::CliReporter nil elsif impact.nil? "unknown" - elsif results&.find { |r| r.status == "skipped" } + elsif results&.find { |r| r[:status] == "skipped" } "skipped" - elsif results.empty? || results.all? { |r| r.status == "passed" } + elsif results.nil? || results.empty? || results.all? { |r| r[:status] == "passed" } "passed" else "failed" @@ -340,9 +347,9 @@ module InspecPlugins::CliReporter end def impact_string_for_result(result) - if result.status == "skipped" + if result[:status] == "skipped" "skipped" - elsif result.status == "passed" + elsif result[:status] == "passed" "passed" elsif impact.nil? "unknown" @@ -352,11 +359,11 @@ module InspecPlugins::CliReporter end def failure_count - results.select { |r| r.status == "failed" }.size + results.select { |r| r[:status] == "failed" }.size end def skipped_count - results.select { |r| r.status == "skipped" }.size + results.select { |r| r[:status] == "skipped" }.size end end end diff --git a/lib/plugins/inspec-reporter-cli/README.md b/lib/plugins/inspec-reporter-cli/README.md deleted file mode 100644 index 16574e92f..000000000 --- a/lib/plugins/inspec-reporter-cli/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# cli reporter - -This is the implementation of the "cli" reporter. It is the default reporter used if you do not specify a reporter. - -## To Install This Plugin - -This plugin is included with inspec. There is no need to install it separately. - -## What This Plugin Does - -This reporter generates a summary of output at the end of the run to STDOUT by default. By default it uses color and terminal graphics if possible, depending on the capabilities of the host platform. - diff --git a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli.rb b/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli.rb deleted file mode 100644 index f2d62ed6a..000000000 --- a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative "inspec-reporter-cli/version" - -module InspecPlugins - module CliReporter - class Plugin < ::Inspec.plugin(2) - plugin_name :'inspec-reporter-cli' - reporter :cli do - require_relative "inspec-reporter-cli/reporter" - InspecPlugins::CliReporter::Reporter - end - end - end -end diff --git a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/version.rb b/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/version.rb deleted file mode 100644 index 3e4821b71..000000000 --- a/lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/version.rb +++ /dev/null @@ -1,5 +0,0 @@ -module InspecPlugins - module CliReporter - VERSION = "0.1.0".freeze - end -end diff --git a/test/unit/reporters/cli_test.rb b/test/unit/reporters/cli_test.rb index 753d8ef4e..04c03c350 100644 --- a/test/unit/reporters/cli_test.rb +++ b/test/unit/reporters/cli_test.rb @@ -1,17 +1,16 @@ require "helper" -require_relative "../../../lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli" -require_relative "../../../lib/plugins/inspec-reporter-cli/lib/inspec-reporter-cli/reporter" +require "inspec/reporters" -describe InspecPlugins::CliReporter::Reporter do +describe Inspec::Reporters::CLI do WINDOWS = RUBY_PLATFORM =~ /windows|mswin|msys|mingw|cygwin/ let(:report) do data = JSON.parse(File.read("test/fixtures/reporters/run_data.json"), symbolize_names: true) - cli = InspecPlugins::CliReporter::Reporter + cli = Inspec::Reporters::CLI cli.new({ run_data: data }) end let(:profile) { report.run_data[:profiles].first } - let(:control) { InspecPlugins::CliReporter::Reporter::ControlForCliDisplay } + let(:control) { Inspec::Reporters::CLI::Control } before do RSpec.configuration.color = true if defined?(RSpec.configuration) @@ -123,7 +122,7 @@ describe InspecPlugins::CliReporter::Reporter do let(:profile_control) do control.new(profile[:controls].first) end - let(:result) { profile_control.control_obj.results.first } + let(:result) { profile_control.data[:results].first } it "confirm standard result" do output = report.send(:format_result, profile_control, result, :standard)