diff --git a/Cargo.lock b/Cargo.lock index d976077..da643d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,6 +155,16 @@ dependencies = [ "once_cell", ] +[[package]] +name = "clap-verbosity-flag" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eef05769009513df2eb1c3b4613e7fad873a14c600ff025b08f250f59fee7de" +dependencies = [ + "clap", + "log", +] + [[package]] name = "clap_builder" version = "4.2.2" @@ -235,6 +245,19 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + [[package]] name = "errno" version = "0.3.1" @@ -350,6 +373,9 @@ dependencies = [ "assert_cmd", "assert_fs", "clap", + "clap-verbosity-flag", + "env_logger", + "log", "predicates", "reqwest", "serde", @@ -461,6 +487,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.26" @@ -1096,6 +1128,15 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "termtree" version = "0.4.1" diff --git a/Cargo.toml b/Cargo.toml index ab51850..f3b3841 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,9 @@ edition = "2021" assert_cmd = "2.0.11" assert_fs = "1.0.13" clap = { version = "4.2.2", features = ["derive"] } +clap-verbosity-flag = "2.0.1" +env_logger = "0.10.0" +log = "0.4.17" predicates = "3.0.3" reqwest = { version = "0.11", features = ["json"] } serde = "1.0.160" diff --git a/src/main.rs b/src/main.rs index 6412af5..beb33a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,8 @@ use std::fs::{self, File}; use std::io::{BufRead, BufReader, BufWriter, Write}; use clap::Parser; +use clap_verbosity_flag::Verbosity; +use log::{info, warn}; use reqwest::header::{HeaderMap, HeaderValue, ACCEPT, AUTHORIZATION, USER_AGENT}; use serde_json::from_str; use serde_json::Value; @@ -18,6 +20,8 @@ struct Cli { #[clap(short, long)] /// The GitHub API token for authentication. token: Option, + #[clap(flatten)] + verbose: Verbosity, } #[derive(Debug)] @@ -25,6 +29,13 @@ pub struct CustomError(String); fn main() -> Result<(), CustomError> { let args = Cli::parse(); + + env_logger::Builder::new() + .filter_level(args.verbose.log_level_filter()) + .format_module_path(false) + .format_target(false) + .init(); + let client = reqwest::Client::new(); read_file_and_process_line_by_line(&args, &client, &fetch_sbom)?; Ok(()) @@ -90,7 +101,7 @@ async fn fetch_sbom( HeaderValue::from_str(&format!("Bearer {}", token)).expect("Expects bearer token"), ); } else { - println!("Token is not set! I can only access some public repositories. Consider using a token with --token option"); + info!("Token is not set! I can only access some public repositories. Consider using a token with --token option"); } headers.insert( USER_AGENT, @@ -108,15 +119,15 @@ async fn fetch_sbom( .await .map_err(|err| CustomError(format!("Failed to get response body: {}", err)))?; if response_text.contains("API rate limit exceeded") { - println!("Error: API rate limit exceeded"); + warn!("Error: API rate limit exceeded"); std::process::exit(1); } if response_text.contains("Not Found") { - println!("Error: Repository '{}' not found", repo_name); + warn!("Error: Repository '{}' not found", repo_name); return Ok(()); } if response_text.contains("Bad credentials") { - println!("Error: Invalid Token, check token permissions and expiry date!"); + warn!("Error: Invalid Token, check token permissions and expiry date!"); std::process::exit(1); } @@ -135,7 +146,7 @@ async fn fetch_sbom( .expect("Could not create directory"); let sbom_save_directory_path = format!("{}/{}.json", sbom_save_directory_path, repo_name); save_sbom_to_file(repo_name, &response_text, &sbom_save_directory_path)?; - println!("{:#?}", spdx.to_string()); + info!("{:#?}", spdx.to_string()); Ok(()) } diff --git a/tests/cli.rs b/tests/cli.rs index f66cd9d..b80ef88 100644 --- a/tests/cli.rs +++ b/tests/cli.rs @@ -14,13 +14,14 @@ fn retrieves_sbom_from_github() -> Result<(), Box> { cmd.arg("--repo-list-path") .arg(file.path()) .arg("--save-directory-path") - .arg("target/tmp/"); + .arg("target/tmp/") + .arg("-vvv"); // Assert - cmd.assert().success().stdout(predicate::str::contains( + cmd.assert().success().stderr(predicate::str::contains( "com.github.Brend-Smits/retrieve-github-sbom-action", )); - cmd.assert().success().stdout(predicate::str::contains( + cmd.assert().success().stderr(predicate::str::contains( "Token is not set! I can only access some public repositories. Consider using a token with --token option", )); Ok(()) @@ -35,7 +36,8 @@ fn file_doesnt_exist() -> Result<(), Box> { .arg("--save-directory-path") .arg("test/file/doesnt/exist") .arg("--token") - .arg("foo"); + .arg("foo") + .arg("-vvv"); cmd.assert().failure().stderr(predicate::str::contains( "Error reading `test/file/doesnt/exist`: No such file or directory (os error 2)", )); @@ -54,8 +56,9 @@ fn invalid_token_should_error() -> Result<(), Box> { .arg("--save-directory-path") .arg("test/path/doesnt-exist") .arg("--token") - .arg("foo"); - cmd.assert().failure().stdout(predicate::str::contains( + .arg("foo") + .arg("-vvv"); + cmd.assert().failure().stderr(predicate::str::contains( "Error: Invalid Token, check token permissions and expiry date!\n", )); @@ -73,8 +76,9 @@ fn non_existent_repo_should_log_and_continue() -> Result<(), Box