use crate::cli::arguments::{CheckCategory, ReadabilityTypeArgument};
use crate::cli::{paths_from_options, CommandLineOptions};
use acorn::analyzer::readability::ReadabilityType;
use acorn::analyzer::{summary, Analysis, Check, Validation};
use acorn::prelude::PathBuf;
use acorn::schema::research_activity::ResearchActivity;
use acorn::util::{print_values_as_table, Label};
use acorn::{fail, skip};
use clap_verbosity_flag::Verbosity;
use color_eyre::eyre::{Report, Result};
use dotenvy::dotenv;
use std::process::exit;
use tracing::debug;
const READABILITY_METRIC: &str = "READABILITY_METRIC";
fn count(issues: Vec<Check>) -> usize {
issues
.into_iter()
.filter(|Check { success, .. }| !success)
.map(|issue| issue.issue_count())
.sum()
}
#[allow(clippy::too_many_arguments)]
pub fn run(
path: &Option<PathBuf>,
branch: &Option<String>,
commit: &Option<String>,
ignore: &Option<String>,
skip: &[CheckCategory],
disable_website_checks: &bool,
exit_on_first_error: &bool,
merge_request: &bool,
skip_verify_checksum: &bool,
offline: &bool,
no_fail: &bool,
readability_metric: &ReadabilityTypeArgument,
verbose: &Verbosity,
) -> Result<(), Report> {
let level = verbose.log_level();
if *offline {
println!("=> {} ACORN is running in offline mode", Label::fmt_skip("OFFLINE"));
}
let options = CommandLineOptions::init()
.maybe_branch(branch.clone())
.maybe_commit(commit.clone())
.maybe_ignore(ignore.clone())
.exit_on_first_error(*exit_on_first_error)
.merge_request(*merge_request)
.build();
let CommandLineOptions { exit_on_first_error, .. } = options;
let paths = paths_from_options(path, &Some(options));
let schema_issues = if skip.contains(&CheckCategory::Schema) {
skip!("Schema validation");
vec![]
} else {
let is_offline = *offline || *disable_website_checks;
let results = ResearchActivity::check(paths.clone())
.into_iter()
.chain(ResearchActivity::url_analysis(paths.clone(), is_offline))
.collect::<Vec<_>>();
let issues = count(results.clone());
if issues > 0 && exit_on_first_error {
if level.is_some() {
fail!("ACORN found {} schema validation errors", issues);
results.iter().for_each(|issue| issue.clone().print());
}
exit(exitcode::DATAERR);
}
results
};
let prose_issues = if skip.contains(&CheckCategory::Prose) {
skip!("Prose analysis");
vec![]
} else {
let results = ResearchActivity::prose_analysis(paths.clone(), *offline, *skip_verify_checksum);
let issues = count(results.clone());
if issues > 0 && exit_on_first_error {
if level.is_some() {
fail!("ACORN found {} prose issues", issues);
results.iter().for_each(|issue| issue.clone().print());
}
exit(exitcode::DATAERR);
}
results
};
let readability_issues = if skip.contains(&CheckCategory::Readability) {
skip!("Readability analysis");
vec![]
} else {
let metric_value_from_cli = ReadabilityType::from_string(&readability_metric.to_string());
let metric = match dotenv() {
| Ok(_) => match dotenvy::var(READABILITY_METRIC) {
| Ok(value) if !value.is_empty() => {
debug!(value, "=> {} Readability metric from .env", Label::using());
ReadabilityType::from_string(&value)
}
| _ => metric_value_from_cli,
},
| _ => metric_value_from_cli,
};
let results = ResearchActivity::readability_analysis(paths, metric);
let issues = count(results.clone());
if issues > 0 && exit_on_first_error {
if level.is_some() {
fail!("ACORN found {} readability issues", issues);
results.iter().for_each(|issue| issue.clone().print());
}
exit(exitcode::DATAERR);
}
results
};
let conventions_issues = if skip.contains(&CheckCategory::Conventions) {
skip!("Conventions validation");
vec![]
} else {
vec![]
};
let all_issues = schema_issues
.clone()
.into_iter()
.chain(prose_issues.clone())
.chain(readability_issues.clone())
.chain(conventions_issues.clone())
.inspect(|issue| {
if level.is_some() {
issue.clone().print();
}
})
.filter(|Check { success, .. }| !success)
.collect::<Vec<Check>>();
if count(all_issues.clone()) > 0 && !*no_fail {
if level.is_some() {
let headers = vec!["Issue Type", "Issue Count"];
let rows = summary(all_issues);
println!("\n");
print_values_as_table(&Label::fmt_fail("Issues Overview"), headers, rows);
}
exit(exitcode::DATAERR);
}
Ok(())
}