CHEF-4115 Added ability to merge reporter configurations from both CLI and config (#6568) (#6579)

* Added ability to merge cli and config reporter options



* Test cases to validate working of reporter configuration using cli and config



* Documentation change to add information on reporter configurations usage with both



* Added Doc review changes and text fixture for config json



* Verify fix



* Verify pipeline test fixes for reporter options to be read successfully



* Test changes in both cli and config reporter usage scenarios to fix verify pipeline



* Review comments to improvise



* Renamed testing fixture file for reporter cli config file



---------

Signed-off-by: Nikita Mathur <nikita.mathur@chef.io>
Co-authored-by: Nikita Mathur <Nik08@users.noreply.github.com>
This commit is contained in:
Clinton Wolfe 2023-07-25 08:45:42 -04:00 committed by GitHub
parent 3146906c3e
commit eff13369f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 13 deletions

View file

@ -15,7 +15,7 @@ A `reporter` is a facility for formatting and delivering the results of a Chef I
Chef InSpec allows you to output your test results to one or more reporters. Chef InSpec allows you to output your test results to one or more reporters.
Configure the reporter(s) using either the `--reporter` option or as part of the general configuration file using the `--config` (or `--json-config`, prior to v3.6) option. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout). Configure the reporter(s) using the `--reporter` option or as part of the general configuration file using the `--config` (or `--json-config`, prior to v3.6) option. Both the --reporter and --config options may be used, in which case the options are merged. While you can configure multiple reporters to write to different files, only one reporter can output to the screen(stdout).
## Syntax ## Syntax

View file

@ -561,7 +561,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI
end end
def run_command(opts) def run_command(opts)
runner = Inspec::Runner.new(Inspec::Config.new(opts)) runner = Inspec::Runner.new(opts)
res = runner.eval_with_virtual_profile(opts[:command]) res = runner.eval_with_virtual_profile(opts[:command])
runner.load runner.load

View file

@ -448,6 +448,13 @@ module Inspec
# Reporter options may be defined top-level. # Reporter options may be defined top-level.
options.merge!(config_file_reporter_options) options.merge!(config_file_reporter_options)
if @cli_opts["reporter"]
# Add reporter_cli_opts in options to capture reporter cli opts separately
options.merge!({ "reporter_cli_opts" => @cli_opts["reporter"] })
# Delete reporter from cli_opts to avoid direct merging of reporter info of cli and config
@cli_opts.delete("reporter")
end
# Highest precedence: merge in any options defined via the CLI # Highest precedence: merge in any options defined via the CLI
options.merge!(@cli_opts) options.merge!(@cli_opts)
@ -476,13 +483,13 @@ module Inspec
end end
def finalize_parse_reporters(options) # rubocop:disable Metrics/AbcSize def finalize_parse_reporters(options) # rubocop:disable Metrics/AbcSize
# default to cli report for ad-hoc runners # Default to cli report for ad-hoc runners
options["reporter"] = ["cli"] if options["reporter"].nil? options["reporter_cli_opts"] = ["cli"] if (options["reporter"].nil? || options["reporter"].empty?) && options["reporter_cli_opts"].nil?
# parse out cli to proper report format # Parse out reporter_cli_opts to proper report format
if options["reporter"].is_a?(Array) if options["reporter_cli_opts"].is_a?(Array)
reports = {} reports = {}
options["reporter"].each do |report| options["reporter_cli_opts"].each do |report|
reporter_name, destination = report.split(":", 2) reporter_name, destination = report.split(":", 2)
if destination.nil? || destination.strip == "-" if destination.nil? || destination.strip == "-"
reports[reporter_name] = { "stdout" => true } reports[reporter_name] = { "stdout" => true }
@ -494,7 +501,12 @@ module Inspec
reports[reporter_name]["target_id"] = options["target_id"] if options["target_id"] reports[reporter_name]["target_id"] = options["target_id"] if options["target_id"]
end end
end end
options["reporter"] = reports
if options["reporter"].nil? || options["reporter"].empty?
options["reporter"] = reports
else
options["reporter"].merge!(reports)
end
end end
# add in stdout if not specified # add in stdout if not specified
@ -507,6 +519,10 @@ module Inspec
end end
validate_reporters!(options["reporter"]) validate_reporters!(options["reporter"])
# Delete reporter_cli_opts after graceful merging of cli and config reporters
options.delete("reporter_cli_opts")
options options
end end
@ -548,15 +564,12 @@ module Inspec
class Defaults class Defaults
DEFAULTS = { DEFAULTS = {
exec: { exec: {
"reporter" => ["cli"],
"show_progress" => false, "show_progress" => false,
"color" => true, "color" => true,
"create_lockfile" => true, "create_lockfile" => true,
"backend_cache" => true, "backend_cache" => true,
}, },
shell: { shell: {},
"reporter" => ["cli"],
},
}.freeze }.freeze
def self.for_command(command_name) def self.for_command(command_name)

View file

@ -0,0 +1,7 @@
{
"reporter": {
"cli" : {
"stdout" : true
}
}
}

View file

@ -81,7 +81,7 @@ describe "inputs" do
let(:common_options) do let(:common_options) do
{ {
profile: "#{inputs_profiles_path}/via-runner", profile: "#{inputs_profiles_path}/via-runner",
reporter: ["json"], "reporter" => ["json"],
} }
end end

View file

@ -1085,6 +1085,34 @@ describe "inspec exec" do
end end
end end
describe "When specifying a config file and --reporter option to configure reporter in a run in a correct manner" do
it "should obey the configurations of both --reporter and config reporter options" do
outpath = Dir.tmpdir
cli_args = "--no-create-lockfile --reporter json:#{outpath}/foo/bar/test.json --config " + File.join(config_dir_path, "json-config", "reporter-cli-config.json")
inspec("exec #{complete_profile} #{cli_args}")
# File specified with --reporter option - test to see file exists
_(File.exist?("#{outpath}/foo/bar/test.json")).must_equal true
_(File.stat("#{outpath}/foo/bar/test.json").size).must_be :>, 0
# STDOUT true set using config - test to see if this is obeyed
_(stdout).must_include "complete example profile (complete)"
_(stdout).must_include "1 successful control"
_(stdout).must_include "0 control failures"
_(stdout).must_include "0 controls skipped"
_(stderr).must_be_empty
assert_exit_code 0, out
end
end
describe "When specifying a config file and --reporter option to configure reporter with stdout true from both the options" do
let(:cli_args) { "--config " + File.join(config_dir_path, "json-config", "reporter-cli-config.json") + " --reporter json html2" }
let(:run_result) { run_inspec_process("exec " + File.join(profile_path, "basic_profile") + " " + cli_args) }
it "should raise error that only single reporter can have output to stdout" do
_(run_result.stderr).wont_equal ""
_(run_result.stderr).must_include "The option --reporter can only have a single report outputting to stdout."
end
end
describe "when specifying the execution target" do describe "when specifying the execution target" do
let(:local_plat) do let(:local_plat) do
json = run_inspec_process("detect --format json", {}).stdout json = run_inspec_process("detect --format json", {}).stdout