diff options
author | Matthias Beyer <mail@beyermatthias.de> | 2020-12-11 11:36:11 +0100 |
---|---|---|
committer | Matthias Beyer <mail@beyermatthias.de> | 2020-12-11 11:41:20 +0100 |
commit | 746e0cf6a73f81b1f746948422b746a07b4621c0 (patch) | |
tree | ed0139aa2f971bb3fe5ae57ce709376c65a72d60 | |
parent | b25131ed65496c9cf0f616f761517590aa16d120 (diff) |
Add "lint" subcommand
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r-- | src/cli.rs | 18 | ||||
-rw-r--r-- | src/commands/lint.rs | 87 | ||||
-rw-r--r-- | src/commands/mod.rs | 3 | ||||
-rw-r--r-- | src/main.rs | 5 |
4 files changed, 113 insertions, 0 deletions
@@ -596,6 +596,24 @@ pub fn cli<'a>() -> App<'a> { ) ) + .subcommand(App::new("lint") + .about("Release artifacts") + .arg(Arg::new("package_name") + .required(false) + .multiple(false) + .index(1) + .value_name("NAME") + .about("Package name to lint (if not present, every package will be linted") + ) + .arg(Arg::new("package_version") + .required(false) + .multiple(false) + .index(2) + .value_name("VERSION_CONSTRAINT") + .about("A version constraint to search for (optional), E.G. '=1.0.0'") + ) + ) + } fn script_arg_line_numbers<'a>() -> clap::Arg<'a> { diff --git a/src/commands/lint.rs b/src/commands/lint.rs new file mode 100644 index 0000000..8a3222b --- /dev/null +++ b/src/commands/lint.rs @@ -0,0 +1,87 @@ +use anyhow::anyhow; +use anyhow::Result; +use clap::ArgMatches; +use log::{error, info, trace}; +use tokio::stream::StreamExt; + +use crate::config::*; +use crate::package::Shebang; +use crate::repository::Repository; +use crate::package::PackageName; +use crate::package::PackageVersionConstraint; +use crate::package::ScriptBuilder; +use crate::util::progress::ProgressBars; + +pub async fn lint(matches: &ArgMatches, progressbars: ProgressBars, config: &Configuration, repo: Repository) -> Result<()> { + let linter = config.script_linter() + .as_ref() + .ok_or_else(|| anyhow!("No linting script configured"))?; + + let shebang = Shebang::from(config.shebang().clone()); + let pname = matches.value_of("package_name").map(String::from).map(PackageName::from); + let pvers = matches.value_of("package_version").map(String::from).map(PackageVersionConstraint::new).transpose()?; + + let bar = progressbars.bar(); + bar.set_message("Linting package scripts..."); + + let lint_results = repo.packages() + .filter(|p| pname.as_ref().map(|n| p.name() == n).unwrap_or(true)) + .filter(|p| pvers.as_ref().map(|v| v.matches(p.version())).unwrap_or(true)) + .map(|pkg| { + let shebang = shebang.clone(); + let bar = bar.clone(); + async move { + trace!("Linting script of {} {} with '{}'", pkg.name(), pkg.version(), linter.display()); + let cmd = tokio::process::Command::new(linter); + let script = ScriptBuilder::new(&shebang) + .build(pkg, config.available_phases(), *config.strict_script_interpolation())?; + + let (status, stdout, stderr) = script.lint(cmd).await?; + bar.inc(1); + Ok((pkg.name().clone(), pkg.version().clone(), status, stdout, stderr)) + } + }) + .collect::<futures::stream::FuturesUnordered<_>>() + .collect::<Result<Vec<_>>>() + .await? + .into_iter() + .map(|tpl| { + let pkg_name = tpl.0; + let pkg_vers = tpl.1; + let status = tpl.2; + let stdout = tpl.3; + let stderr = tpl.4; + + if status.success() { + info!("Linting {pkg_name} {pkg_vers} script (exit {status}):\nstdout:\n{stdout}\n\nstderr:\n\n{stderr}", + pkg_name = pkg_name, + pkg_vers = pkg_vers, + status = status, + stdout = stdout, + stderr = stderr + ); + true + } else { + error!("Linting {pkg_name} {pkg_vers} errored ({status}):\n\nstdout:\n{stdout}\n\nstderr:\n{stderr}\n\n", + pkg_name = pkg_name, + pkg_vers = pkg_vers, + status = status, + stdout = stdout, + stderr = stderr + ); + false + } + }) + .collect::<Vec<_>>(); + + let lint_ok = lint_results.iter().all(|b| *b); + + if !lint_ok { + bar.finish_with_message("Linting errored"); + return Err(anyhow!("Linting was not successful")) + } else { + bar.finish_with_message(&format!("Finished linting {} package scripts", lint_results.len())); + Ok(()) + } +} + diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c9c64c3..2fb124e 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -13,6 +13,9 @@ pub use find_pkg::find_pkg; mod dependencies_of; pub use dependencies_of::dependencies_of; +mod lint; +pub use lint::lint; + mod what_depends; pub use what_depends::what_depends; diff --git a/src/main.rs b/src/main.rs index e00014b..da02de0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -142,6 +142,11 @@ async fn main() -> Result<()> { crate::commands::release(db_connection_config, &config, matches).await? } + Some(("lint", matches)) => { + let repo = load_repo()?; + crate::commands::lint(matches, progressbars, &config, repo).await? + } + Some((other, _)) => return Err(anyhow!("Unknown subcommand: {}", other)), None => return Err(anyhow!("No subcommand")), } |