diff --git a/.rustfmt.toml b/.rustfmt.toml index e96b69b4..4729b684 100644 --- a/.rustfmt.toml +++ b/.rustfmt.toml @@ -5,4 +5,3 @@ # make it easier for people to access and contribute to the Hipcheck # source code. hard_tabs = true - diff --git a/Cargo.lock b/Cargo.lock index 4e48250e..ca95898b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "aho-corasick" version = "1.1.3" @@ -86,6 +80,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "anyhow" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + [[package]] name = "ascii" version = "0.9.3" @@ -257,15 +257,6 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" -[[package]] -name = "crc32fast" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" -dependencies = [ - "cfg-if", -] - [[package]] name = "criterion" version = "0.5.1" @@ -465,16 +456,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" -[[package]] -name = "flate2" -version = "1.0.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "foreign-types" version = "0.3.2" @@ -596,128 +577,6 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" -[[package]] -name = "hc_analysis" -version = "0.1.0" -dependencies = [ - "content_inspector", - "curl", - "dirs", - "dotenv", - "glob", - "hc_common", - "hc_config", - "hc_data", - "hc_report", - "hc_serde", - "hc_shell", - "hc_version", - "maplit", - "petgraph", - "serde_derive", - "spdx-rs", - "tempfile", - "toml", - "unicode-normalization", - "unicode-segmentation", - "ureq", - "walkdir", - "xml-rs", -] - -[[package]] -name = "hc_common" -version = "0.1.0" -dependencies = [ - "chrono", - "hc_serde", - "lazy_static", - "log", - "once_cell", - "ordered-float", - "regex", - "salsa", - "schemars", - "semver", - "serde_json", - "toml", - "url", - "which", -] - -[[package]] -name = "hc_config" -version = "0.1.0" -dependencies = [ - "hc_common", - "smart-default", -] - -[[package]] -name = "hc_core" -version = "0.1.0" -dependencies = [ - "criterion", - "duct", - "hc_analysis", - "hc_common", - "hc_shell", - "hc_version", - "tempfile", -] - -[[package]] -name = "hc_data" -version = "0.1.0" -dependencies = [ - "dirs", - "graphql_client", - "hc_common", - "hc_config", - "hc_serde", - "hc_shell", - "hc_version", - "nom", - "petgraph", - "tempfile", - "ureq", -] - -[[package]] -name = "hc_report" -version = "0.1.0" -dependencies = [ - "hc_common", - "hc_version", - "paste", -] - -[[package]] -name = "hc_serde" -version = "0.1.0" -dependencies = [ - "serde", -] - -[[package]] -name = "hc_shell" -version = "0.1.0" -dependencies = [ - "duct", - "hc_common", - "hc_report", - "libc", - "termcolor", - "winapi", -] - -[[package]] -name = "hc_version" -version = "0.1.0" -dependencies = [ - "hc_common", -] - [[package]] name = "heck" version = "0.3.3" @@ -743,11 +602,48 @@ checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" name = "hipcheck" version = "3.1.0" dependencies = [ + "anyhow", + "chrono", "clap", + "content_inspector", + "criterion", + "curl", + "dirs", + "dotenv", + "duct", "env_logger", - "hc_analysis", - "hc_common", - "hc_core", + "glob", + "graphql_client", + "lazy_static", + "libc", + "log", + "maplit", + "native-tls", + "nom", + "once_cell", + "ordered-float", + "paste", + "petgraph", + "regex", + "salsa", + "schemars", + "semver", + "serde", + "serde_derive", + "serde_json", + "smart-default", + "spdx-rs", + "tempfile", + "termcolor", + "toml", + "unicode-normalization", + "unicode-segmentation", + "ureq", + "url", + "walkdir", + "which", + "winapi", + "xml-rs", ] [[package]] @@ -956,15 +852,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" -dependencies = [ - "adler", -] - [[package]] name = "native-tls" version = "0.2.11" @@ -1127,6 +1014,12 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pathbuf" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc5ef818343d9b62a8391bfbc8fbd449acf2e6ddd2f1a9aede0eae4c7d91c25c" + [[package]] name = "pathdiff" version = "0.2.1" @@ -1297,21 +1190,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -1331,37 +1209,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" -dependencies = [ - "log", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd36cc4259e3e4514335c4a138c6b43171a8d61d8f5c9348f9fc7529416f247" - -[[package]] -name = "rustls-webpki" -version = "0.102.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - [[package]] name = "rustversion" version = "1.0.15" @@ -1484,18 +1331,18 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.198" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9846a40c979031340571da2545a4e5b7c4163bdae79b301d5f86d03979451fcc" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.198" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88edab869b01783ba905e7d0153f9fc1a6505a96e4ad3018011eedb838566d9" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", @@ -1599,12 +1446,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - [[package]] name = "strum" version = "0.24.1" @@ -1624,12 +1465,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "subtle" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" - [[package]] name = "syn" version = "1.0.109" @@ -1819,12 +1654,6 @@ dependencies = [ "void", ] -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - [[package]] name = "ureq" version = "2.9.7" @@ -1832,17 +1661,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d11a831e3c0b56e438a28308e7c810799e3c118417f342d30ecec080105395cd" dependencies = [ "base64", - "flate2", "log", "native-tls", "once_cell", - "rustls", - "rustls-pki-types", - "rustls-webpki", "serde", "serde_json", "url", - "webpki-roots", ] [[package]] @@ -1963,15 +1787,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "which" version = "6.0.1" @@ -2188,18 +2003,13 @@ checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" name = "xtask" version = "0.1.0" dependencies = [ + "anyhow", "clap", "duct", "glob", - "hc_common", "open", + "pathbuf", "serde", "toml", "which", ] - -[[package]] -name = "zeroize" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/Cargo.toml b/Cargo.toml index 2caef84f..6eca65bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,9 @@ -# Necessary for 'cargo outdated' -cargo-features = ["resolver"] - [workspace] # Use the newer, better feature resolver. resolver = "2" # All the actual crates are in `libs/` or `hipcheck/` -members = [ - "hipcheck", - "libs/*", - "xtask", -] +members = ["hipcheck", "xtask"] # Make sure Hipcheck is run with `cargo run`. default-members = ["hipcheck"] - diff --git a/benches/basic.rs b/benches/basic.rs deleted file mode 100644 index f4c1a14c..00000000 --- a/benches/basic.rs +++ /dev/null @@ -1,56 +0,0 @@ -use criterion::{criterion_group, criterion_main, Criterion, PlottingBackend}; -use hc_common::CheckKind; -use hc_core::*; -use std::time::Duration; - -fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("hc check repo https://github.com/expressjs/express", |b| { - b.iter(|| { - let repo = "https://github.com/expressjs/express"; - - let shell = { - let verbosity = Verbosity::Quiet; - let color_choice = ColorChoice::Auto; - - Shell::new( - Output::stdout(color_choice), - Output::stderr(color_choice), - verbosity, - ) - }; - - let check = Check { - check_type: CheckType::RepoSource, - check_value: repo.into(), - parent_command_value: CheckKind::Repo.name().to_string(), - }; - - let config_path = None; - let data_path = None; - let home_dir = None; - let format = Format::Human; - let raw_version = "3.0.0"; - - run_with_shell( - shell, - check, - config_path, - data_path, - home_dir, - format, - raw_version, - ) - }) - }); -} - -criterion_group! { - name = benches; - config = Criterion::default() - .sample_size(10) - .measurement_time(Duration::from_secs(150)) - .plotting_backend(PlottingBackend::Plotters); - targets = criterion_benchmark -} - -criterion_main!(benches); diff --git a/hipcheck/Cargo.toml b/hipcheck/Cargo.toml index aaff8826..5a83e8fe 100644 --- a/hipcheck/Cargo.toml +++ b/hipcheck/Cargo.toml @@ -12,11 +12,65 @@ path = "src/main.rs" [dependencies] -# Internal dependencies. -hc_analysis = { path = "../libs/hc_analysis" } -hc_common = { path = "../libs/hc_common" } -hc_core = { path = "../libs/hc_core" } - -# External dependencies. -clap = { version = "4.5.4", default-features = false, features = ["string", "std"]} +content_inspector = "0.2.4" +dotenv = "0.15.0" +chrono = { version = "0.4.19", features = ["serde"] } +clap = { version = "4.5.4", default-features = false, features = [ + "string", + "std", +] } +curl = "0.4.38" +dirs = "5.0.1" +duct = "0.13.5" env_logger = { version = "0.11.3" } +glob = "0.3.0" +graphql_client = "0.14.0" +lazy_static = "1.4.0" +log = "0.4.16" +libc = "0.2.154" +maplit = "1.0.2" +nom = "7.1.3" +once_cell = "1.10.0" +ordered-float = { version = "4.2.0", features = ["serde"] } +paste = "1.0.7" +petgraph = { version = "0.6.0", features = ["serde-1"] } +regex = "1.5.5" +salsa = "0.16.1" +schemars = { version = "0.8.17", default-features = false, features = [ + "derive", + "preserve_order", + "chrono", +] } +semver = "1.0.9" +serde = { version = "1.0.200", features = ["derive", "rc"] } +serde_derive = "1.0.137" +serde_json = "1.0.80" +smart-default = "0.7.1" +spdx-rs = "0.5.0" +termcolor = "1.1.3" +toml = "0.8.12" +unicode-normalization = "0.1.19" +unicode-segmentation = "1.9.0" +ureq = { version = "2.9.7", default-features = false, features = [ + "json", + "native-tls", +] } +url = "2.2.2" +walkdir = "2.5.0" +which = { version = "6.0.1", default-features = false } +xml-rs = "0.8.20" +native-tls = "0.2.11" + +[target.'cfg(windows)'.dependencies.winapi] +version = "0.3.9" +features = ["handleapi", "processenv", "winbase", "wincon", "winnt"] + +[build-dependencies] +anyhow = "1.0.83" +which = { version = "6.0.1", default-features = false } + +[dev-dependencies] +dirs = "5.0.1" +tempfile = "3.10.1" +duct = "0.13.7" +criterion = "0.5.1" diff --git a/libs/hc_version/src/build.rs b/hipcheck/build.rs similarity index 77% rename from libs/hc_version/src/build.rs rename to hipcheck/build.rs index 42df4c0b..44391b7d 100644 --- a/libs/hc_version/src/build.rs +++ b/hipcheck/build.rs @@ -1,12 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::{command_util::log_git_args, context::Context, error::Result, hc_error, which}; +use anyhow::anyhow; +use anyhow::Context as _; +use anyhow::Result; use std::convert::AsRef; use std::ffi::OsStr; use std::iter::IntoIterator; use std::ops::Not as _; use std::path::Path; use std::process::Command; +use which::which; fn main() { let repo_dir = env!("CARGO_MANIFEST_DIR", "can't find Cargo manifest directory"); @@ -38,11 +41,8 @@ impl GitCommand { S: AsRef, { // Init the command. - let git_path = which::which("git").context("can't find git command")?; - let repo = repo_path.display().to_string(); - let path = git_path.display().to_string(); - log_git_args(&repo, args, &path); - let mut command = Command::new(&git_path); + let git_path = which("git").context("can't find git command")?; + let mut command = Command::new(git_path); command.args(args); // Set the path if necessary @@ -67,12 +67,12 @@ impl GitCommand { } match String::from_utf8(output.stderr) { - Ok(msg) if msg.is_empty().not() => Err(hc_error!( + Ok(msg) if msg.is_empty().not() => Err(anyhow!( "git failed with message '{}' [status: {}]", msg.trim(), output.status )), - _ => Err(hc_error!("git failed [status: {}]", output.status)), + _ => Err(anyhow!("git failed [status: {}]", output.status)), } } } diff --git a/hipcheck/src/analysis.rs b/hipcheck/src/analysis.rs new file mode 100644 index 00000000..62aabf47 --- /dev/null +++ b/hipcheck/src/analysis.rs @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: Apache-2.0 + +#[allow(clippy::module_inception)] +pub mod analysis; +pub mod metric; +pub mod report_builder; +pub mod score; +pub mod session; + +pub use analysis::AnalysisProvider; +pub use analysis::AnalysisProviderStorage; +pub use metric::MetricProvider; diff --git a/libs/hc_analysis/src/analysis.rs b/hipcheck/src/analysis/analysis.rs similarity index 97% rename from libs/hc_analysis/src/analysis.rs rename to hipcheck/src/analysis/analysis.rs index 72bb78f9..bd90e98a 100644 --- a/libs/hc_analysis/src/analysis.rs +++ b/hipcheck/src/analysis/analysis.rs @@ -1,17 +1,24 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::metric::{affiliation::AffiliatedType, MetricProvider}; -use hc_common::{ - chrono::Duration, - error::{Error, Result}, - salsa, F64, -}; -use hc_config::{AttacksConfigQuery, CommitConfigQuery, FuzzConfigQuery, PracticesConfigQuery}; -use hc_data::git::GitProvider; -use hc_report::{Concern, PrConcern}; -use std::collections::{HashMap, HashSet}; +use crate::analysis::metric::affiliation::AffiliatedType; +use crate::analysis::metric::MetricProvider; +use crate::config::AttacksConfigQuery; +use crate::config::CommitConfigQuery; +use crate::config::FuzzConfigQuery; +use crate::config::PracticesConfigQuery; +use crate::data::git::GitProvider; +use crate::error::Error; +use crate::error::Result; +use crate::report::Concern; +use crate::report::PrConcern; +use crate::F64; +use chrono::Duration; +use std::collections::HashMap; +use std::collections::HashSet; use std::default::Default; -use std::fmt::{self, Display, Formatter}; +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; use std::ops::Not; use std::rc::Rc; diff --git a/libs/hc_analysis/src/metric/activity.rs b/hipcheck/src/analysis/metric/activity.rs similarity index 85% rename from libs/hc_analysis/src/metric/activity.rs rename to hipcheck/src/analysis/metric/activity.rs index 25cecbc8..0669a082 100644 --- a/libs/hc_analysis/src/metric/activity.rs +++ b/hipcheck/src/analysis/metric/activity.rs @@ -1,14 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - chrono::{prelude::*, Duration}, - error::Result, - log, - serde::{ser::SerializeStruct, Serialize, Serializer}, -}; -use std::{rc::Rc, result::Result as StdResult}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::error::Result; +use chrono::prelude::*; +use chrono::Duration; +use serde::ser::SerializeStruct; +use serde::Serialize; +use serde::Serializer; +use std::rc::Rc; +use std::result::Result as StdResult; #[derive(Debug, Eq, PartialEq)] pub struct ActivityOutput { diff --git a/libs/hc_analysis/src/metric/affiliation.rs b/hipcheck/src/analysis/metric/affiliation.rs similarity index 95% rename from libs/hc_analysis/src/metric/affiliation.rs rename to hipcheck/src/analysis/metric/affiliation.rs index 533d89f2..a77e1e73 100644 --- a/libs/hc_analysis/src/metric/affiliation.rs +++ b/hipcheck/src/analysis/metric/affiliation.rs @@ -1,20 +1,22 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::{ - context::Context as _, - error::{Error, Result}, - filesystem as file, hc_error, log, - serde::{ - self, - de::{Error as SerdeError, Visitor}, - Deserialize, Deserializer, Serialize, - }, -}; -use hc_data::git::{Commit, CommitContributorView}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::git::Commit; +use crate::data::git::CommitContributorView; +use crate::error::Error; +use crate::error::Result; +use crate::filesystem as file; +use crate::hc_error; +use serde::de::Error as SerdeError; +use serde::de::Visitor; +use serde::Deserialize; +use serde::Deserializer; +use serde::Serialize; use std::cell::RefCell; use std::collections::HashMap; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryFrom; +use std::convert::TryInto; use std::fmt; use std::ops::Not as _; use std::path::Path; @@ -22,20 +24,17 @@ use std::rc::Rc; use std::result::Result as StdResult; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct AffiliationOutput { pub affiliations: Vec, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct Affiliation { pub commit: Rc, pub affiliated_type: AffiliatedType, } #[derive(Debug, Eq, PartialEq, Serialize, Clone, Copy)] -#[serde(crate = "self::serde")] pub enum AffiliatedType { Author, Committer, @@ -205,7 +204,6 @@ impl<'haystack> Matcher<'haystack> { /// An overall organization metric specification, with a strategy for how the /// metric will be performed, and a list of organizations. #[derive(Deserialize)] -#[serde(crate = "self::serde")] struct OrgSpec { strategy: Strategy, orgs: Vec, @@ -260,7 +258,6 @@ impl OrgSpec { /// An organization metric strategy. It either implicitly includes _all_ /// organizations in the Orgs struct, or has a more detailed custom specification. #[derive(Deserialize)] -#[serde(crate = "self::serde")] enum Strategy { All(Mode), Specified(Spec), @@ -270,7 +267,6 @@ enum Strategy { /// commits which are independent of the listed orgs, or all commits which are /// affiliated with the listed orgs. #[derive(Deserialize, Clone, Copy)] -#[serde(crate = "self::serde")] enum Mode { Independent, Affiliated, @@ -284,7 +280,6 @@ enum Mode { /// specifiers may be combined (for example, analyzing all commits from some /// country, plus commits from an organization not from that country). #[derive(Deserialize)] -#[serde(crate = "self::serde")] struct Spec { mode: Mode, list: Vec, @@ -336,7 +331,6 @@ fn get_by_name<'spec>(name: &str, list: &'spec [Org]) -> Result> /// A single organization, with a name, a list of hosts (which form the basis /// for the hosts used in the analyzer), and an affiliated country. #[derive(Clone, Deserialize, Debug)] -#[serde(crate = "self::serde")] struct Org { name: String, hosts: Vec, @@ -412,7 +406,6 @@ impl<'de> Visitor<'de> for ReferenceVisitor { } #[derive(Deserialize, Debug)] -#[serde(crate = "self::serde")] struct RawOrgSpec { strategy: Option, strategy_spec: Option, @@ -420,7 +413,6 @@ struct RawOrgSpec { } #[derive(Deserialize, Debug)] -#[serde(crate = "self::serde")] struct RawSpec { mode: String, list: Vec, diff --git a/libs/hc_analysis/src/metric/binary.rs b/hipcheck/src/analysis/metric/binary.rs similarity index 76% rename from libs/hc_analysis/src/metric/binary.rs rename to hipcheck/src/analysis/metric/binary.rs index 492e21f3..86606a98 100644 --- a/libs/hc_analysis/src/metric/binary.rs +++ b/hipcheck/src/analysis/metric/binary.rs @@ -1,17 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::metric::binary_detector::detect_binary_files; -use crate::MetricProvider; -use hc_common::{ - error::Result, - log, - serde::{self, Serialize}, - TryFilter, -}; +use crate::analysis::metric::binary_detector::detect_binary_files; +use crate::analysis::MetricProvider; +use crate::error::Result; +use crate::TryFilter; +use serde::Serialize; use std::rc::Rc; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct BinaryOutput { pub binary_files: Vec>, } @@ -28,7 +24,7 @@ pub fn binary_metric(db: &dyn MetricProvider) -> Result> { let binary_files = detect_binary_files(&pathbuf_rc)? .into_iter() .try_filter(|f| db.is_likely_binary_file(Rc::clone(f))) - .collect::>()?; + .collect::>()?; log::info!("completed binary metric"); diff --git a/libs/hc_analysis/src/metric/binary_detector/mod.rs b/hipcheck/src/analysis/metric/binary_detector/mod.rs similarity index 89% rename from libs/hc_analysis/src/metric/binary_detector/mod.rs rename to hipcheck/src/analysis/metric/binary_detector/mod.rs index 57a62d93..b6e57fa4 100644 --- a/libs/hc_analysis/src/metric/binary_detector/mod.rs +++ b/hipcheck/src/analysis/metric/binary_detector/mod.rs @@ -4,22 +4,25 @@ mod query; pub use query::*; -use content_inspector::{inspect, ContentType}; -use hc_common::{ - context::Context, - error::Result, - filesystem::read_toml, - hc_error, - serde::{self, de::Visitor, Deserialize, Deserializer}, -}; -use std::fmt::{self, Formatter}; +use crate::context::Context; +use crate::error::Result; +use crate::filesystem::read_toml; +use crate::hc_error; +use content_inspector::inspect; +use content_inspector::ContentType; +use serde::de::Visitor; +use serde::Deserialize; +use serde::Deserializer; +use std::fmt; +use std::fmt::Formatter; use std::fs::File; use std::io::prelude::Read; use std::io::BufReader; use std::path::Path; use std::rc::Rc; use std::result::Result as StdResult; -use walkdir::{DirEntry, WalkDir}; +use walkdir::DirEntry; +use walkdir::WalkDir; #[derive(Debug, PartialEq, Eq)] pub struct BinaryFileDetector { @@ -28,10 +31,8 @@ pub struct BinaryFileDetector { impl BinaryFileDetector { /// Constructs a new `BinaryFileDetector` from the `Binary.toml` file. - pub fn load>( - binary_config_file: P, - ) -> hc_common::error::Result { - fn inner(binary_config_file: &Path) -> hc_common::error::Result { + pub fn load>(binary_config_file: P) -> crate::error::Result { + fn inner(binary_config_file: &Path) -> crate::error::Result { let extensions_file: ExtensionsFile = read_toml(binary_config_file) .context("failed to read binary type defintions from Binary config file")?; @@ -64,13 +65,11 @@ impl BinaryFileDetector { } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct ExtensionsFile { formats: Vec, } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct BinaryExtensions { #[serde(default = "missing_bin_type")] r#type: BinaryType, diff --git a/libs/hc_analysis/src/metric/binary_detector/query.rs b/hipcheck/src/analysis/metric/binary_detector/query.rs similarity index 86% rename from libs/hc_analysis/src/metric/binary_detector/query.rs rename to hipcheck/src/analysis/metric/binary_detector/query.rs index d5502857..e57bb81a 100644 --- a/libs/hc_analysis/src/metric/binary_detector/query.rs +++ b/hipcheck/src/analysis/metric/binary_detector/query.rs @@ -2,10 +2,10 @@ //! A query group for binary file detection queries. -use crate::metric::binary_detector::BinaryFileDetector; -use hc_common::context::Context as _; -use hc_common::{error::Result, salsa}; -use hc_config::PracticesConfigQuery; +use crate::analysis::metric::binary_detector::BinaryFileDetector; +use crate::config::PracticesConfigQuery; +use crate::context::Context as _; +use crate::error::Result; use std::rc::Rc; /// Queries related to binary file detection diff --git a/libs/hc_analysis/src/metric/churn.rs b/hipcheck/src/analysis/metric/churn.rs similarity index 85% rename from libs/hc_analysis/src/metric/churn.rs rename to hipcheck/src/analysis/metric/churn.rs index 10db789b..f5767d1d 100644 --- a/libs/hc_analysis/src/metric/churn.rs +++ b/hipcheck/src/analysis/metric/churn.rs @@ -1,26 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::metric::math::{mean, std_dev}; -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - hc_error, log, - serde::{self, Serialize}, - TryAny, TryFilter, F64, -}; -use hc_data::git::Commit; +use crate::analysis::metric::math::mean; +use crate::analysis::metric::math::std_dev; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::git::Commit; +use crate::error::Result; +use crate::hc_error; +use crate::TryAny; +use crate::TryFilter; +use crate::F64; +use serde::Serialize; use std::collections::HashMap; use std::rc::Rc; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct ChurnOutput { pub commit_churn_freqs: Vec, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct CommitChurnFreq { pub commit: Rc, pub churn: F64, @@ -39,7 +38,7 @@ pub fn churn_metric(db: &dyn MetricProvider) -> Result> { .iter() .try_any(|fd| db.is_likely_source_file(Rc::clone(&fd.file_name))) }) - .collect::>>()?; + .collect::>>()?; let mut commit_churns = Vec::new(); let mut total_files_changed: i64 = 0; @@ -51,7 +50,7 @@ pub fn churn_metric(db: &dyn MetricProvider) -> Result> { .file_diffs .iter() .try_filter(|file_diff| db.is_likely_source_file(Rc::clone(&file_diff.file_name))) - .collect::>>()?; + .collect::>>()?; // Update files changed. let files_changed = source_files.len() as i64; @@ -131,10 +130,10 @@ pub fn churn_metric(db: &dyn MetricProvider) -> Result> { .map(|c| c.churn.into_inner()) .collect(); - let mean = mean(&churns) - .ok_or_else(|| hc_common::error::Error::msg("failed to get mean churn value"))?; + let mean = + mean(&churns).ok_or_else(|| crate::error::Error::msg("failed to get mean churn value"))?; let std_dev = std_dev(mean, &churns) - .ok_or_else(|| hc_common::error::Error::msg("failed to get churn standard deviation"))?; + .ok_or_else(|| crate::error::Error::msg("failed to get churn standard deviation"))?; log::trace!("mean of churn scores [mean='{}']", mean); log::trace!("standard deviation of churn scores [stddev='{}']", std_dev); diff --git a/libs/hc_analysis/src/metric/commit_trust.rs b/hipcheck/src/analysis/metric/commit_trust.rs similarity index 92% rename from libs/hc_analysis/src/metric/commit_trust.rs rename to hipcheck/src/analysis/metric/commit_trust.rs index 33a8dda8..b2a0680a 100644 --- a/libs/hc_analysis/src/metric/commit_trust.rs +++ b/hipcheck/src/analysis/metric/commit_trust.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{error::Result, log}; -use std::{collections::HashMap, rc::Rc}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::error::Result; +use std::collections::HashMap; +use std::rc::Rc; pub const TRUST_PHASE: &str = "commit trust"; diff --git a/libs/hc_analysis/src/metric/contributor_trust.rs b/hipcheck/src/analysis/metric/contributor_trust.rs similarity index 97% rename from libs/hc_analysis/src/metric/contributor_trust.rs rename to hipcheck/src/analysis/metric/contributor_trust.rs index 71feec11..66d86025 100644 --- a/libs/hc_analysis/src/metric/contributor_trust.rs +++ b/hipcheck/src/analysis/metric/contributor_trust.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{error::Result, log}; -use std::{collections::HashMap, rc::Rc}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::error::Result; +use std::collections::HashMap; +use std::rc::Rc; pub const TRUST_PHASE: &str = "contributor trust"; pub const PR_TRUST_PHASE: &str = "pull request contributor trust"; diff --git a/libs/hc_analysis/src/metric/entropy.rs b/hipcheck/src/analysis/metric/entropy.rs similarity index 92% rename from libs/hc_analysis/src/metric/entropy.rs rename to hipcheck/src/analysis/metric/entropy.rs index e02b6854..9fcbe945 100644 --- a/libs/hc_analysis/src/metric/entropy.rs +++ b/hipcheck/src/analysis/metric/entropy.rs @@ -1,15 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::metric::math::{mean, std_dev}; -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - hc_error, log, - serde::{self, Serialize}, - TryAny, TryFilter, F64, -}; -use hc_data::git::{Commit, CommitDiff, Diff}; +use crate::analysis::metric::math::mean; +use crate::analysis::metric::math::std_dev; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::git::Commit; +use crate::data::git::CommitDiff; +use crate::data::git::Diff; +use crate::error::Result; +use crate::hc_error; +use crate::TryAny; +use crate::TryFilter; +use crate::F64; +use serde::Serialize; use std::collections::HashMap; use std::iter::Iterator; use std::ops::Not as _; @@ -77,7 +80,6 @@ pub fn entropy_metric(db: &dyn MetricProvider) -> Result> { /// The final output for entropy metric, containing an entropy score for /// every commit. #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct EntropyOutput { /// The set of commit entropies. pub commit_entropies: Vec, @@ -92,7 +94,6 @@ impl EntropyOutput { /// The entropy of a single commit. #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct CommitEntropy { /// The commit pub commit: Rc, @@ -139,7 +140,7 @@ struct GraphemeFreqView<'gra> { fn is_likely_source_file( commit_diff: &CommitDiff, db: &dyn MetricProvider, -) -> hc_common::error::Result { +) -> crate::error::Result { commit_diff .diff .file_diffs @@ -212,10 +213,10 @@ fn z_scores(mut commit_entropies: Vec) -> Result, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct Match { pub commit: Rc, pub identities_match: bool, diff --git a/libs/hc_analysis/src/metric/linguist/mod.rs b/hipcheck/src/analysis/metric/linguist/mod.rs similarity index 92% rename from libs/hc_analysis/src/metric/linguist/mod.rs rename to hipcheck/src/analysis/metric/linguist/mod.rs index d56a1f9e..c080f87e 100644 --- a/libs/hc_analysis/src/metric/linguist/mod.rs +++ b/hipcheck/src/analysis/metric/linguist/mod.rs @@ -4,15 +4,15 @@ mod query; pub use query::*; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - filesystem::read_toml, - log, - serde::{self, de::Visitor, Deserialize, Deserializer}, -}; +use crate::context::Context as _; +use crate::error::Result; +use crate::filesystem::read_toml; +use serde::de::Visitor; +use serde::Deserialize; +use serde::Deserializer; use std::convert::AsRef; -use std::fmt::{self, Formatter}; +use std::fmt; +use std::fmt::Formatter; use std::path::Path; use std::result::Result as StdResult; @@ -65,13 +65,11 @@ impl SourceFileDetector { } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct LanguageFile { languages: Vec, } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct LanguageExtensions { #[serde(default = "missing_lang_type")] r#type: LanguageType, diff --git a/libs/hc_analysis/src/metric/linguist/query.rs b/hipcheck/src/analysis/metric/linguist/query.rs similarity index 86% rename from libs/hc_analysis/src/metric/linguist/query.rs rename to hipcheck/src/analysis/metric/linguist/query.rs index 94eee4e2..d71a4d87 100644 --- a/libs/hc_analysis/src/metric/linguist/query.rs +++ b/hipcheck/src/analysis/metric/linguist/query.rs @@ -2,9 +2,10 @@ //! A query group for source file language detection queries. -use crate::metric::linguist::SourceFileDetector; -use hc_common::{context::Context, error::Result, salsa}; -use hc_config::LanguagesConfigQuery; +use crate::analysis::metric::linguist::SourceFileDetector; +use crate::config::LanguagesConfigQuery; +use crate::context::Context; +use crate::error::Result; use std::rc::Rc; /// Queries related to source file language detection diff --git a/libs/hc_analysis/src/metric/math.rs b/hipcheck/src/analysis/metric/math.rs similarity index 100% rename from libs/hc_analysis/src/metric/math.rs rename to hipcheck/src/analysis/metric/math.rs diff --git a/libs/hc_analysis/src/metric/mod.rs b/hipcheck/src/analysis/metric/mod.rs similarity index 92% rename from libs/hc_analysis/src/metric/mod.rs rename to hipcheck/src/analysis/metric/mod.rs index bc86df28..d8a1d0a7 100644 --- a/libs/hc_analysis/src/metric/mod.rs +++ b/hipcheck/src/analysis/metric/mod.rs @@ -19,6 +19,14 @@ pub mod typo; use std::rc::Rc; +use crate::config::AttacksConfigQuery; +use crate::config::CommitConfigQuery; +use crate::data::git::GitProvider; +use crate::data::DependenciesProvider; +use crate::data::FuzzProvider; +use crate::data::ModuleProvider; +use crate::data::PullRequestReviewProvider; +use crate::error::Result; use activity::ActivityOutput; use affiliation::AffiliationOutput; use binary::BinaryOutput; @@ -28,11 +36,6 @@ use commit_trust::CommitTrustOutput; use contributor_trust::ContributorTrustOutput; use entropy::EntropyOutput; use fuzz::FuzzOutput; -use hc_common::{error::Result, salsa}; -use hc_config::{AttacksConfigQuery, CommitConfigQuery}; -use hc_data::{ - git::GitProvider, DependenciesProvider, FuzzProvider, ModuleProvider, PullRequestReviewProvider, -}; use identity::IdentityOutput; use linguist::Linguist; use module::ModuleOutput; diff --git a/libs/hc_analysis/src/metric/module.rs b/hipcheck/src/analysis/metric/module.rs similarity index 75% rename from libs/hc_analysis/src/metric/module.rs rename to hipcheck/src/analysis/metric/module.rs index 97cb5f8a..a53b0a8f 100644 --- a/libs/hc_analysis/src/metric/module.rs +++ b/hipcheck/src/analysis/metric/module.rs @@ -1,17 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - log, - serde::{self, Serialize}, -}; -use hc_data::ModuleGraph; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::ModuleGraph; +use crate::error::Result; +use serde::Serialize; use std::rc::Rc; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct ModuleOutput { pub module_graph: Rc, pub is_modular: bool, diff --git a/libs/hc_analysis/src/metric/module_contributors.rs b/hipcheck/src/analysis/metric/module_contributors.rs similarity index 91% rename from libs/hc_analysis/src/metric/module_contributors.rs rename to hipcheck/src/analysis/metric/module_contributors.rs index 1965c7bf..52a3d894 100644 --- a/libs/hc_analysis/src/metric/module_contributors.rs +++ b/hipcheck/src/analysis/metric/module_contributors.rs @@ -1,23 +1,20 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - log, - serde::{self, Serialize}, -}; -use hc_data::{git::Contributor, Module}; -use std::{collections::HashMap, rc::Rc}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::git::Contributor; +use crate::data::Module; +use crate::error::Result; +use serde::Serialize; +use std::collections::HashMap; +use std::rc::Rc; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct ModuleContributorsOutput { pub contributors_map: Rc, Vec>>, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct ContributedModule { pub module: Rc, pub new_contributor: bool, diff --git a/libs/hc_analysis/src/metric/review.rs b/hipcheck/src/analysis/metric/review.rs similarity index 80% rename from libs/hc_analysis/src/metric/review.rs rename to hipcheck/src/analysis/metric/review.rs index 3b164100..aae5d72e 100644 --- a/libs/hc_analysis/src/metric/review.rs +++ b/hipcheck/src/analysis/metric/review.rs @@ -1,23 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - log, - serde::{self, Serialize}, -}; -use hc_data::PullRequest; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::PullRequest; +use crate::error::Result; +use serde::Serialize; use std::rc::Rc; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct ReviewOutput { pub pull_reviews: Vec, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct PullReview { pub pull_request: Rc, pub has_review: bool, diff --git a/libs/hc_analysis/src/metric/typo.rs b/hipcheck/src/analysis/metric/typo.rs similarity index 97% rename from libs/hc_analysis/src/metric/typo.rs rename to hipcheck/src/analysis/metric/typo.rs index 31c93513..893a89a1 100644 --- a/libs/hc_analysis/src/metric/typo.rs +++ b/hipcheck/src/analysis/metric/typo.rs @@ -1,30 +1,29 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::MetricProvider; -use hc_common::context::Context as _; -use hc_common::{ - error::Result, - filesystem as file, log, - serde::{self, Deserialize, Serialize}, -}; -use hc_data::{Dependencies, Lang}; +use crate::analysis::MetricProvider; +use crate::context::Context as _; +use crate::data::Dependencies; +use crate::data::Lang; +use crate::error::Result; +use crate::filesystem as file; use maplit::hashmap; +use serde::Deserialize; +use serde::Serialize; use std::cmp::Ordering; use std::collections::HashMap; use std::convert::AsRef; -use std::fmt::{self, Display}; +use std::fmt; +use std::fmt::Display; use std::path::Path; use std::rc::Rc; use std::str; #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct TypoOutput { pub typos: Vec, } #[derive(Debug, Eq, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct TypoDep { pub dependency: Rc, pub typo: Typo, @@ -39,7 +38,7 @@ pub fn typo_metric(db: &dyn MetricProvider) -> Result> { let typo_output = match dependencies.language { Lang::JavaScript => typos_for_javascript(&typo_file, dependencies), - Lang::Unknown => Err(hc_common::error::Error::msg( + Lang::Unknown => Err(crate::error::Error::msg( "failed to identify a known language", )), }?; @@ -72,13 +71,11 @@ fn typos_for_javascript( } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct TypoFile { languages: Languages, } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] struct Languages { javascript: Vec, } @@ -400,7 +397,6 @@ fn get_homoglyph_typos(results: &mut Vec, name: &str, homoglyphs: &[Homogl } #[derive(Debug, Clone, PartialEq, Eq, Serialize)] -#[serde(crate = "self::serde")] pub struct Typo { kind: TypoKind, typo: String, @@ -530,7 +526,6 @@ impl PartialEq for &Typo { } #[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)] -#[serde(crate = "self::serde")] enum TypoKind { Addition, Bitsquatting, @@ -735,7 +730,7 @@ impl KeyboardLayout { mod test { use super::NameFuzzer; use super::Typo; - use hc_common::lazy_static::lazy_static; + use lazy_static::lazy_static; macro_rules! test_typos { ( from: $name:ident, to: $to:literal, expected: [ $( $expected:ident ),* ] ) => { diff --git a/libs/hc_analysis/src/report_builder.rs b/hipcheck/src/analysis/report_builder.rs similarity index 94% rename from libs/hc_analysis/src/report_builder.rs rename to hipcheck/src/analysis/report_builder.rs index dace63bb..c2f13801 100644 --- a/libs/hc_analysis/src/report_builder.rs +++ b/hipcheck/src/analysis/report_builder.rs @@ -1,13 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::{analysis::AnalysisReport, score::ScoringResults, session::Session}; -use hc_common::{ - error::{Error, Result}, - hc_error, log, -}; -use hc_config::RiskConfigQuery; -use hc_data::source::SourceQuery; -pub use hc_report::*; +use crate::analysis::analysis::AnalysisReport; +use crate::analysis::score::ScoringResults; +use crate::analysis::session::Session; +use crate::config::RiskConfigQuery; +use crate::data::source::SourceQuery; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +pub use crate::report::*; +use crate::version::VersionQuery; use std::default::Default; use std::result::Result as StdResult; @@ -40,7 +42,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::ACTIVITY_PHASE + crate::analysis::score::ACTIVITY_PHASE )) } } @@ -72,7 +74,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::AFFILIATION_PHASE + crate::analysis::score::AFFILIATION_PHASE )) } } @@ -104,7 +106,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::BINARY_PHASE + crate::analysis::score::BINARY_PHASE )) } } @@ -135,7 +137,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::CHURN_PHASE + crate::analysis::score::CHURN_PHASE )) } } @@ -166,7 +168,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::ENTROPY_PHASE + crate::analysis::score::ENTROPY_PHASE )) } } @@ -197,7 +199,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::IDENTITY_PHASE + crate::analysis::score::IDENTITY_PHASE )) } } @@ -225,7 +227,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::FUZZ_PHASE + crate::analysis::score::FUZZ_PHASE )) } } @@ -256,7 +258,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::REVIEW_PHASE + crate::analysis::score::REVIEW_PHASE )) } } @@ -287,7 +289,7 @@ pub fn build_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::TYPO_PHASE + crate::analysis::score::TYPO_PHASE )) } } @@ -482,7 +484,7 @@ pub fn build_pr_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::PR_AFFILIATION_PHASE + crate::analysis::score::PR_AFFILIATION_PHASE )) } } @@ -516,7 +518,7 @@ pub fn build_pr_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::PR_CONTRIBUTOR_TRUST_PHASE + crate::analysis::score::PR_CONTRIBUTOR_TRUST_PHASE )) } } @@ -550,7 +552,7 @@ pub fn build_pr_report(session: &Session, scoring: &ScoringResults) -> Result { return Err(hc_error!( "phase name does not match {} analysis", - crate::score::PR_MODULE_CONTRIBUTORS_PHASE + crate::analysis::score::PR_MODULE_CONTRIBUTORS_PHASE )) } } diff --git a/libs/hc_analysis/src/score.rs b/hipcheck/src/analysis/score.rs similarity index 99% rename from libs/hc_analysis/src/score.rs rename to hipcheck/src/analysis/score.rs index 6eabbfe8..094cbc59 100644 --- a/libs/hc_analysis/src/score.rs +++ b/hipcheck/src/analysis/score.rs @@ -1,16 +1,18 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::{ - analysis::{AnalysisOutcome, AnalysisReport}, - AnalysisProvider, -}; -use hc_common::{error::Result, hc_error, salsa}; -use hc_shell::Phase; +use crate::analysis::analysis::AnalysisOutcome; +use crate::analysis::analysis::AnalysisReport; +use crate::analysis::AnalysisProvider; +use crate::error::Result; +use crate::hc_error; +use crate::shell::Phase; use std::default::Default; use std::rc::Rc; -use petgraph::graph::{node_index as n, NodeIndex}; -use petgraph::{prelude::Graph, EdgeDirection::Outgoing}; +use petgraph::graph::node_index as n; +use petgraph::graph::NodeIndex; +use petgraph::prelude::Graph; +use petgraph::EdgeDirection::Outgoing; pub const RISK_PHASE: &str = "risk"; diff --git a/libs/hc_analysis/src/session/mod.rs b/hipcheck/src/analysis/session/mod.rs similarity index 92% rename from libs/hc_analysis/src/session/mod.rs rename to hipcheck/src/analysis/session/mod.rs index 8f27e3c7..78e496d9 100644 --- a/libs/hc_analysis/src/session/mod.rs +++ b/hipcheck/src/analysis/session/mod.rs @@ -3,44 +3,59 @@ mod pm; mod spdx; -use crate::{ - metric::{ - binary_detector::BinaryFileStorage, linguist::LinguistStorage, MetricProviderStorage, - }, - score::ScoringProviderStorage, - AnalysisProviderStorage, -}; +use crate::analysis::metric::binary_detector::BinaryFileStorage; +use crate::analysis::metric::linguist::LinguistStorage; +use crate::analysis::metric::MetricProviderStorage; +use crate::analysis::score::ScoringProviderStorage; +use crate::analysis::AnalysisProviderStorage; +use crate::command_util::DependentProgram; +use crate::config::AttacksConfigQueryStorage; +use crate::config::CommitConfigQueryStorage; +use crate::config::Config; +use crate::config::ConfigSource; +use crate::config::ConfigSourceStorage; +use crate::config::FuzzConfigQueryStorage; +use crate::config::LanguagesConfigQueryStorage; +use crate::config::PracticesConfigQueryStorage; +use crate::config::RiskConfigQueryStorage; +use crate::context::Context as _; +use crate::data::git::get_git_version; +use crate::data::git::GitProviderStorage; +use crate::data::npm::get_npm_version; +use crate::data::source::Source; +use crate::data::source::SourceChangeRequest; +use crate::data::source::SourceKind; +use crate::data::source::SourceQuery; +use crate::data::source::SourceQueryStorage; +use crate::data::source::SourceRepo; +use crate::data::CodeQualityProviderStorage; +use crate::data::DependenciesProviderStorage; +use crate::data::FuzzProviderStorage; +use crate::data::GitHubProviderStorage; +use crate::data::ModuleProvider; +use crate::data::ModuleProviderStorage; +use crate::data::PullRequestReviewProviderStorage; +use crate::error::Error; +use crate::error::Result; +use crate::filesystem::create_dir_all; +use crate::hc_error; +use crate::pathbuf; +use crate::report::Format; +use crate::report::ReportParams; +use crate::report::ReportParamsStorage; +use crate::shell::Phase; +use crate::shell::Shell; +use crate::version::get_version; +use crate::version::VersionQuery; +use crate::version::VersionQueryStorage; +use crate::HIPCHECK_TOML_FILE; +use chrono::prelude::*; use dotenv::var; -use hc_common::context::Context as _; -use hc_common::{ - chrono::prelude::*, - command_util::DependentProgram, - error::{Error, Result}, - filesystem::create_dir_all, - hc_error, pathbuf, salsa, HIPCHECK_TOML_FILE, -}; -use hc_config::{ - AttacksConfigQueryStorage, CommitConfigQueryStorage, Config, ConfigSource, ConfigSourceStorage, - FuzzConfigQueryStorage, LanguagesConfigQueryStorage, PracticesConfigQueryStorage, - RiskConfigQueryStorage, -}; -use hc_data::ModuleProvider; -use hc_data::{ - git::get_git_version, - git::GitProviderStorage, - npm::get_npm_version, - source::{ - Source, SourceChangeRequest, SourceKind, SourceQuery, SourceQueryStorage, SourceRepo, - }, - CodeQualityProviderStorage, DependenciesProviderStorage, FuzzProviderStorage, - GitHubProviderStorage, ModuleProviderStorage, PullRequestReviewProviderStorage, -}; -use hc_report::{Format, ReportParams, ReportParamsStorage}; -use hc_shell::{Phase, Shell}; -use hc_version::{get_version, VersionQuery, VersionQueryStorage}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; +use std::ffi::OsString; use std::fmt; -use std::path::{Path, PathBuf}; +use std::path::Path; +use std::path::PathBuf; use std::rc::Rc; use std::result::Result as StdResult; @@ -499,7 +514,7 @@ pub enum CheckType { #[cfg(test)] mod tests { use super::*; - use hc_common::test_util::with_env_vars; + use crate::test_util::with_env_vars; use tempfile::TempDir; const TEMPDIR_PREFIX: &str = "hc_test"; diff --git a/libs/hc_analysis/src/session/pm.rs b/hipcheck/src/analysis/session/pm.rs similarity index 97% rename from libs/hc_analysis/src/session/pm.rs rename to hipcheck/src/analysis/session/pm.rs index 3d87c878..30302161 100644 --- a/libs/hc_analysis/src/session/pm.rs +++ b/hipcheck/src/analysis/session/pm.rs @@ -1,19 +1,21 @@ // SPDX-License-Identifier: Apache-2.0 #![allow(dead_code)] -use hc_common::context::Context as _; -use hc_common::{ - error::{Error, Result}, - hc_error, - serde_json::{self, Value}, - url::{Host, Url}, - CheckKind, EXIT_FAILURE, -}; +use crate::context::Context as _; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::CheckKind; +use crate::EXIT_FAILURE; +use serde_json::Value; use std::cmp::max; use std::cmp::Ordering; use std::process::exit; -use xml::reader::{EventReader, XmlEvent}; -//This entire module was largely copied from https://gitlab.mitre.org/software-assurance/repofinder +use std::sync::Arc; +use url::Host; +use url::Url; +use xml::reader::EventReader; +use xml::reader::XmlEvent; const MAVEN: &str = CheckKind::Maven.name(); const NPM: &str = CheckKind::Npm.name(); @@ -362,7 +364,10 @@ fn extract_repo_for_npm(raw_package: &str) -> Result { }; // Make an HTTP request to that URL. - let response = ureq::get(®istry) + let response = ureq::AgentBuilder::new() + .tls_connector(Arc::new(native_tls::TlsConnector::new()?)) + .build() + .get(®istry) .call() .context("request to npm API failed, make sure the package name is correct as well as the project version")?; @@ -410,7 +415,10 @@ fn extract_repo_for_pypi(raw_package: &str) -> Result { }; // Make an HTTP request to that URL. - let response = ureq::get(®istry) + let response = ureq::AgentBuilder::new() + .tls_connector(Arc::new(native_tls::TlsConnector::new()?)) + .build() + .get(®istry) .call() .context("request to PYPI API failed, make sure the project name is correct (case matters) as well as the project version")?; @@ -442,7 +450,10 @@ fn extract_repo_for_pypi(raw_package: &str) -> Result { fn extract_repo_for_maven(url: &str) -> Result { // Make an HTTP request to that URL to get the POM file. - let response = ureq::get(url) + let response = ureq::AgentBuilder::new() + .tls_connector(Arc::new(native_tls::TlsConnector::new()?)) + .build() + .get(url) .call() .context("request to Maven API failed")?; @@ -506,8 +517,8 @@ fn is_none_or_empty(s: Option<&str>) -> bool { mod tests { // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; - use hc_common::url::Url; use serde_json::json; + use url::Url; #[test] fn test_extract_repo_for_pypi() { diff --git a/libs/hc_analysis/src/session/spdx.rs b/hipcheck/src/analysis/session/spdx.rs similarity index 94% rename from libs/hc_analysis/src/session/spdx.rs rename to hipcheck/src/analysis/session/spdx.rs index 2ccfbb67..fdd215e8 100644 --- a/libs/hc_analysis/src/session/spdx.rs +++ b/hipcheck/src/analysis/session/spdx.rs @@ -2,10 +2,13 @@ //! Utilities for extracting repository info from SPDX documents. -use hc_common::context::Context as _; -use hc_common::{error::Result, hc_error, serde_json, url::Url}; +use crate::context::Context as _; +use crate::error::Result; +use crate::hc_error; use spdx_rs::models::SPDX; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; +use std::ffi::OsString; +use url::Url; // The package download location field tag const DLOAD_LOCN_TAG: &str = "PackageDownloadLocation"; diff --git a/libs/hc_common/src/command_util.rs b/hipcheck/src/command_util.rs similarity index 93% rename from libs/hc_common/src/command_util.rs rename to hipcheck/src/command_util.rs index 36c8eb97..cbca67a4 100644 --- a/libs/hc_common/src/command_util.rs +++ b/hipcheck/src/command_util.rs @@ -1,181 +1,185 @@ -// SPDX-License-Identifier: Apache-2.0 - -use crate::context::Context as _; -use crate::{error::Result, hc_error, log, semver::Version}; -use once_cell::sync::Lazy; -use regex::Regex; -use std::collections::HashMap; -use std::convert::AsRef; -use std::env; -use std::ffi::OsStr; -use std::fmt::{self, Display, Formatter}; -use std::iter::IntoIterator; - -use DependentProgram::*; - -type VersionMap = HashMap; - -static MIN_VERSIONS: Lazy = Lazy::new(|| { - fn insert_version(hm: &mut VersionMap, program: DependentProgram) { - // SAFETY: The versions in `min_version_str` are known to be valid. - hm.insert(program, Version::parse(program.min_version_str()).unwrap()); - } - - let mut versions = HashMap::new(); - insert_version(&mut versions, EsLint); - insert_version(&mut versions, Git); - insert_version(&mut versions, Npm); - insert_version(&mut versions, ModuleDeps); - versions -}); - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -pub enum DependentProgram { - EsLint, - Git, - Npm, - ModuleDeps, -} - -impl DependentProgram { - pub fn check_version(&self, version: &str) -> Result { - let version = parse_version(*self, version)?; - let min_version = self - .min_version() - .ok_or_else(|| hc_error!("failed to get min version for {}", self))?; - - if &version >= min_version { - Ok(true) - } else { - Err(hc_error!( - "{} version is {}; must be >= {}", - self, - version, - min_version - )) - } - } - - pub fn min_version<'v>(&self) -> Option<&'v Version> { - MIN_VERSIONS.get(self) - } - - fn min_version_str(&self) -> &'static str { - match self { - // https://github.com/eslint/eslint/blob/main/CHANGELOG.md - EsLint => "7.0.0", - - // https://github.com/git/git/search?q="flag-goes-here"+in%3Afile+filename%3A*.txt+path%3ADocumentation%2FRelNotes%2F - Git => "2.14.0", - - // https://docs.npmjs.com/cli/v6/commands - Npm => "6.0.0", - - // `module-deps` doesn't report a version number, so we just lie here. - ModuleDeps => "0.0.0", - } - } -} - -impl Display for DependentProgram { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let name = match self { - EsLint => "eslint", - Git => "git", - Npm => "npm", - ModuleDeps => "module-deps", - }; - - write!(f, "{}", name) - } -} - -fn parse_version(program: DependentProgram, version: &str) -> Result { - // Typical version strings, at least on MacOS: - // - // - git: `git version 2.30.1 (Apple Git-130)` - // - eslint: `v7.32.0` - // - npm: `6.14.15` - - let re = Regex::new(r"(\d+\.\d+\.\d+)").context("failed to build version regex")?; - - let cap = re - .captures(version) - .ok_or_else(|| hc_error!("failed to capture {} version output", program))?; - - let version = cap - .get(1) - .ok_or_else(|| hc_error!("failed to find a {} version", program))? - .as_str(); - - log::debug!("{} version detected [version='{}']", program, version); - - Ok(Version::parse(version)?) -} - -/// Print command line args as well as commands and args for git commands -pub fn log_git_args(repo_path: &str, args: I, git_path: &str) -where - I: IntoIterator + Copy, - S: AsRef, -{ - let program = Git; - - log::debug!("logging {} CLI args", program); - - for arg in env::args() { - log::debug!("{} CLI environment arg [arg='{}']", program, arg); - } - - log::debug!("{} CLI executable location [path='{}']", program, git_path); - - log::debug!("{} CLI repository location [path='{}']", program, repo_path); - - log_each_arg(args, program); - - log::debug!("done logging {} CLI args", DependentProgram::Git); -} - -/// print command line args as well as commands and args for npm and other non git commands -pub fn log_args(command_path: &str, args: I, program: DependentProgram) -where - I: IntoIterator + Copy, - S: AsRef, -{ - log::debug!("logging {} CLI args", &program); - - // https://doc.rust-lang.org/std/env/fn.args.html - for arg in env::args() { - log::debug!("{} CLI environment arg [arg='{}']", program, arg); - } - - log::debug!( - "{} CLI executable location [path='{}']", - program, - command_path - ); - - log_each_arg(args, program); - - log::debug!("done logging {} CLI args", &program); -} - -pub fn log_each_arg(args: I, program: DependentProgram) -where - I: IntoIterator, - S: AsRef, -{ - for (index, val) in args.into_iter().enumerate() { - let arg_val = val - .as_ref() - .to_str() - .unwrap_or("argument for command could not be logged."); - - log::debug!( - "{} CLI argument [name='{}', value='{}']", - program, - index, - arg_val - ); - } -} +// SPDX-License-Identifier: Apache-2.0 + +use crate::context::Context as _; +use crate::error::Result; +use crate::hc_error; +use once_cell::sync::Lazy; +use regex::Regex; +use semver::Version; +use std::collections::HashMap; +use std::convert::AsRef; +use std::env; +use std::ffi::OsStr; +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; +use std::iter::IntoIterator; + +use DependentProgram::*; + +type VersionMap = HashMap; + +static MIN_VERSIONS: Lazy = Lazy::new(|| { + fn insert_version(hm: &mut VersionMap, program: DependentProgram) { + // SAFETY: The versions in `min_version_str` are known to be valid. + hm.insert(program, Version::parse(program.min_version_str()).unwrap()); + } + + let mut versions = HashMap::new(); + insert_version(&mut versions, EsLint); + insert_version(&mut versions, Git); + insert_version(&mut versions, Npm); + insert_version(&mut versions, ModuleDeps); + versions +}); + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum DependentProgram { + EsLint, + Git, + Npm, + ModuleDeps, +} + +impl DependentProgram { + pub fn check_version(&self, version: &str) -> Result { + let version = parse_version(*self, version)?; + let min_version = self + .min_version() + .ok_or_else(|| hc_error!("failed to get min version for {}", self))?; + + if &version >= min_version { + Ok(true) + } else { + Err(hc_error!( + "{} version is {}; must be >= {}", + self, + version, + min_version + )) + } + } + + pub fn min_version<'v>(&self) -> Option<&'v Version> { + MIN_VERSIONS.get(self) + } + + fn min_version_str(&self) -> &'static str { + match self { + // https://github.com/eslint/eslint/blob/main/CHANGELOG.md + EsLint => "7.0.0", + + // https://github.com/git/git/search?q="flag-goes-here"+in%3Afile+filename%3A*.txt+path%3ADocumentation%2FRelNotes%2F + Git => "2.14.0", + + // https://docs.npmjs.com/cli/v6/commands + Npm => "6.0.0", + + // `module-deps` doesn't report a version number, so we just lie here. + ModuleDeps => "0.0.0", + } + } +} + +impl Display for DependentProgram { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + let name = match self { + EsLint => "eslint", + Git => "git", + Npm => "npm", + ModuleDeps => "module-deps", + }; + + write!(f, "{}", name) + } +} + +fn parse_version(program: DependentProgram, version: &str) -> Result { + // Typical version strings, at least on MacOS: + // + // - git: `git version 2.30.1 (Apple Git-130)` + // - eslint: `v7.32.0` + // - npm: `6.14.15` + + let re = Regex::new(r"(\d+\.\d+\.\d+)").context("failed to build version regex")?; + + let cap = re + .captures(version) + .ok_or_else(|| hc_error!("failed to capture {} version output", program))?; + + let version = cap + .get(1) + .ok_or_else(|| hc_error!("failed to find a {} version", program))? + .as_str(); + + log::debug!("{} version detected [version='{}']", program, version); + + Ok(Version::parse(version)?) +} + +/// Print command line args as well as commands and args for git commands +pub fn log_git_args(repo_path: &str, args: I, git_path: &str) +where + I: IntoIterator + Copy, + S: AsRef, +{ + let program = Git; + + log::debug!("logging {} CLI args", program); + + for arg in env::args() { + log::debug!("{} CLI environment arg [arg='{}']", program, arg); + } + + log::debug!("{} CLI executable location [path='{}']", program, git_path); + + log::debug!("{} CLI repository location [path='{}']", program, repo_path); + + log_each_arg(args, program); + + log::debug!("done logging {} CLI args", DependentProgram::Git); +} + +/// print command line args as well as commands and args for npm and other non git commands +pub fn log_args(command_path: &str, args: I, program: DependentProgram) +where + I: IntoIterator + Copy, + S: AsRef, +{ + log::debug!("logging {} CLI args", &program); + + // https://doc.rust-lang.org/std/env/fn.args.html + for arg in env::args() { + log::debug!("{} CLI environment arg [arg='{}']", program, arg); + } + + log::debug!( + "{} CLI executable location [path='{}']", + program, + command_path + ); + + log_each_arg(args, program); + + log::debug!("done logging {} CLI args", &program); +} + +pub fn log_each_arg(args: I, program: DependentProgram) +where + I: IntoIterator, + S: AsRef, +{ + for (index, val) in args.into_iter().enumerate() { + let arg_val = val + .as_ref() + .to_str() + .unwrap_or("argument for command could not be logged."); + + log::debug!( + "{} CLI argument [name='{}', value='{}']", + program, + index, + arg_val + ); + } +} diff --git a/libs/hc_config/src/query.rs b/hipcheck/src/config.rs similarity index 52% rename from libs/hc_config/src/query.rs rename to hipcheck/src/config.rs index cb8cdb7e..9951146e 100644 --- a/libs/hc_config/src/query.rs +++ b/hipcheck/src/config.rs @@ -1,12 +1,474 @@ // SPDX-License-Identifier: Apache-2.0 -//! Query groups for accessing Hipcheck configuration data. - -use crate::Config; -use hc_common::{pathbuf, salsa, BINARY_CONFIG_FILE, F64, LANGS_FILE, ORGS_FILE, TYPO_FILE}; +//! Defines the configuration file format. + +use crate::context::Context; +use crate::error::Result; +use crate::filesystem as file; +use crate::pathbuf; +use crate::BINARY_CONFIG_FILE; +use crate::F64; +use crate::LANGS_FILE; +use crate::ORGS_FILE; +use crate::TYPO_FILE; +use serde::Deserialize; +use serde::Serialize; +use smart_default::SmartDefault; +use std::default::Default; +use std::path::Path; use std::path::PathBuf; use std::rc::Rc; +impl Config { + /// Load configuration from the given directory. + pub fn load_from(config_path: &Path) -> Result { + file::exists(config_path)?; + let config = file::read_toml(config_path).context("can't parse config file")?; + + Ok(config) + } +} + +/// Represents the configuration of Hipcheck's analyses. +#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)] +#[serde(default)] +pub struct Config { + /// The configuration of overall project risk tolerance. + #[serde(default)] + pub risk: RiskConfig, + + /// The configuration of Hipcheck's different analyses. + #[serde(default)] + pub analysis: AnalysisConfig, + + /// The configuration of Hipcheck's knowledge about languages. + #[serde(default)] + pub languages: LanguagesConfig, +} + +/// Represents configuration of the overall risk threshold of an assessment. +#[derive(Debug, Serialize, Deserialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct RiskConfig { + /// The risk tolerance threshold, a value between 0 and 1. + #[default(_code = "F64::new(0.5).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub threshold: F64, +} + +/// Defines configuration for all of Hipcheck's analyses. +#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)] +#[serde(default)] +pub struct AnalysisConfig { + /// Defines configuration for practices analysis. + #[serde(default)] + pub practices: PracticesConfig, + + /// Defines configuration for attack analysis. + #[serde(default)] + pub attacks: AttacksConfig, +} + +/// Configuration of analyses on a repo's development practices. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct PracticesConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// Defines configuration for activity analysis. + #[serde(default)] + pub activity: ActivityConfig, + + /// Defines configuration for binary file analysis. + #[serde(default)] + pub binary: BinaryConfig, + + /// Defines configuration for in fuzz analysis. + #[serde(default)] + pub fuzz: FuzzConfig, + + /// Defines configuration for identity analysis. + #[serde(default)] + pub identity: IdentityConfig, + + /// Defines configuration for review analysis. + #[serde(default)] + pub review: ReviewConfig, +} + +/// Configuration of analyses on potential attacks against a repo. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct AttacksConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// Defines configuration for typo analysis. + #[serde(default)] + pub typo: TypoConfig, + + /// Defines configuration for commit analysis. + #[serde(default)] + pub commit: CommitConfig, +} + +/// Configuration of analyses on individual commits. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct CommitConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// Defines configuration for affiliation analysis. + #[serde(default)] + pub affiliation: AffiliationConfig, + + /// Defines configuration for churn analysis. + #[serde(default)] + pub churn: ChurnConfig, + + /// Defines configuration for contributor trust analysis. + #[serde(default)] + pub contributor_trust: ContributorTrustConfig, + + /// Defines configuration for contributor trust analysis. + #[serde(default)] + pub commit_trust: CommitTrustConfig, + + /// Defines configuration for entropy analysis. + #[serde(default)] + pub entropy: EntropyConfig, + + /// Defines configuration for pull request affiliation analysis. + #[serde(default)] + pub pr_affiliation: PrAffiliationConfig, + + /// Defines configuration for pull request module contributors analysis. + #[serde(default)] + pub pr_module_contributors: PrModuleContributorsConfig, +} + +/// Defines configuration for activity analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct ActivityConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A number of weeks, over which a repo fails the analysis. + #[default = 71] + pub week_count_threshold: u64, +} + +/// Defines configuration for affiliation analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct AffiliationConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A number of affiliations permitted, over which a repo fails the analysis. + #[default = 0] + pub count_threshold: u64, + + /// An "orgs file" containing info for affiliation matching. + #[default = "Orgs.toml"] + pub orgs_file: String, +} + +/// Defines configuration for binary file analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct BinaryConfig { + /// Binary file extension configuration file. + #[default = "Binary.toml"] + pub binary_config_file: String, + + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A count of binary files over which a repo fails the analysis. + #[default = 0] + pub binary_file_threshold: u64, +} + +/// Defines configuration for churn analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct ChurnConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A churn Z-score, over which a commit is marked as "bad" + #[default(_code = "F64::new(3.0).unwrap()")] + pub value_threshold: F64, + + /// A percentage of "bad" commits over which a repo fails the analysis. + #[default(_code = "F64::new(0.02).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines configuration for commit trust analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct CommitTrustConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, +} + +/// Defines configuration for contributor trust analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct ContributorTrustConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A trust N-score, number of commits over which a commitor is marked as trusted or not + #[default = 3] + pub value_threshold: u64, + + /// A number of months over which a contributor would be tracked for trust. + #[default = 3] + pub trust_month_count_threshold: u64, + + /// A percentage of "bad" commits over which a repo fails the analysis because commit is not trusted. + #[default(_code = "F64::new(0.0).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines configuration for entropy analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct EntropyConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// An entropy Z-score, over which a commit is marked as "bad" + #[default(_code = "F64::new(10.0).unwrap()")] + pub value_threshold: F64, + + /// A percentage of "bad" commits over which a repo fails the analysis. + #[default(_code = "F64::new(0.0).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines configuration for identity analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct IdentityConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A percentage of commits permitted to have a mismatch between committer and + /// submitter identity, over which a repo fails the analysis. + #[default(_code = "F64::new(0.20).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines configuration for review analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct ReviewConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A percentage of pull requests permitted to not have review prior to being + /// merged, over which a repo fails the analysis. + #[default(_code = "F64::new(0.05).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines configuration for typo analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct TypoConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// The number of potential dependency name typos permitted, over which + /// a repo fails the analysis. + #[default = 0] + pub count_threshold: u64, + + /// Path to a "typos file" containing necessary information for typo detection. + #[default = "Typos.toml"] + pub typo_file: String, +} + +/// Defines configuration for pull request affiliation analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct PrAffiliationConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// A number of affiliations permitted, over which a repo fails the analysis. + #[default = 0] + pub count_threshold: u64, +} + +/// Defines configuration for pull request module committers analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct PrModuleContributorsConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, + + /// Percent of committers working on a module for the first time permitted, over which a repo fails the analysis. + #[default(_code = "F64::new(0.30).unwrap()")] + #[serde(deserialize_with = "de::percent")] + pub percent_threshold: F64, +} + +/// Defines the configuration of language-specific info. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct LanguagesConfig { + /// The file to pull language information from. + #[default = "Langs.toml"] + pub langs_file: String, +} + +/// Defines configuration for fuzz analysis. +#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] +#[serde(default)] +pub struct FuzzConfig { + /// Whether the analysis is active. + #[default = true] + pub active: bool, + + /// How heavily the analysis' results weigh in risk scoring. + #[default = 1] + pub weight: u64, +} + +/// Inner module for deserialization helpers. +mod de { + use super::F64; + use serde::de; + use serde::de::Deserializer; + use serde::de::Visitor; + use std::fmt; + use std::fmt::Formatter; + + /// Deserialize a float, ensuring it's between 0.0 and 1.0 inclusive. + pub(super) fn percent<'de, D>(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct PercentVisitor; + + impl<'de> Visitor<'de> for PercentVisitor { + type Value = f64; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a float between 0.0 and 1.0 inclusive") + } + + fn visit_f64(self, value: f64) -> Result + where + E: de::Error, + { + if is_percent(value) { + Ok(value) + } else { + Err(de::Error::custom("must be between 0.0 and 1.0 inclusive")) + } + } + } + + // Deserialize and return as `F64` + let percent = deserializer.deserialize_f64(PercentVisitor)?; + Ok(F64::new(percent).unwrap()) + } + + /// Check if a float is a valid percent value. + fn is_percent(f: f64) -> bool { + (0.0..=1.0).contains(&f) + } +} + /// Query for accessing a source of Hipcheck config data #[salsa::query_group(ConfigSourceStorage)] pub trait ConfigSource: salsa::Database { diff --git a/libs/hc_common/src/context.rs b/hipcheck/src/context.rs similarity index 95% rename from libs/hc_common/src/context.rs rename to hipcheck/src/context.rs index e1c6d0b9..2cce5058 100644 --- a/libs/hc_common/src/context.rs +++ b/hipcheck/src/context.rs @@ -3,7 +3,8 @@ //! A duplicate of the `anyhow::Context` extension trait intended to //! make error propagation less verbose. -use crate::error::{Error, Introspect}; +use crate::error::Error; +use crate::error::Introspect; use std::error::Error as StdError; /// Functions for adding context to an error result @@ -69,7 +70,8 @@ where // Restricts implementations of `Context` only to those contained in // this module mod sealed { - use super::{Error, StdError}; + use super::Error; + use super::StdError; pub trait Sealed {} diff --git a/libs/hc_data/src/lib.rs b/hipcheck/src/data.rs similarity index 93% rename from libs/hc_data/src/lib.rs rename to hipcheck/src/data.rs index 4ba6f471..6971d2c2 100644 --- a/libs/hc_data/src/lib.rs +++ b/hipcheck/src/data.rs @@ -16,18 +16,21 @@ pub mod source; pub use query::*; use std::collections::HashSet; -use git::{get_commits_for_file, Commit, CommitContributor, Contributor, Diff}; +use crate::context::Context; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::pathbuf; +use git::get_commits_for_file; +use git::Commit; +use git::CommitContributor; +use git::Contributor; +use git::Diff; use github::*; -use hc_common::{ - context::Context, - error::Error, - error::Result, - hc_error, log, pathbuf, - serde::{self, Serialize}, -}; use modules::RawModule; use petgraph::visit::Dfs; use petgraph::Graph; +use serde::Serialize; use std::path::Path; use std::rc::Rc; @@ -71,13 +74,12 @@ impl Lang { } #[derive(Clone, Debug, Serialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct Fuzz { pub exists: bool, } pub fn get_fuzz_check(token: &str, repo_uri: Rc) -> Result { - let github = GitHub::new("google", "oss-fuzz", token); + let github = GitHub::new("google", "oss-fuzz", token)?; let github_result = github .fuzz_check(repo_uri) @@ -91,14 +93,12 @@ pub fn get_fuzz_check(token: &str, repo_uri: Rc) -> Result { } #[derive(Debug, Serialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct PullRequest { pub id: u64, pub reviews: u64, } #[derive(Debug, Serialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct SinglePullRequest { pub id: u64, pub reviews: u64, @@ -113,7 +113,7 @@ pub fn get_pull_request_reviews_from_github( repo: &str, token: &str, ) -> Result> { - let github = GitHub::new(owner, repo, token); + let github = GitHub::new(owner, repo, token)?; let results = github .get_reviews_for_pr() @@ -134,7 +134,7 @@ pub fn get_single_pull_request_review_from_github( pull_request: &u64, token: &str, ) -> Result { - let github_pr = GitHubPr::new(owner, repo, pull_request, token); + let github_pr = GitHubPr::new(owner, repo, pull_request, token)?; let github_result = github_pr .get_review_for_single_pr() @@ -212,21 +212,19 @@ pub fn get_single_pull_request_review_from_github( // Module structs/enums +#[allow(unused)] #[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize)] -#[serde(crate = "self::serde")] pub enum Relationship { Child, Import, } #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize)] -#[serde(crate = "self::serde")] pub struct Module { pub file: String, } #[derive(Clone, Debug, Serialize)] -#[serde(crate = "self::serde")] pub struct ModuleGraph { pub connections: Graph, } diff --git a/libs/hc_data/src/code_quality.rs b/hipcheck/src/data/code_quality.rs similarity index 90% rename from libs/hc_data/src/code_quality.rs rename to hipcheck/src/data/code_quality.rs index bb2ff80b..04f573ae 100644 --- a/libs/hc_data/src/code_quality.rs +++ b/hipcheck/src/data/code_quality.rs @@ -1,10 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -use std::path::{Path, PathBuf}; +use std::path::Path; +use std::path::PathBuf; -use crate::es_lint::data::{ESLintMessage, ESLintReports}; -use crate::es_lint::get_eslint_reports; -use hc_common::{error::Result, hc_error}; +use crate::data::es_lint::data::ESLintMessage; +use crate::data::es_lint::data::ESLintReports; +use crate::data::es_lint::get_eslint_reports; +use crate::error::Result; +use crate::hc_error; pub type CodeQualityReport = Vec; diff --git a/libs/hc_data/src/es_lint/command.rs b/hipcheck/src/data/es_lint/command.rs similarity index 91% rename from libs/hc_data/src/es_lint/command.rs rename to hipcheck/src/data/es_lint/command.rs index fe2d1d96..4fb4ba51 100644 --- a/libs/hc_data/src/es_lint/command.rs +++ b/hipcheck/src/data/es_lint/command.rs @@ -3,12 +3,11 @@ use std::ffi::OsStr; use std::process::Command; -use hc_common::context::Context as _; -use hc_common::{ - command_util::{log_args, DependentProgram}, - error::Result, - hc_error, log, which, -}; +use crate::command_util::log_args; +use crate::command_util::DependentProgram; +use crate::context::Context as _; +use crate::error::Result; +use crate::hc_error; #[derive(Debug)] pub struct ESLintCommand { diff --git a/libs/hc_data/src/es_lint/data.rs b/hipcheck/src/data/es_lint/data.rs similarity index 94% rename from libs/hc_data/src/es_lint/data.rs rename to hipcheck/src/data/es_lint/data.rs index 48f78423..e6ddf498 100644 --- a/libs/hc_data/src/es_lint/data.rs +++ b/hipcheck/src/data/es_lint/data.rs @@ -4,12 +4,16 @@ /// https://eslint.org/docs/user-guide/formatters/#json /// /// This parser has been tested with the output from ESLint v7.31.0 -use hc_common::serde::{self, Deserialize}; +use serde::Deserialize; + +// ESLint's JSON output is demonstrated here: +// https://eslint.org/docs/user-guide/formatters/#json +// +// This parser has been tested with the output from ESLint v7.31.0 pub type ESLintReports = Vec; #[derive(Debug, Clone, Deserialize)] -#[serde(crate = "self::serde")] pub struct ESLintReport { #[serde(rename = "filePath")] pub file_path: String, @@ -26,7 +30,6 @@ pub struct ESLintReport { } #[derive(Debug, Clone, Deserialize)] -#[serde(crate = "self::serde")] pub struct ESLintMessage { #[serde(rename = "ruleId")] pub rule_id: String, @@ -43,7 +46,6 @@ pub struct ESLintMessage { #[cfg(test)] mod test { use super::*; - use hc_common::serde_json; #[test] fn parse_message() { diff --git a/libs/hc_data/src/es_lint/mod.rs b/hipcheck/src/data/es_lint/mod.rs similarity index 95% rename from libs/hc_data/src/es_lint/mod.rs rename to hipcheck/src/data/es_lint/mod.rs index e478d42a..cfa80f13 100644 --- a/libs/hc_data/src/es_lint/mod.rs +++ b/hipcheck/src/data/es_lint/mod.rs @@ -3,10 +3,11 @@ use std::ffi::OsStr; use std::path::Path; +use crate::context::Context as _; +use crate::error::Result; use command::ESLintCommand; use data::ESLintReports; -use hc_common::context::Context as _; -use hc_common::{error::Result, semver::Version, serde_json}; +use semver::Version; pub mod command; pub mod data; @@ -47,7 +48,7 @@ pub fn get_eslint_reports(path: &Path, version: String) -> Result mod test { use super::*; - use hc_common::command_util::DependentProgram; + use crate::command_util::DependentProgram; use std::fs::File; use std::io::Write; diff --git a/libs/hc_data/src/git/data.rs b/hipcheck/src/data/git/data.rs similarity index 87% rename from libs/hc_data/src/git/data.rs rename to hipcheck/src/data/git/data.rs index c69a03d7..9c8a58d2 100644 --- a/libs/hc_data/src/git/data.rs +++ b/hipcheck/src/data/git/data.rs @@ -1,15 +1,16 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::{ - chrono::{DateTime, FixedOffset}, - serde::{self, Deserialize, Serialize}, -}; -use std::fmt::{self, Display, Formatter}; +use chrono::DateTime; +use chrono::FixedOffset; +use serde::Deserialize; +use serde::Serialize; +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; use std::rc::Rc; /// Commits as they come directly out of `git log`. #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct RawCommit { pub hash: String, @@ -25,7 +26,6 @@ pub struct RawCommit { /// Commits as understood in Hipcheck's data model. #[derive(Debug, Serialize, Clone, PartialEq, Eq, Hash)] -#[serde(crate = "self::serde")] pub struct Commit { pub hash: String, @@ -42,7 +42,6 @@ impl Display for Commit { /// Authors or committers of a commit. #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Clone, Hash, PartialOrd, Ord)] -#[serde(crate = "self::serde")] pub struct Contributor { pub name: String, pub email: String, @@ -56,7 +55,6 @@ impl Display for Contributor { /// "Joim struct" for commits and contributors. #[derive(Debug, PartialEq, Eq, Serialize, Clone)] -#[serde(crate = "self::serde")] pub struct CommitContributor { // Index of commit cache pub commit_id: usize, @@ -67,7 +65,6 @@ pub struct CommitContributor { /// "Join struct" for commits and signature data. #[derive(Debug, PartialEq, Eq, Serialize, Clone)] -#[serde(crate = "self::serde")] pub struct CommitSigner { // Index of commit cache pub commit_id: usize, @@ -79,7 +76,6 @@ pub struct CommitSigner { /// Temporary data structure for looking up the contributors of a commit #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct CommitContributorView { pub commit: Rc, pub author: Rc, @@ -88,7 +84,6 @@ pub struct CommitContributorView { /// Temporary data structure for looking up the commits associated with a contributor #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct ContributorView { pub contributor: Rc, pub commits: Vec>, @@ -96,7 +91,6 @@ pub struct ContributorView { /// Temporary data structure for looking up the signer of a commit #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct CommitSignerView { pub commit: Rc, pub signer_name: Option>, @@ -105,7 +99,6 @@ pub struct CommitSignerView { /// Temporary data structure for looking up the commits associated with a signer name #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct SignerNameView { pub signer_name: Rc, pub commits: Vec>, @@ -113,7 +106,6 @@ pub struct SignerNameView { /// Temporary data structure for looking up the commits associated with a signer key #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct SignerKeyView { pub signer_key: Rc, pub commits: Vec>, @@ -121,7 +113,6 @@ pub struct SignerKeyView { /// Temporary data structure for looking up the keys associated with a signer name #[derive(Debug, Serialize, Clone, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct SignerView { pub signer_name: Rc, pub signer_keys: Vec>, @@ -129,7 +120,6 @@ pub struct SignerView { /// View into commits and diffs joined together. #[derive(Debug, Serialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct CommitDiff { pub commit: Rc, pub diff: Rc, @@ -157,7 +147,6 @@ impl Display for CommitDiff { /// A set of changes in a commit. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct Diff { pub additions: Option, pub deletions: Option, @@ -166,7 +155,6 @@ pub struct Diff { /// A set of changes to a specific file in a commit. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] -#[serde(crate = "self::serde")] pub struct FileDiff { pub file_name: Rc, pub additions: Option, diff --git a/libs/hc_data/src/git/mod.rs b/hipcheck/src/data/git/mod.rs similarity index 93% rename from libs/hc_data/src/git/mod.rs rename to hipcheck/src/data/git/mod.rs index b7fef0bb..47de9162 100644 --- a/libs/hc_data/src/git/mod.rs +++ b/hipcheck/src/data/git/mod.rs @@ -8,12 +8,10 @@ pub use data::*; use parse::*; pub use query::*; -pub use crate::git_command::*; -use hc_common::context::Context as _; -use hc_common::{ - error::{Error, Result}, - log, -}; +use crate::context::Context as _; +pub use crate::data::git_command::*; +use crate::error::Error; +use crate::error::Result; use std::path::Path; pub fn get_git_version() -> Result { @@ -62,6 +60,7 @@ pub fn get_commits_from_date(repo: &Path, date: &str) -> Result> git_log(&raw_output) } +#[allow(unused)] pub fn get_last_commit(repo: &Path) -> Result { let mut raw_commits = get_commits(repo)?; @@ -106,7 +105,7 @@ pub fn get_commits_for_file(repo_path: &Path, file: &str) -> Result { #[cfg(test)] mod test { use super::*; - use hc_common::command_util::DependentProgram; + use crate::command_util::DependentProgram; #[test] #[ignore = "can't guarantee availability of Git"] diff --git a/libs/hc_data/src/git/parse.rs b/hipcheck/src/data/git/parse.rs similarity index 97% rename from libs/hc_data/src/git/parse.rs rename to hipcheck/src/data/git/parse.rs index 9c6aac32..e95f6a36 100644 --- a/libs/hc_data/src/git/parse.rs +++ b/hipcheck/src/data/git/parse.rs @@ -2,22 +2,34 @@ #![allow(dead_code)] -use crate::git::{Contributor, Diff, FileDiff, RawCommit}; -use hc_common::context::Context as _; -use hc_common::{ - chrono::{DateTime, FixedOffset}, - error::{Error, Result}, - log, -}; -use nom::{ - branch::alt, - character::complete::{char as character, digit1, not_line_ending, one_of, space1}, - combinator::{opt, peek, recognize}, - error::{Error as NomError, ErrorKind}, - multi::{fold_many0, many0, many1, many_m_n}, - sequence::{preceded, terminated, tuple}, - IResult, -}; +use crate::context::Context as _; +use crate::data::git::Contributor; +use crate::data::git::Diff; +use crate::data::git::FileDiff; +use crate::data::git::RawCommit; +use crate::error::Error; +use crate::error::Result; +use chrono::DateTime; +use chrono::FixedOffset; +use nom::branch::alt; +use nom::character::complete::char as character; +use nom::character::complete::digit1; +use nom::character::complete::not_line_ending; +use nom::character::complete::one_of; +use nom::character::complete::space1; +use nom::combinator::opt; +use nom::combinator::peek; +use nom::combinator::recognize; +use nom::error::Error as NomError; +use nom::error::ErrorKind; +use nom::multi::fold_many0; +use nom::multi::many0; +use nom::multi::many1; +use nom::multi::many_m_n; +use nom::sequence::preceded; +use nom::sequence::terminated; +use nom::sequence::tuple; +use nom::IResult; use std::iter::Iterator; use std::rc::Rc; use std::result::Result as StdResult; @@ -1001,7 +1013,7 @@ index 20b42ecfdf..b0f30e8e35 100644 +++ b/README.md @@ -432,24 +432,31 @@ Other Style Guides }); - + // bad - inbox.filter((msg) => { - const { subject, author } = msg; @@ -1014,28 +1026,28 @@ index 20b42ecfdf..b0f30e8e35 100644 + var indexMap = myArray.reduce(function(memo, item, index) { + memo[item] = index; + }, {}); - + - // good - inbox.filter((msg) => { - const { subject, author } = msg; - if (subject === 'Mockingbird') { - return author === 'Harper Lee'; - } - + - return false; + // good + var indexMap = myArray.reduce(function(memo, item, index) { + memo[item] = index; + return memo; + }, {}); -+ -+ ++ ++ + // bad + const alpha = people.sort((lastOne, nextOne) => { + const [aLast, aFirst] = lastOne.split(', '); + const [bLast, bFirst] = nextOne.split(', '); }); -+ ++ + // good + const alpha = people.sort((lastOne, nextOne) => { + const [aLast, aFirst] = lastOne.split(', '); @@ -1044,7 +1056,7 @@ index 20b42ecfdf..b0f30e8e35 100644 + }); + ``` - + "#; @@ -1071,13 +1083,13 @@ index 20b42ecfdf..b0f30e8e35 100644 memo[item] = index; return memo; }, {}); - - + + // bad const alpha = people.sort((lastOne, nextOne) => { const [aLast, aFirst] = lastOne.split(', '); const [bLast, bFirst] = nextOne.split(', '); - + // good const alpha = people.sort((lastOne, nextOne) => { const [aLast, aFirst] = lastOne.split(', '); @@ -1105,7 +1117,7 @@ index 20b42ecfdf..b0f30e8e35 100644 +++ b/README.md @@ -432,24 +432,31 @@ Other Style Guides }); - + // bad - inbox.filter((msg) => { - const { subject, author } = msg; @@ -1118,28 +1130,28 @@ index 20b42ecfdf..b0f30e8e35 100644 + var indexMap = myArray.reduce(function(memo, item, index) { + memo[item] = index; + }, {}); - + - // good - inbox.filter((msg) => { - const { subject, author } = msg; - if (subject === 'Mockingbird') { - return author === 'Harper Lee'; - } - + - return false; + // good + var indexMap = myArray.reduce(function(memo, item, index) { + memo[item] = index; + return memo; + }, {}); -+ -+ ++ ++ + // bad + const alpha = people.sort((lastOne, nextOne) => { + const [aLast, aFirst] = lastOne.split(', '); + const [bLast, bFirst] = nextOne.split(', '); }); -+ ++ + // good + const alpha = people.sort((lastOne, nextOne) => { + const [aLast, aFirst] = lastOne.split(', '); @@ -1148,7 +1160,7 @@ index 20b42ecfdf..b0f30e8e35 100644 + }); + ``` - + "#; @@ -1175,13 +1187,13 @@ index 20b42ecfdf..b0f30e8e35 100644 memo[item] = index; return memo; }, {}); - - + + // bad const alpha = people.sort((lastOne, nextOne) => { const [aLast, aFirst] = lastOne.split(', '); const [bLast, bFirst] = nextOne.split(', '); - + // good const alpha = people.sort((lastOne, nextOne) => { const [aLast, aFirst] = lastOne.split(', '); diff --git a/libs/hc_data/src/git/query/impls.rs b/hipcheck/src/data/git/query/impls.rs similarity index 94% rename from libs/hc_data/src/git/query/impls.rs rename to hipcheck/src/data/git/query/impls.rs index 0293a7ed..6c277689 100644 --- a/libs/hc_data/src/git/query/impls.rs +++ b/hipcheck/src/data/git/query/impls.rs @@ -3,16 +3,27 @@ //! Derived query implementations for the `GitProvider` query group. use super::GitProvider; -use crate::git::{ - get_commits, get_commits_from_date, get_diffs, Commit, CommitContributor, - CommitContributorView, CommitDiff, CommitSigner, CommitSignerView, Contributor, - ContributorView, Diff, GitCommand, RawCommit, SignerKeyView, SignerNameView, SignerView, -}; -use hc_common::{ - chrono::prelude::*, - context::Context, - error::{Error, Result}, -}; +use crate::context::Context; +use crate::data::git::get_commits; +use crate::data::git::get_commits_from_date; +use crate::data::git::get_diffs; +use crate::data::git::Commit; +use crate::data::git::CommitContributor; +use crate::data::git::CommitContributorView; +use crate::data::git::CommitDiff; +use crate::data::git::CommitSigner; +use crate::data::git::CommitSignerView; +use crate::data::git::Contributor; +use crate::data::git::ContributorView; +use crate::data::git::Diff; +use crate::data::git::GitCommand; +use crate::data::git::RawCommit; +use crate::data::git::SignerKeyView; +use crate::data::git::SignerNameView; +use crate::data::git::SignerView; +use crate::error::Error; +use crate::error::Result; +use chrono::prelude::*; use std::rc::Rc; pub(crate) fn raw_commits(db: &dyn GitProvider) -> Result>> { diff --git a/libs/hc_data/src/git/query/mod.rs b/hipcheck/src/data/git/query/mod.rs similarity index 85% rename from libs/hc_data/src/git/query/mod.rs rename to hipcheck/src/data/git/query/mod.rs index da1e8997..58b8e695 100644 --- a/libs/hc_data/src/git/query/mod.rs +++ b/hipcheck/src/data/git/query/mod.rs @@ -4,16 +4,23 @@ mod impls; -use crate::{ - git::{ - Commit, CommitContributor, CommitContributorView, CommitDiff, CommitSigner, - CommitSignerView, Contributor, ContributorView, Diff, RawCommit, SignerKeyView, - SignerNameView, SignerView, - }, - source::SourceQuery, -}; -use hc_common::{chrono::prelude::*, error::Result, salsa}; -use hc_version::VersionQuery; +use crate::data::git::Commit; +use crate::data::git::CommitContributor; +use crate::data::git::CommitContributorView; +use crate::data::git::CommitDiff; +use crate::data::git::CommitSigner; +use crate::data::git::CommitSignerView; +use crate::data::git::Contributor; +use crate::data::git::ContributorView; +use crate::data::git::Diff; +use crate::data::git::RawCommit; +use crate::data::git::SignerKeyView; +use crate::data::git::SignerNameView; +use crate::data::git::SignerView; +use crate::data::source::SourceQuery; +use crate::error::Result; +use crate::version::VersionQuery; +use chrono::prelude::*; use std::rc::Rc; /// Queries about Git objects diff --git a/libs/hc_data/src/git_command.rs b/hipcheck/src/data/git_command.rs similarity index 94% rename from libs/hc_data/src/git_command.rs rename to hipcheck/src/data/git_command.rs index 6c04835b..113b6802 100644 --- a/libs/hc_data/src/git_command.rs +++ b/hipcheck/src/data/git_command.rs @@ -1,7 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::context::Context as _; -use hc_common::{command_util::log_git_args, error::Result, hc_error, which}; +use crate::command_util::log_git_args; +use crate::context::Context as _; +use crate::error::Result; +use crate::hc_error; use std::convert::AsRef; use std::ffi::OsStr; use std::iter::IntoIterator; diff --git a/libs/hc_data/src/github/authenticated_agent.rs b/hipcheck/src/data/github/authenticated_agent.rs similarity index 74% rename from libs/hc_data/src/github/authenticated_agent.rs rename to hipcheck/src/data/github/authenticated_agent.rs index 49804686..bfaabe08 100644 --- a/libs/hc_data/src/github/authenticated_agent.rs +++ b/hipcheck/src/data/github/authenticated_agent.rs @@ -1,7 +1,13 @@ //! Defines an authenticated [`Agent`] type that adds token auth to all requests. -use crate::github::hidden::Hidden; -use ureq::{Agent, Request}; +use std::sync::Arc; + +use crate::data::github::hidden::Hidden; +use crate::error::Result; +use native_tls::TlsConnector; +use ureq::Agent; +use ureq::AgentBuilder; +use ureq::Request; /// An [`Agent`] which authenticates requests with token auth. /// @@ -17,11 +23,14 @@ pub struct AuthenticatedAgent<'token> { impl<'token> AuthenticatedAgent<'token> { /// Construct a new authenticated agent. - pub fn new(token: &'token str) -> AuthenticatedAgent<'token> { - AuthenticatedAgent { - agent: Agent::new(), - token: Hidden::new(token), - } + pub fn new(token: &'token str) -> Result> { + let agent = AgentBuilder::new() + .tls_connector(Arc::new(TlsConnector::new()?)) + .build(); + + let token = Hidden::new(token); + + Ok(AuthenticatedAgent { agent, token }) } /// Make an authenticated GET request. diff --git a/libs/hc_data/src/github/code_search.rs b/hipcheck/src/data/github/code_search.rs similarity index 90% rename from libs/hc_data/src/github/code_search.rs rename to hipcheck/src/data/github/code_search.rs index d2c80951..a51c7a12 100644 --- a/libs/hc_data/src/github/code_search.rs +++ b/hipcheck/src/data/github/code_search.rs @@ -1,11 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::github::authenticated_agent::AuthenticatedAgent; -use hc_common::{ - error::{Error, Result}, - hc_error, - serde_json::Value, -}; +use crate::data::github::authenticated_agent::AuthenticatedAgent; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use serde_json::Value; use std::rc::Rc; const GH_API_V4_SEARCH: &str = "https://api.github.com/search/code"; diff --git a/libs/hc_data/src/github/data.rs b/hipcheck/src/data/github/data.rs similarity index 88% rename from libs/hc_data/src/github/data.rs rename to hipcheck/src/data/github/data.rs index b9827f05..5750ffec 100644 --- a/libs/hc_data/src/github/data.rs +++ b/hipcheck/src/data/github/data.rs @@ -1,8 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -use crate::git::{Diff, RawCommit}; - +use crate::data::git::Diff; +use crate::data::git::RawCommit; use serde::Deserialize; + #[derive(Debug, Deserialize)] pub struct GitHubFullPullRequest { pub pull_request: GitHubPullRequest, diff --git a/libs/hc_data/src/github/gh_query.graphql b/hipcheck/src/data/github/gh_query.graphql similarity index 100% rename from libs/hc_data/src/github/gh_query.graphql rename to hipcheck/src/data/github/gh_query.graphql diff --git a/libs/hc_data/src/github/gh_schema.graphql b/hipcheck/src/data/github/gh_schema.graphql similarity index 100% rename from libs/hc_data/src/github/gh_schema.graphql rename to hipcheck/src/data/github/gh_schema.graphql diff --git a/libs/hc_data/src/github/graphql.rs b/hipcheck/src/data/github/graphql.rs similarity index 85% rename from libs/hc_data/src/github/graphql.rs rename to hipcheck/src/data/github/graphql.rs index 790b968a..3082523f 100644 --- a/libs/hc_data/src/github/graphql.rs +++ b/hipcheck/src/data/github/graphql.rs @@ -2,14 +2,19 @@ use std::convert::TryInto; -use self::reviews::{ResponseData, ReviewsRepositoryPullRequestsNodes as RawPull, Variables}; -use crate::github::{authenticated_agent::AuthenticatedAgent, data::*}; -use graphql_client::{GraphQLQuery, QueryBody, Response}; -use hc_common::{ - error::{Error, Result}, - hc_error, - serde_json::{from_value as from_json_value, to_value as to_json_value}, -}; +use self::reviews::ResponseData; +use self::reviews::ReviewsRepositoryPullRequestsNodes as RawPull; +use self::reviews::Variables; +use crate::data::github::authenticated_agent::AuthenticatedAgent; +use crate::data::github::data::*; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use graphql_client::GraphQLQuery; +use graphql_client::QueryBody; +use graphql_client::Response; +use serde_json::from_value as from_json_value; +use serde_json::to_value as to_json_value; /// The URL of the GitHub GraphQL API. const GH_API_V4: &str = "https://api.github.com/graphql"; @@ -17,8 +22,8 @@ const GH_API_V4: &str = "https://api.github.com/graphql"; /// Defines the query being made against the GitHub API. #[derive(GraphQLQuery)] #[graphql( - schema_path = "src/github/gh_schema.graphql", - query_path = "src/github/gh_query.graphql", + schema_path = "src/data/github/gh_schema.graphql", + query_path = "src/data/github/gh_query.graphql", response_derives = "Debug" )] pub struct Reviews; diff --git a/libs/hc_data/src/github/graphql_pr.rs b/hipcheck/src/data/github/graphql_pr.rs similarity index 89% rename from libs/hc_data/src/github/graphql_pr.rs rename to hipcheck/src/data/github/graphql_pr.rs index 251f21bd..7d7fc294 100644 --- a/libs/hc_data/src/github/graphql_pr.rs +++ b/hipcheck/src/data/github/graphql_pr.rs @@ -1,21 +1,23 @@ // SPDX-License-Identifier: Apache-2.0 -use self::review::{ - ResponseData, ReviewRepositoryPullRequest as RawPull, - ReviewRepositoryPullRequestCommitsNodes as RawPullCommit, Variables, -}; -use crate::{ - git::{Contributor, RawCommit}, - github::{authenticated_agent::AuthenticatedAgent, data::*}, -}; -use graphql_client::{GraphQLQuery, QueryBody, Response}; -use hc_common::{ - chrono::DateTime, - context::Context, - error::{Error, Result}, - hc_error, - serde_json::{from_value as from_json_value, to_value as to_json_value}, -}; +use self::review::ResponseData; +use self::review::ReviewRepositoryPullRequest as RawPull; +use self::review::ReviewRepositoryPullRequestCommitsNodes as RawPullCommit; +use self::review::Variables; +use crate::context::Context; +use crate::data::git::Contributor; +use crate::data::git::RawCommit; +use crate::data::github::authenticated_agent::AuthenticatedAgent; +use crate::data::github::data::*; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use chrono::DateTime; +use graphql_client::GraphQLQuery; +use graphql_client::QueryBody; +use graphql_client::Response; +use serde_json::from_value as from_json_value; +use serde_json::to_value as to_json_value; use std::convert::TryFrom; /// The URL of the GitHub GraphQL API. @@ -24,8 +26,8 @@ const GH_API_V4: &str = "https://api.github.com/graphql"; /// Defines the query being made against the GitHub API. #[derive(GraphQLQuery)] #[graphql( - schema_path = "src/github/gh_schema.graphql", - query_path = "src/github/gh_query.graphql", + schema_path = "src/data/github/gh_schema.graphql", + query_path = "src/data/github/gh_query.graphql", response_derives = "Debug" )] pub struct Review; diff --git a/libs/hc_data/src/github/hidden.rs b/hipcheck/src/data/github/hidden.rs similarity index 85% rename from libs/hc_data/src/github/hidden.rs rename to hipcheck/src/data/github/hidden.rs index 3577f01c..a8de4eeb 100644 --- a/libs/hc_data/src/github/hidden.rs +++ b/hipcheck/src/data/github/hidden.rs @@ -1,4 +1,6 @@ -use std::fmt::{Debug, Formatter, Result as FmtResult}; +use std::fmt::Debug; +use std::fmt::Formatter; +use std::fmt::Result as FmtResult; /// Helper container to ensure a value isn't printed. pub struct Hidden(T); diff --git a/libs/hc_data/src/github/mod.rs b/hipcheck/src/data/github/mod.rs similarity index 74% rename from libs/hc_data/src/github/mod.rs rename to hipcheck/src/data/github/mod.rs index afd113fd..fd83990f 100644 --- a/libs/hc_data/src/github/mod.rs +++ b/hipcheck/src/data/github/mod.rs @@ -7,14 +7,14 @@ mod graphql; mod graphql_pr; mod hidden; -use crate::code_search::search_code_request; -use crate::git::parse::github_diff; -use crate::github::authenticated_agent::AuthenticatedAgent; -use crate::github::data::*; -use crate::github::graphql::get_all_reviews; -use crate::github::graphql_pr::get_all_pr_reviews; -use hc_common::context::Context as _; -use hc_common::{error::Result, log}; +use crate::context::Context as _; +use crate::data::code_search::search_code_request; +use crate::data::git::parse::github_diff; +use crate::data::github::authenticated_agent::AuthenticatedAgent; +use crate::data::github::data::*; +use crate::data::github::graphql::get_all_reviews; +use crate::data::github::graphql_pr::get_all_pr_reviews; +use crate::error::Result; use std::rc::Rc; pub struct GitHub<'a> { @@ -24,12 +24,12 @@ pub struct GitHub<'a> { } impl<'a> GitHub<'a> { - pub fn new(owner: &'a str, repo: &'a str, token: &'a str) -> GitHub<'a> { - GitHub { + pub fn new(owner: &'a str, repo: &'a str, token: &'a str) -> Result> { + Ok(GitHub { owner, repo, - agent: AuthenticatedAgent::new(token), - } + agent: AuthenticatedAgent::new(token)?, + }) } pub fn fuzz_check(&self, repo_uri: Rc) -> Result { @@ -54,13 +54,13 @@ impl<'a> GitHubPr<'a> { repo: &'a str, pull_request: &'a u64, token: &'a str, - ) -> GitHubPr<'a> { - GitHubPr { + ) -> Result> { + Ok(GitHubPr { owner, repo, pull_request, - agent: AuthenticatedAgent::new(token), - } + agent: AuthenticatedAgent::new(token)?, + }) } pub fn get_review_for_single_pr(&self) -> Result { diff --git a/libs/hc_data/src/hash.rs b/hipcheck/src/data/hash.rs similarity index 94% rename from libs/hc_data/src/hash.rs rename to hipcheck/src/data/hash.rs index 0dace2c2..2949a4bd 100644 --- a/libs/hc_data/src/hash.rs +++ b/hipcheck/src/data/hash.rs @@ -24,7 +24,8 @@ macro_rules! hash { mod tests { use crate::hash; use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; + use std::hash::Hash; + use std::hash::Hasher; #[test] fn it_works() { diff --git a/libs/hc_data/src/modules.rs b/hipcheck/src/data/modules.rs similarity index 92% rename from libs/hc_data/src/modules.rs rename to hipcheck/src/data/modules.rs index 252fdbfa..b476e699 100644 --- a/libs/hc_data/src/modules.rs +++ b/hipcheck/src/data/modules.rs @@ -1,13 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::context::Context as _; -use hc_common::{ - command_util::{log_args, DependentProgram}, - error::{Error, Result}, - hc_error, pathbuf, - serde::{self, Deserialize}, - serde_json, -}; +use crate::command_util::log_args; +use crate::command_util::DependentProgram; +use crate::context::Context as _; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::pathbuf; +use serde::Deserialize; use serde_json::Value as JsonValue; use std::collections::HashMap; use std::convert::AsRef; @@ -15,7 +15,8 @@ use std::ffi::OsStr; use std::fs; use std::iter::IntoIterator; use std::ops::Not as _; -use std::path::{Path, PathBuf}; +use std::path::Path; +use std::path::PathBuf; use std::process::Command; pub fn generate_module_model(repo_dir: &Path, module_deps: &Path) -> Result> { @@ -54,7 +55,6 @@ fn detect_npm_package_root(pkg_file: &Path) -> Result { } #[derive(Debug, Deserialize)] -#[serde(crate = "self::serde")] pub struct RawModule { pub file: String, pub entry: bool, diff --git a/libs/hc_data/src/npm.rs b/hipcheck/src/data/npm.rs similarity index 93% rename from libs/hc_data/src/npm.rs rename to hipcheck/src/data/npm.rs index b2f93b7a..04674e43 100644 --- a/libs/hc_data/src/npm.rs +++ b/hipcheck/src/data/npm.rs @@ -1,22 +1,25 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::{ - command_util::{log_args, DependentProgram}, - context::Context, - error::Result, - filesystem as file, hc_error, log, pathbuf, - serde::{self, Deserialize}, - which, -}; +use crate::command_util::log_args; +use crate::command_util::DependentProgram; +use crate::context::Context; +use crate::error::Result; +use crate::filesystem as file; +use crate::hc_error; +use crate::pathbuf; +use serde::Deserialize; +use std::collections::HashMap; use std::convert::AsRef; use std::ffi::OsStr; use std::iter::IntoIterator; -use std::path::{Path, PathBuf}; -use std::process::{Child, Command, Stdio}; -use std::{collections::HashMap, ops::Not}; +use std::ops::Not; +use std::path::Path; +use std::path::PathBuf; +use std::process::Child; +use std::process::Command; +use std::process::Stdio; #[derive(Debug, Clone, PartialEq, Eq, Deserialize)] -#[serde(crate = "self::serde")] pub struct PackageFile { pub main: String, } @@ -111,7 +114,6 @@ fn generate_package_lock_file(package_dir: &Path, version: String) -> Result<()> } #[derive(Deserialize)] -#[serde(crate = "self::serde")] struct PackageLockFile { dependencies: Option>>, } @@ -146,7 +148,6 @@ fn resolve_deps(name: &str, detail: &Dependency) -> Vec { } #[derive(Deserialize)] -#[serde(crate = "self::serde")] struct Dependency { dependencies: Option>>, } @@ -255,7 +256,7 @@ impl NpmCommand { #[cfg(test)] mod test { use super::*; - use hc_common::command_util::DependentProgram; + use crate::command_util::DependentProgram; #[test] #[ignore = "can't guarantee availability of NPM"] diff --git a/libs/hc_data/src/query/code_quality.rs b/hipcheck/src/data/query/code_quality.rs similarity index 76% rename from libs/hc_data/src/query/code_quality.rs rename to hipcheck/src/data/query/code_quality.rs index ed18a5eb..b9e7c1e1 100644 --- a/libs/hc_data/src/query/code_quality.rs +++ b/hipcheck/src/data/query/code_quality.rs @@ -4,10 +4,11 @@ use std::rc::Rc; -use crate::code_quality::{get_eslint_report, CodeQualityReport}; -use crate::source::SourceQuery; -use hc_common::{error::Result, salsa}; -use hc_version::VersionQuery; +use crate::data::code_quality::get_eslint_report; +use crate::data::code_quality::CodeQualityReport; +use crate::data::source::SourceQuery; +use crate::error::Result; +use crate::version::VersionQuery; /// Queries about code quality #[salsa::query_group(CodeQualityProviderStorage)] diff --git a/libs/hc_data/src/query/dependencies.rs b/hipcheck/src/data/query/dependencies.rs similarity index 84% rename from libs/hc_data/src/query/dependencies.rs rename to hipcheck/src/data/query/dependencies.rs index bbd3f12d..bb3f102d 100644 --- a/libs/hc_data/src/query/dependencies.rs +++ b/hipcheck/src/data/query/dependencies.rs @@ -2,11 +2,12 @@ //! Query group for dependencies information. -use crate::npm::{get_package_file, PackageFile}; -use crate::source::SourceQuery; -use crate::Dependencies; -use hc_common::{error::Result, salsa}; -use hc_version::VersionQuery; +use crate::data::npm::get_package_file; +use crate::data::npm::PackageFile; +use crate::data::source::SourceQuery; +use crate::data::Dependencies; +use crate::error::Result; +use crate::version::VersionQuery; use std::rc::Rc; /// Queries about dependencies diff --git a/libs/hc_data/src/query/fuzz.rs b/hipcheck/src/data/query/fuzz.rs similarity index 86% rename from libs/hc_data/src/query/fuzz.rs rename to hipcheck/src/data/query/fuzz.rs index e388b3bb..4c1898b7 100644 --- a/libs/hc_data/src/query/fuzz.rs +++ b/hipcheck/src/data/query/fuzz.rs @@ -3,12 +3,11 @@ //! Query group for fuzzing checks. use super::github::GitHubProvider; -use crate::{get_fuzz_check, Fuzz}; -use hc_common::{ - error::{Error, Result}, - log, salsa, -}; -use hc_config::ConfigSource; +use crate::config::ConfigSource; +use crate::data::get_fuzz_check; +use crate::data::Fuzz; +use crate::error::Error; +use crate::error::Result; /// A query that provides a fuzz check #[salsa::query_group(FuzzProviderStorage)] diff --git a/libs/hc_data/src/query/github.rs b/hipcheck/src/data/query/github.rs similarity index 94% rename from libs/hc_data/src/query/github.rs rename to hipcheck/src/data/query/github.rs index 65e8f836..fcb93d63 100644 --- a/libs/hc_data/src/query/github.rs +++ b/hipcheck/src/data/query/github.rs @@ -2,11 +2,10 @@ //! Query group for data pertaining to a remote GitHub source. -use crate::source::{Remote, SourceQuery}; -use hc_common::{ - error::{Error, Result}, - salsa, -}; +use crate::data::source::Remote; +use crate::data::source::SourceQuery; +use crate::error::Error; +use crate::error::Result; use std::rc::Rc; /// Queries about a remote GitHub source diff --git a/hipcheck/src/data/query/mod.rs b/hipcheck/src/data/query/mod.rs new file mode 100644 index 00000000..0e5af7df --- /dev/null +++ b/hipcheck/src/data/query/mod.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! A collection of Salsa query groups for accessing the data used in +//! Hipcheck's analyses. + +mod code_quality; +mod dependencies; +mod fuzz; +mod github; +mod module; +mod pr_review; + +#[allow(unused)] +pub use code_quality::CodeQualityProvider; +pub use code_quality::CodeQualityProviderStorage; +pub use dependencies::DependenciesProvider; +pub use dependencies::DependenciesProviderStorage; +pub use fuzz::FuzzProvider; +pub use fuzz::FuzzProviderStorage; +pub use github::GitHubProvider; +pub use github::GitHubProviderStorage; +pub use module::ModuleCommitMap; +pub use module::ModuleProvider; +pub use module::ModuleProviderStorage; +pub use pr_review::PullRequestReviewProvider; +pub use pr_review::PullRequestReviewProviderStorage; diff --git a/libs/hc_data/src/query/module.rs b/hipcheck/src/data/query/module.rs similarity index 89% rename from libs/hc_data/src/query/module.rs rename to hipcheck/src/data/query/module.rs index ddf941dd..1d381baf 100644 --- a/libs/hc_data/src/query/module.rs +++ b/hipcheck/src/data/query/module.rs @@ -2,18 +2,18 @@ //! Query group for module information. -use std::{path::PathBuf, rc::Rc}; - -use crate::{ - associate_modules_and_commits, - git::{Commit, GitProvider}, - Module, ModuleGraph, -}; - -use hc_common::{ - error::{Error, Result}, - pathbuf, salsa, -}; +use std::path::PathBuf; +use std::rc::Rc; + +use crate::data::associate_modules_and_commits; +use crate::data::git::Commit; +use crate::data::git::GitProvider; +use crate::data::Module; +use crate::data::ModuleGraph; + +use crate::error::Error; +use crate::error::Result; +use crate::pathbuf; /// A module and an associated commit pub type ModuleCommitMap = Rc, Rc)>>; diff --git a/libs/hc_data/src/query/pr_review.rs b/hipcheck/src/data/query/pr_review.rs similarity index 90% rename from libs/hc_data/src/query/pr_review.rs rename to hipcheck/src/data/query/pr_review.rs index dee99579..c8f18935 100644 --- a/libs/hc_data/src/query/pr_review.rs +++ b/hipcheck/src/data/query/pr_review.rs @@ -3,17 +3,19 @@ //! Query group for GitHub pull request reviews. use super::github::GitHubProvider; -use crate::{ - get_pull_request_reviews_from_github, get_single_pull_request_review_from_github, - git::{Commit, CommitContributorView, CommitDiff, Contributor, ContributorView}, - PullRequest, SinglePullRequest, -}; -use hc_common::{ - context::Context, - error::{Error, Result}, - salsa, -}; -use hc_config::ConfigSource; +use crate::config::ConfigSource; +use crate::context::Context; +use crate::data::get_pull_request_reviews_from_github; +use crate::data::get_single_pull_request_review_from_github; +use crate::data::git::Commit; +use crate::data::git::CommitContributorView; +use crate::data::git::CommitDiff; +use crate::data::git::Contributor; +use crate::data::git::ContributorView; +use crate::data::PullRequest; +use crate::data::SinglePullRequest; +use crate::error::Error; +use crate::error::Result; use std::rc::Rc; /// A query that provides GitHub pull request reviews diff --git a/libs/hc_data/src/source/mod.rs b/hipcheck/src/data/source/mod.rs similarity index 98% rename from libs/hc_data/src/source/mod.rs rename to hipcheck/src/data/source/mod.rs index 907ef2ce..33dee983 100644 --- a/libs/hc_data/src/source/mod.rs +++ b/hipcheck/src/data/source/mod.rs @@ -4,19 +4,23 @@ mod query; pub use query::*; -use crate::git_command::GitCommand; -use hc_common::log::{self, debug}; -use hc_common::{ - context::Context, - error::{Error, Result}, - hc_error, pathbuf, - url::Url, -}; -use hc_shell::Phase; +use crate::context::Context; +use crate::data::git_command::GitCommand; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::pathbuf; +use crate::shell::Phase; +use log::debug; use std::ffi::OsStr; -use std::fmt::{self, Debug, Display, Formatter}; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; use std::fs; -use std::path::{Path, PathBuf}; +use std::path::Path; +use std::path::PathBuf; +use url::Url; // Right now our only subject of analysis is a repository, represented by the // `Source` type. It may optionally include a `Remote` component, in which diff --git a/libs/hc_data/src/source/query.rs b/hipcheck/src/data/source/query.rs similarity index 95% rename from libs/hc_data/src/source/query.rs rename to hipcheck/src/data/source/query.rs index ab2dc86f..6ae6c186 100644 --- a/libs/hc_data/src/source/query.rs +++ b/hipcheck/src/data/source/query.rs @@ -2,11 +2,10 @@ //! A query group for accessing Git repository data. -use crate::{ - hash, - source::{Remote, Source}, -}; -use hc_common::{pathbuf, salsa}; +use crate::data::source::Remote; +use crate::data::source::Source; +use crate::hash; +use crate::pathbuf; use std::path::PathBuf; use std::rc::Rc; @@ -69,7 +68,7 @@ fn url(db: &dyn SourceQuery) -> Option> { // Computes the appropriate path based on the remote or local info fn storage_path(db: &dyn SourceQuery) -> Rc { - use crate::source::Remote::*; + use crate::data::source::Remote::*; let path_buf = match db.remote() { Some(remote) => match remote.as_ref() { diff --git a/libs/hc_common/src/error.rs b/hipcheck/src/error.rs similarity index 98% rename from libs/hc_common/src/error.rs rename to hipcheck/src/error.rs index 1212e2e5..31bc1432 100644 --- a/libs/hc_common/src/error.rs +++ b/hipcheck/src/error.rs @@ -10,10 +10,11 @@ //! which error out aren't retried, as it always compares as equal to //! any other error. -use log; use std::borrow::Cow; use std::error::Error as StdError; -use std::fmt::{self, Debug, Display}; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Display; use std::rc::Rc; pub type Result = std::result::Result; @@ -75,11 +76,13 @@ impl Error { } } + #[allow(unused)] /// Get the next error in the chain. pub fn source(&self) -> Option<&(dyn StdError + 'static)> { self.head.source() } + #[allow(unused)] /// Get the root error of the chain. pub fn root_cause(&self) -> Error { let mut current = &self.head; diff --git a/libs/hc_common/src/filesystem.rs b/hipcheck/src/filesystem.rs similarity index 95% rename from libs/hc_common/src/filesystem.rs rename to hipcheck/src/filesystem.rs index 75860556..0904ddbf 100644 --- a/libs/hc_common/src/filesystem.rs +++ b/hipcheck/src/filesystem.rs @@ -1,13 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 use crate::context::Context as _; -use crate::{ - error::Result, - hc_error, - serde::{de::DeserializeOwned, Serialize}, - serde_json, -}; -use std::fs::{self, File}; +use crate::error::Result; +use crate::hc_error; +use serde::de::DeserializeOwned; +use serde::Serialize; +use std::fs; +use std::fs::File; use std::ops::Not; use std::path::Path; @@ -57,6 +56,7 @@ pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> } /// Write JSON to a file. +#[allow(unused)] pub fn write_json, T: ?Sized + Serialize>(path: P, value: &T) -> Result<()> { // The non-generic inner function (NGIF) trick is useless here, since T would still be generic, // so instead we do this conversion up-front to avoid borrowing issues with the `with_context` diff --git a/hipcheck/src/main.rs b/hipcheck/src/main.rs index 5999e85a..13491a0c 100644 --- a/hipcheck/src/main.rs +++ b/hipcheck/src/main.rs @@ -1,20 +1,57 @@ // SPDX-License-Identifier: Apache-2.0 -use clap::{Arg, ArgAction, Command}; -use env_logger::{Builder, Env}; -use hc_analysis::session::{Check, CheckType}; -use hc_common::{ - context::Context, error::Result, hc_error, schemars::schema_for, serde_json, CheckKind, -}; -use hc_core::{ - print_error, resolve_config, resolve_data, resolve_home, run, version, AnyReport, ColorChoice, - Format, Outcome, Output, PrReport, Report, Verbosity, -}; +mod analysis; +mod command_util; +mod config; +mod context; +mod data; +mod error; +mod filesystem; +mod pathbuf; +mod report; +mod shell; +mod test_util; +#[cfg(test)] +mod tests; +mod try_any; +mod try_filter; +mod version; + +use crate::analysis::report_builder::build_pr_report; +use crate::analysis::report_builder::build_report; +use crate::analysis::report_builder::AnyReport; +use crate::analysis::report_builder::Format; +use crate::analysis::report_builder::PrReport; +use crate::analysis::report_builder::Report; +use crate::analysis::score::score_pr_results; +use crate::analysis::score::score_results; +use crate::analysis::session::resolve_config; +use crate::analysis::session::resolve_data; +use crate::analysis::session::resolve_home; +use crate::analysis::session::Check; +use crate::analysis::session::CheckType; +use crate::analysis::session::Session; +use crate::context::Context as _; +use crate::error::Error; +use crate::error::Result; +use crate::shell::ColorChoice; +use crate::shell::Output; +use crate::shell::Shell; +use crate::shell::Verbosity; +use clap::Arg; +use clap::ArgAction; +use clap::Command; +use env_logger::Builder; +use env_logger::Env; +use schemars::schema_for; +use std::env; use std::ffi::OsString; +use std::path::Path; use std::path::PathBuf; use std::process::exit; use std::str::FromStr; -use std::{env, path::Path}; +use try_any::TryAny; +use try_filter::TryFilter; /// Entry point for Hipcheck. /// @@ -726,3 +763,233 @@ fn print_missing() -> ! { let exit_code = Outcome::Ok.exit_code(); exit(exit_code) } + +/// An `f64` that is never `NaN`. +type F64 = ordered_float::NotNan; + +// Global variables for toml files per issue 157 config updates +const LANGS_FILE: &str = "Langs.toml"; +const BINARY_CONFIG_FILE: &str = "Binary.toml"; +const TYPO_FILE: &str = "Typos.toml"; +const ORGS_FILE: &str = "Orgs.toml"; +const HIPCHECK_TOML_FILE: &str = "Hipcheck.toml"; + +// Constants for exiting with error codes. +/// Indicates the program failed. +const EXIT_FAILURE: i32 = 1; + +#[allow(unused)] +/// Indicates the program succeeded. +const EXIT_SUCCESS: i32 = 0; + +//used in hc_session::pm and main.rs, global variables for hc check CheckKindHere node-ipc@9.2.1 +enum CheckKind { + Repo, + Request, + Patch, + Maven, + Npm, + Pypi, + Spdx, +} + +impl CheckKind { + const fn name(&self) -> &'static str { + match self { + CheckKind::Repo => "repo", + CheckKind::Request => "request", + CheckKind::Patch => "patch", + CheckKind::Maven => "maven", + CheckKind::Npm => "npm", + CheckKind::Pypi => "pypi", + CheckKind::Spdx => "spdx", + } + } +} + +/// Run Hipcheck. +/// +/// Parses arguments, sets up shell output, and then runs the main logic. +#[allow(clippy::too_many_arguments)] +fn run( + output: Output, + error_output: Output, + verbosity: Verbosity, + check: Check, + config_path: Option, + data_path: Option, + home_dir: Option, + format: Format, + raw_version: &str, +) -> (Shell, Result) { + // Setup wrapper for shell output. + let shell = Shell::new(output, error_output, verbosity); + + // Run and print / report errors. + run_with_shell( + shell, + check, + config_path, + data_path, + home_dir, + format, + raw_version, + ) +} + +// This is for testing purposes. +/// Now that we're fully-initialized, run Hipcheck's analyses. +#[allow(clippy::too_many_arguments)] +#[doc(hidden)] +fn run_with_shell( + shell: Shell, + check: Check, + config_path: Option, + data_path: Option, + home_dir: Option, + format: Format, + raw_version: &str, +) -> (Shell, Result) { + // Initialize the session. + let session = match Session::new( + shell, + &check, + &check.check_value, + config_path, + data_path, + home_dir, + format, + raw_version, + ) { + Ok(session) => session, + Err((shell, err)) => return (shell, Err(err)), + }; + + match check.check_type { + CheckType::RepoSource | CheckType::SpdxDocument => { + // Run analyses against a repo and score the results (score calls analyses that call metrics). + let mut phase = match session.shell.phase("analyzing and scoring results") { + Ok(phase) => phase, + Err(err) => return (session.end(), Err(err)), + }; + + let scoring = match score_results(&mut phase, &session) { + Ok(scoring) => scoring, + _ => { + return ( + session.end(), + Err(Error::msg("Trouble scoring and analyzing results")), + ) + } + }; + + match phase.finish() { + Ok(()) => {} + Err(err) => return (session.end(), Err(err)), + }; + + // Build the final report. + let report = + match build_report(&session, &scoring).context("failed to build final report") { + Ok(report) => report, + Err(err) => return (session.end(), Err(err)), + }; + + (session.end(), Ok(AnyReport::Report(report))) + } + CheckType::PackageVersion => { + // Run analyses against a repo and score the results (score calls analyses that call metrics). + let mut phase = match session.shell.phase("analyzing and scoring results") { + Ok(phase) => phase, + Err(err) => return (session.end(), Err(err)), + }; + + let scoring = match score_results(&mut phase, &session) { + Ok(scoring) => scoring, + _ => { + return ( + session.end(), + Err(Error::msg("Trouble scoring and analyzing results")), + ) + } + }; + + match phase.finish() { + Ok(()) => {} + Err(err) => return (session.end(), Err(err)), + }; + + // Build the final report. + let report = + match build_report(&session, &scoring).context("failed to build final report") { + Ok(report) => report, + Err(err) => return (session.end(), Err(err)), + }; + + (session.end(), Ok(AnyReport::Report(report))) + } + CheckType::PrUri => { + // Run analyses against a pull request and score the results (score calls analyses that call metrics). + let mut phase = match session.shell.phase("scoring and analyzing results") { + Ok(phase) => phase, + Err(err) => return (session.end(), Err(err)), + }; + + let score = match score_pr_results(&mut phase, &session) { + Ok(score) => score, + _ => { + return ( + session.end(), + Err(Error::msg("Trouble scoring and analyzing results")), + ) + } + }; + + match phase.finish() { + Ok(()) => {} + Err(err) => return (session.end(), Err(err)), + }; + + // Build the final report. + let pr_report = + match build_pr_report(&session, &score).context("failed to build final report") { + Ok(pr_report) => pr_report, + Err(err) => return (session.end(), Err(err)), + }; + + (session.end(), Ok(AnyReport::PrReport(pr_report))) + } + _ => ( + session.end(), + Err(Error::msg( + "Hipcheck attempted to analyze an unsupported type", + )), + ), + } +} + +/// Print errors which occur before the `Shell` type can be setup. +fn print_error(err: &Error) { + let mut chain = err.chain(); + + // PANIC: First error is guaranteed to be present. + eprintln!("error: {}", chain.next().unwrap()); + + for err in chain { + eprintln!(" {}", err); + } +} + +enum Outcome { + Ok, + Err, +} + +impl Outcome { + fn exit_code(&self) -> i32 { + match self { + Outcome::Ok => 0, + Outcome::Err => 1, + } + } +} diff --git a/libs/hc_common/src/pathbuf.rs b/hipcheck/src/pathbuf.rs similarity index 100% rename from libs/hc_common/src/pathbuf.rs rename to hipcheck/src/pathbuf.rs diff --git a/libs/hc_report/src/lib.rs b/hipcheck/src/report.rs similarity index 94% rename from libs/hc_report/src/lib.rs rename to hipcheck/src/report.rs index 897cd82a..ebd3cebf 100644 --- a/libs/hc_report/src/lib.rs +++ b/hipcheck/src/report.rs @@ -9,21 +9,21 @@ // The report serves double-duty, because it's both the thing used to print user-friendly // results on the CLI, and the type that's serialized out to JSON for machine-friendly output. -mod query; - -pub use query::*; - -use hc_common::{ - chrono::prelude::*, - error::{Error, Result}, - hc_error, log, - schemars::{self, JsonSchema}, - serde::{self, Serialize, Serializer}, -}; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::version::VersionQuery; +use chrono::prelude::*; use paste::paste; +use schemars::JsonSchema; +use serde::Serialize; +use serde::Serializer; use std::default::Default; -use std::fmt::{self, Display, Formatter}; -use std::hash::{Hash, Hasher}; +use std::fmt; +use std::fmt::Display; +use std::fmt::Formatter; +use std::hash::Hash; +use std::hash::Hasher; use std::iter::Iterator; use std::ops::Not as _; use std::rc::Rc; @@ -57,8 +57,7 @@ pub enum AnyReport { /// The report output to the user. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Report { /// The name of the repository being analyzed. pub repo_name: Rc, @@ -129,8 +128,8 @@ impl Report { /// An analysis which passed. #[derive(Debug, Serialize, JsonSchema)] -#[serde(transparent, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(transparent)] +#[schemars(crate = "schemars")] pub struct PassingAnalysis( /// The analysis which passed. Analysis, @@ -144,8 +143,7 @@ impl PassingAnalysis { /// An analysis which failed, including potential specific concerns. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct FailingAnalysis { /// The analysis. #[serde(flatten)] @@ -224,8 +222,7 @@ fn no_concerns(concerns: &[Concern]) -> bool { /// An analysis that did _not_ succeed. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct ErroredAnalysis { analysis: AnalysisIdent, error: ErrorReport, @@ -262,8 +259,7 @@ fn try_add_msg(msgs: &mut Vec, error_report: &Option>) /// The name of the analyses. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub enum AnalysisIdent { Activity, Affiliation, @@ -298,8 +294,7 @@ impl Display for AnalysisIdent { /// A simple, serializable version of `Error`. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct ErrorReport { msg: String, #[serde(skip_serializing_if = "source_is_none")] @@ -353,8 +348,8 @@ impl From<&(dyn std::error::Error + 'static)> for ErrorReport { /// An analysis, with score and threshold. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(tag = "analysis", crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(tag = "analysis")] +#[schemars(crate = "schemars")] pub enum Analysis { /// Activity analysis. Activity { @@ -661,8 +656,8 @@ impl Analysis { /// only used where additional detail / evidence should be provided beyond the /// top-level information. #[derive(Clone, Debug, Serialize, JsonSchema)] -#[serde(untagged, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(untagged)] +#[schemars(crate = "schemars")] pub enum Concern { /// Commits with affiliated contributor(s) Affiliation { contributor: String, count: i64 }, @@ -794,8 +789,7 @@ impl Eq for Concern {} /// The pull request report output to the user. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct PrReport { /// The URI of the pull request being analyzed. pub pr_uri: Rc, @@ -866,8 +860,8 @@ impl PrReport { /// An analysis which passed. #[derive(Debug, Serialize, JsonSchema)] -#[serde(transparent, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(transparent)] +#[schemars(crate = "schemars")] pub struct PrPassingAnalysis( /// The analysis which passed. PrAnalysis, @@ -881,8 +875,7 @@ impl PrPassingAnalysis { /// An analysis which failed, including potential specific concerns. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct PrFailingAnalysis { /// The analysis. #[serde(flatten)] @@ -945,8 +938,7 @@ fn pr_no_concerns(concerns: &[PrConcern]) -> bool { /// An analysis that did _not_ succeed. #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct PrErroredAnalysis { analysis: PrAnalysisIdent, error: ErrorReport, @@ -982,9 +974,9 @@ fn pr_try_add_msg(msgs: &mut Vec, error_report: &Option } /// The name of the analyses. +#[allow(clippy::enum_variant_names)] #[derive(Debug, Serialize, JsonSchema)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub enum PrAnalysisIdent { PrAffiliation, PrContributorTrust, @@ -1006,9 +998,10 @@ impl Display for PrAnalysisIdent { } /// An analysis, with score and threshold. +#[allow(clippy::enum_variant_names)] #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(tag = "analysis", crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(tag = "analysis")] +#[schemars(crate = "schemars")] pub enum PrAnalysis { /// Pull request affiliation analysis. PrAffiliation { @@ -1154,8 +1147,8 @@ impl PrAnalysis { /// only used where additional detail / evidence should be provided beyond the /// top-level information. #[derive(Clone, Debug, Serialize, JsonSchema)] -#[serde(untagged, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(untagged)] +#[schemars(crate = "schemars")] pub enum PrConcern { /// Commits with affiliated contributor(s) PrAffiliation { contributor: String, count: i64 }, @@ -1225,8 +1218,7 @@ impl<'opt, T, E> From<&'opt Option>> for AnalysisResult<&'opt T, /// Value and threshold for counting-based analyses. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Count { value: u64, threshold: u64, @@ -1234,16 +1226,14 @@ pub struct Count { /// Value for binary-based analyses. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Exists { value: bool, } /// Value and threshold for percentage-based analyses. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Percent { value: f64, threshold: f64, @@ -1252,8 +1242,7 @@ pub struct Percent { /// A final recommendation of whether to use or investigate a piece of software, /// including the risk threshold associated with that decision. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Recommendation { pub kind: RecommendationKind, risk_score: RiskScore, @@ -1282,8 +1271,7 @@ impl Recommendation { /// The kind of recommendation being made. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub enum RecommendationKind { Pass, Investigate, @@ -1301,19 +1289,19 @@ impl RecommendationKind { /// The overall final risk score for a repo. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(transparent, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(transparent)] +#[schemars(crate = "schemars")] pub struct RiskScore(pub f64); /// The risk threshold configured for the Hipcheck session. #[derive(Debug, Serialize, JsonSchema, Clone, Copy)] -#[serde(transparent, crate = "self::serde")] -#[schemars(crate = "self::schemars")] +#[serde(transparent)] +#[schemars(crate = "schemars")] pub struct RiskThreshold(pub f64); /// A serializable and printable wrapper around a datetime with the local timezone. #[derive(Debug, JsonSchema)] -#[schemars(crate = "self::schemars")] +#[schemars(crate = "schemars")] pub struct Timestamp(DateTime); impl From> for Timestamp { @@ -1343,3 +1331,15 @@ impl Serialize for Timestamp { serializer.serialize_str(&self.0.to_rfc3339()) } } + +/// Queries for how Hipcheck reports session results +#[salsa::query_group(ReportParamsStorage)] +pub trait ReportParams: VersionQuery { + /// Returns the time the current Hipcheck session started + #[salsa::input] + fn started_at(&self) -> DateTime; + + /// Returns the format of the final report + #[salsa::input] + fn format(&self) -> Format; +} diff --git a/libs/hc_shell/src/lib.rs b/hipcheck/src/shell.rs similarity index 98% rename from libs/hc_shell/src/lib.rs rename to hipcheck/src/shell.rs index 04e7863b..a748673f 100644 --- a/libs/hc_shell/src/lib.rs +++ b/hipcheck/src/shell.rs @@ -30,7 +30,7 @@ * These methods take a `&mut Output`, a [`Report`] or [`PrReport`], and a [`Format`]. * * At any point, errors may also be printed using [`Shell::error`], which takes an - * [`&Error`][hc_common::error:Error] and a [`Format`]. + * [`&Error`][crate::error:Error] and a [`Format`]. * * ## Why the shell interface? * @@ -84,22 +84,31 @@ #![deny(missing_docs)] -use hc_common::{ - error::{Error, Result}, - hc_error, log, serde_json, -}; -use hc_report::{Format, PrReport, RecommendationKind, Report}; +use crate::error::Error; +use crate::error::Result; +use crate::hc_error; +use crate::report::Format; +use crate::report::PrReport; +use crate::report::RecommendationKind; +use crate::report::Report; use std::cell::Cell; -use std::fmt::{self, Debug, Formatter}; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Formatter; use std::io::stderr; use std::io::stdout; use std::io::IsTerminal as _; use std::io::Write; use std::ops::Not as _; use std::str::FromStr; -use std::time::{Duration, Instant}; +use std::time::Duration; +use std::time::Instant; +use termcolor::Color; use termcolor::Color::*; -use termcolor::{self, Color, ColorSpec, NoColor, StandardStream, WriteColor}; +use termcolor::ColorSpec; +use termcolor::NoColor; +use termcolor::StandardStream; +use termcolor::WriteColor; /// The interface used throughout Hipcheck to print things out to the user. pub struct Shell { @@ -154,6 +163,7 @@ impl Shell { /// Print the prelude header for Hipcheck's run. pub fn prelude(source: &str) + #[allow(unused)] /// Print a warning to the user. pub fn warn(message: &str) @@ -174,6 +184,7 @@ impl Shell { /// Print the in-progress line for a phase. fn status(msg: &str) + #[allow(unused)] /// Print a warning during a phase. fn warn_in_phase(msg: &str) @@ -766,6 +777,7 @@ impl<'sec, 'desc> Phase<'sec, 'desc> { }) } + #[allow(unused)] /// Warn the user. pub fn warn(&mut self, msg: &str) -> Result<()> { self.shell.warn_in_phase(msg) @@ -820,6 +832,7 @@ impl Output { } } + #[allow(unused)] /// Create a new Output wrapping an arbitrary Write. pub fn from_writer(write: impl Write + 'static) -> Output { Output { @@ -984,11 +997,13 @@ pub enum Verbosity { } impl Verbosity { + #[allow(unused)] /// Check if verbosity is quiet. pub fn is_quiet(&self) -> bool { matches!(self, Verbosity::Quiet) } + #[allow(unused)] /// Check if verbosity is normal. pub fn is_normal(&self) -> bool { matches!(self, Verbosity::Normal) @@ -1522,8 +1537,11 @@ enum TtyWidth { #[cfg(unix)] mod imp { use super::TtyWidth; - use hc_common::{error::Result, log}; - use libc::{ioctl, winsize, STDOUT_FILENO, TIOCGWINSZ}; + use crate::error::Result; + use libc::ioctl; + use libc::winsize; + use libc::STDOUT_FILENO; + use libc::TIOCGWINSZ; use std::mem::zeroed; use termcolor::WriteColor; @@ -1560,9 +1578,10 @@ mod imp { #[cfg(windows)] mod imp { use super::TtyWidth; - use hc_common::{error::Result, log}; + use crate::error::Result; + use std::cmp; use std::mem::zeroed; - use std::{cmp, ptr}; + use std::ptr; use termcolor::WriteColor; use winapi::um::fileapi::*; use winapi::um::handleapi::*; diff --git a/libs/hc_common/src/test_util.rs b/hipcheck/src/test_util.rs similarity index 89% rename from libs/hc_common/src/test_util.rs rename to hipcheck/src/test_util.rs index fe6140ea..0638fe09 100644 --- a/libs/hc_common/src/test_util.rs +++ b/hipcheck/src/test_util.rs @@ -2,11 +2,14 @@ //! Utilities for unit testing. -use std::env::{self, VarError}; -use std::panic::{self, RefUnwindSafe, UnwindSafe}; +use std::env; +use std::env::VarError; +use std::panic; +use std::panic::RefUnwindSafe; +use std::panic::UnwindSafe; use std::sync::Mutex; -use crate::lazy_static::lazy_static; +use lazy_static::lazy_static; lazy_static! { static ref SERIAL_TEST: Mutex<()> = Default::default(); @@ -17,6 +20,7 @@ lazy_static! { /// before unwinding the panic. /// /// Credit: Fabian Braun at https://stackoverflow.com/a/67433684 +#[allow(unused)] pub fn with_env_vars(kvs: Vec<(&str, Option<&str>)>, closure: F) where F: Fn() + UnwindSafe + RefUnwindSafe, diff --git a/libs/hc_common/src/tests.rs b/hipcheck/src/tests.rs similarity index 98% rename from libs/hc_common/src/tests.rs rename to hipcheck/src/tests.rs index f87cce31..44828965 100644 --- a/libs/hc_common/src/tests.rs +++ b/hipcheck/src/tests.rs @@ -4,7 +4,8 @@ use crate::error::Error; use crate::hc_error; -use std::io::{self, ErrorKind}; +use std::io; +use std::io::ErrorKind; // Message source root error with no context #[test] diff --git a/libs/hc_common/src/try_any.rs b/hipcheck/src/try_any.rs similarity index 100% rename from libs/hc_common/src/try_any.rs rename to hipcheck/src/try_any.rs diff --git a/libs/hc_common/src/try_filter.rs b/hipcheck/src/try_filter.rs similarity index 100% rename from libs/hc_common/src/try_filter.rs rename to hipcheck/src/try_filter.rs diff --git a/libs/hc_version/src/lib.rs b/hipcheck/src/version.rs similarity index 51% rename from libs/hc_version/src/lib.rs rename to hipcheck/src/version.rs index 3141c337..7d8f357e 100644 --- a/libs/hc_version/src/lib.rs +++ b/hipcheck/src/version.rs @@ -1,15 +1,13 @@ // SPDX-License-Identifier: Apache-2.0 -mod query; - -pub use query::*; - -use hc_common::{context::Context, error::Result, log, semver::Version}; +use crate::context::Context; +use crate::error::Result; +use semver::Version; use std::ops::Not as _; +use std::rc::Rc; +/// Query the environment to identify the proper version string. pub fn get_version(raw_version: &str) -> Result { - // Queries the environment to identify the proper version string. - // // Basic algorithm: // 1. Check the version number in `Cargo.toml`. // 2. If it's an "alpha" release, then in addition to printing @@ -31,3 +29,23 @@ pub fn get_version(raw_version: &str) -> Result { Ok(raw_version.to_string()) } + +/// Queries for current versions of Hipcheck and tool dependencies +#[salsa::query_group(VersionQueryStorage)] +pub trait VersionQuery: salsa::Database { + /// Returns the current Hipcheck version + #[salsa::input] + fn hc_version(&self) -> Rc; + + /// Returns the version of npm currently running on user's machine + #[salsa::input] + fn npm_version(&self) -> Rc; + + /// Returns the version of eslint currently running on user's machine + #[salsa::input] + fn eslint_version(&self) -> Rc; + + /// Returns the version of git currently running on user's machine + #[salsa::input] + fn git_version(&self) -> Rc; +} diff --git a/libs/hc_analysis/Cargo.toml b/libs/hc_analysis/Cargo.toml deleted file mode 100644 index 84c2af06..00000000 --- a/libs/hc_analysis/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "hc_analysis" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -content_inspector = "0.2.4" -dirs = "5.0.1" -dotenv = "0.15.0" -curl = "0.4.38" -glob = "0.3.0" -hc_common = { path = "../hc_common" } -hc_config = { path = "../hc_config" } -hc_data = { path = "../hc_data" } -hc_report = { path = "../hc_report" } -hc_serde = { path = "../hc_serde" } -hc_shell = { path = "../hc_shell" } -hc_version = { path = "../hc_version" } -maplit = "1.0.2" -petgraph = { version = "0.6.0" } -serde_derive = "1.0.137" -spdx-rs = "0.5.0" -toml = "0.8.12" -unicode-normalization = "0.1.19" -unicode-segmentation = "1.9.0" -ureq = { version = "2.9.7", features = ["json"] } -walkdir = "2" -xml-rs = "0.8" - -[dev_dependencies] -tempfile = "3.10.1" \ No newline at end of file diff --git a/libs/hc_analysis/src/lib.rs b/libs/hc_analysis/src/lib.rs deleted file mode 100644 index bb575653..00000000 --- a/libs/hc_analysis/src/lib.rs +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pub mod analysis; -pub mod metric; -pub mod report_builder; -pub mod score; -pub mod session; - -pub use analysis::{AnalysisProvider, AnalysisProviderStorage}; -pub use metric::{MetricProvider, MetricProviderStorage}; -pub use score::{ScoringProvider, ScoringProviderStorage}; diff --git a/libs/hc_common/Cargo.toml b/libs/hc_common/Cargo.toml deleted file mode 100644 index 8024994c..00000000 --- a/libs/hc_common/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "hc_common" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -chrono = { version = "0.4.19", features = ["serde"] } -hc_serde = { path = "../hc_serde" } -lazy_static = "1.4.0" -log = "0.4.16" -once_cell = "1.10.0" -ordered-float = { version = "4.2.0", features = ["serde"] } -regex = "1.5.5" -salsa = "0.16.1" -schemars = { version = "0.8.17", default-features = false, features = ["derive", "preserve_order", "chrono" ] } -semver = "1.0.9" -serde_json = "1.0.80" -toml = "0.8.12" -url = "2.2.2" -which = { version = "6.0.1", default-features = false } \ No newline at end of file diff --git a/libs/hc_common/src/lib.rs b/libs/hc_common/src/lib.rs deleted file mode 100644 index eba442bd..00000000 --- a/libs/hc_common/src/lib.rs +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Provides common access to third-party crates and other -//! functionality used widely throughout Hipcheck. - -pub mod command_util; -pub mod context; -pub mod error; -pub mod filesystem; -pub mod pathbuf; -pub mod test_util; -#[cfg(test)] -mod tests; -mod try_any; -mod try_filter; - -pub use try_any::TryAny; -pub use try_filter::{FallibleFilter, TryFilter}; - -pub use chrono; -pub use hc_serde::serde; -pub use lazy_static; -pub use log; -pub use ordered_float; -pub use salsa; -pub use schemars; -pub use semver; -pub use serde_json; -pub use url; -pub use which; - -/// An `f64` that is never `NaN`. -pub type F64 = ordered_float::NotNan; - -//Global variables for toml files per issue 157 config updates -pub const LANGS_FILE: &str = "Langs.toml"; -pub const BINARY_CONFIG_FILE: &str = "Binary.toml"; -pub const TYPO_FILE: &str = "Typos.toml"; -pub const ORGS_FILE: &str = "Orgs.toml"; -pub const HIPCHECK_TOML_FILE: &str = "Hipcheck.toml"; - -// Constants for exiting with error codes. -/// Indicates the program failed. -pub const EXIT_FAILURE: i32 = 1; - -/// Indicates the program succeeded. -pub const EXIT_SUCCESS: i32 = 0; - -//used in hc_session::pm and main.rs, global variables for hc check CheckKindHere node-ipc@9.2.1 -pub enum CheckKind { - Repo, - Request, - Patch, - Maven, - Npm, - Pypi, - Spdx, -} - -impl CheckKind { - pub const fn name(&self) -> &'static str { - match self { - CheckKind::Repo => "repo", - CheckKind::Request => "request", - CheckKind::Patch => "patch", - CheckKind::Maven => "maven", - CheckKind::Npm => "npm", - CheckKind::Pypi => "pypi", - CheckKind::Spdx => "spdx", - } - } -} diff --git a/libs/hc_config/Cargo.toml b/libs/hc_config/Cargo.toml deleted file mode 100644 index 5a4f983a..00000000 --- a/libs/hc_config/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "hc_config" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -hc_common = { path = "../hc_common" } -smart-default = "0.7.1" diff --git a/libs/hc_config/src/lib.rs b/libs/hc_config/src/lib.rs deleted file mode 100644 index 73bbe874..00000000 --- a/libs/hc_config/src/lib.rs +++ /dev/null @@ -1,465 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Defines the configuration file format. - -mod query; - -pub use query::*; - -use hc_common::{ - context::Context, - error::Result, - filesystem as file, - serde::{self, Deserialize, Serialize}, - F64, -}; -use smart_default::SmartDefault; -use std::default::Default; -use std::path::Path; - -impl Config { - /// Load configuration from the given directory. - pub fn load_from(config_path: &Path) -> Result { - file::exists(config_path)?; - let config = file::read_toml(config_path).context("can't parse config file")?; - - Ok(config) - } -} - -/// Represents the configuration of Hipcheck's analyses. -#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)] -#[serde(crate = "self::serde")] -pub struct Config { - /// The configuration of overall project risk tolerance. - #[serde(default)] - pub risk: RiskConfig, - - /// The configuration of Hipcheck's different analyses. - #[serde(default)] - pub analysis: AnalysisConfig, - - /// The configuration of Hipcheck's knowledge about languages. - #[serde(default)] - pub languages: LanguagesConfig, -} - -/// Represents configuration of the overall risk threshold of an assessment. -#[derive(Debug, Serialize, Deserialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct RiskConfig { - /// The risk tolerance threshold, a value between 0 and 1. - #[default(_code = "F64::new(0.5).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub threshold: F64, -} - -/// Defines configuration for all of Hipcheck's analyses. -#[derive(Debug, Deserialize, Serialize, Default, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct AnalysisConfig { - /// Defines configuration for practices analysis. - #[serde(default)] - pub practices: PracticesConfig, - - /// Defines configuration for attack analysis. - #[serde(default)] - pub attacks: AttacksConfig, -} - -/// Configuration of analyses on a repo's development practices. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct PracticesConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// Defines configuration for activity analysis. - #[serde(default)] - pub activity: ActivityConfig, - - /// Defines configuration for binary file analysis. - #[serde(default)] - pub binary: BinaryConfig, - - /// Defines configuration for in fuzz analysis. - #[serde(default)] - pub fuzz: FuzzConfig, - - /// Defines configuration for identity analysis. - #[serde(default)] - pub identity: IdentityConfig, - - /// Defines configuration for review analysis. - #[serde(default)] - pub review: ReviewConfig, -} - -/// Configuration of analyses on potential attacks against a repo. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct AttacksConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// Defines configuration for typo analysis. - #[serde(default)] - pub typo: TypoConfig, - - /// Defines configuration for commit analysis. - #[serde(default)] - pub commit: CommitConfig, -} - -/// Configuration of analyses on individual commits. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct CommitConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// Defines configuration for affiliation analysis. - #[serde(default)] - pub affiliation: AffiliationConfig, - - /// Defines configuration for churn analysis. - #[serde(default)] - pub churn: ChurnConfig, - - /// Defines configuration for contributor trust analysis. - #[serde(default)] - pub contributor_trust: ContributorTrustConfig, - - /// Defines configuration for contributor trust analysis. - #[serde(default)] - pub commit_trust: CommitTrustConfig, - - /// Defines configuration for entropy analysis. - #[serde(default)] - pub entropy: EntropyConfig, - - /// Defines configuration for pull request affiliation analysis. - #[serde(default)] - pub pr_affiliation: PrAffiliationConfig, - - /// Defines configuration for pull request module contributors analysis. - #[serde(default)] - pub pr_module_contributors: PrModuleContributorsConfig, -} - -/// Defines configuration for activity analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct ActivityConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A number of weeks, over which a repo fails the analysis. - #[default = 71] - pub week_count_threshold: u64, -} - -/// Defines configuration for affiliation analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct AffiliationConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A number of affiliations permitted, over which a repo fails the analysis. - #[default = 0] - pub count_threshold: u64, - - /// An "orgs file" containing info for affiliation matching. - #[default = "Orgs.toml"] - pub orgs_file: String, -} - -/// Defines configuration for binary file analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct BinaryConfig { - /// Binary file extension configuration file. - #[default = "Binary.toml"] - pub binary_config_file: String, - - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A count of binary files over which a repo fails the analysis. - #[default = 0] - pub binary_file_threshold: u64, -} - -/// Defines configuration for churn analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct ChurnConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A churn Z-score, over which a commit is marked as "bad" - #[default(_code = "F64::new(3.0).unwrap()")] - pub value_threshold: F64, - - /// A percentage of "bad" commits over which a repo fails the analysis. - #[default(_code = "F64::new(0.02).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines configuration for commit trust analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct CommitTrustConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, -} - -/// Defines configuration for contributor trust analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct ContributorTrustConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A trust N-score, number of commits over which a commitor is marked as trusted or not - #[default = 3] - pub value_threshold: u64, - - /// A number of months over which a contributor would be tracked for trust. - #[default = 3] - pub trust_month_count_threshold: u64, - - /// A percentage of "bad" commits over which a repo fails the analysis because commit is not trusted. - #[default(_code = "F64::new(0.0).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines configuration for entropy analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct EntropyConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// An entropy Z-score, over which a commit is marked as "bad" - #[default(_code = "F64::new(10.0).unwrap()")] - pub value_threshold: F64, - - /// A percentage of "bad" commits over which a repo fails the analysis. - #[default(_code = "F64::new(0.0).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines configuration for identity analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct IdentityConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A percentage of commits permitted to have a mismatch between committer and - /// submitter identity, over which a repo fails the analysis. - #[default(_code = "F64::new(0.20).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines configuration for review analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct ReviewConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A percentage of pull requests permitted to not have review prior to being - /// merged, over which a repo fails the analysis. - #[default(_code = "F64::new(0.05).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines configuration for typo analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct TypoConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// The number of potential dependency name typos permitted, over which - /// a repo fails the analysis. - #[default = 0] - pub count_threshold: u64, - - /// Path to a "typos file" containing necessary information for typo detection. - #[default = "Typos.toml"] - pub typo_file: String, -} - -/// Defines configuration for pull request affiliation analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct PrAffiliationConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// A number of affiliations permitted, over which a repo fails the analysis. - #[default = 0] - pub count_threshold: u64, -} - -/// Defines configuration for pull request module committers analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct PrModuleContributorsConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, - - /// Percent of committers working on a module for the first time permitted, over which a repo fails the analysis. - #[default(_code = "F64::new(0.30).unwrap()")] - #[serde(deserialize_with = "de::percent")] - pub percent_threshold: F64, -} - -/// Defines the configuration of language-specific info. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(crate = "self::serde")] -pub struct LanguagesConfig { - /// The file to pull language information from. - #[default = "Langs.toml"] - pub langs_file: String, -} - -/// Defines configuration for fuzz analysis. -#[derive(Debug, Deserialize, Serialize, SmartDefault, PartialEq, Eq)] -#[serde(default, crate = "self::serde")] -pub struct FuzzConfig { - /// Whether the analysis is active. - #[default = true] - pub active: bool, - - /// How heavily the analysis' results weigh in risk scoring. - #[default = 1] - pub weight: u64, -} - -/// Inner module for deserialization helpers. -mod de { - use super::serde::de::{self, Deserializer, Visitor}; - use super::F64; - use std::fmt::{self, Formatter}; - - /// Deserialize a float, ensuring it's between 0.0 and 1.0 inclusive. - pub(super) fn percent<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - struct PercentVisitor; - - impl<'de> Visitor<'de> for PercentVisitor { - type Value = f64; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a float between 0.0 and 1.0 inclusive") - } - - fn visit_f64(self, value: f64) -> Result - where - E: de::Error, - { - if is_percent(value) { - Ok(value) - } else { - Err(de::Error::custom("must be between 0.0 and 1.0 inclusive")) - } - } - } - - // Deserialize and return as `F64` - let percent = deserializer.deserialize_f64(PercentVisitor)?; - Ok(F64::new(percent).unwrap()) - } - - /// Check if a float is a valid percent value. - fn is_percent(f: f64) -> bool { - (0.0..=1.0).contains(&f) - } -} diff --git a/libs/hc_core/Cargo.toml b/libs/hc_core/Cargo.toml deleted file mode 100644 index 82a79a14..00000000 --- a/libs/hc_core/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "hc_core" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -hc_analysis = { path = "../hc_analysis" } -hc_common = { path = "../hc_common" } -hc_shell = { path = "../hc_shell" } -hc_version = { path = "../hc_version" } - -[dev_dependencies] -duct = "0.13.7" -tempfile = "3.10.1" -hc_common = { path = "../hc_common" } -criterion = "0.5.1" - -[[bench]] -name = "basic" -harness = false -path = "../../benches/basic.rs" - -[[test]] -name = "can_run" -path = "../../tests/can_run.rs" - diff --git a/libs/hc_core/src/lib.rs b/libs/hc_core/src/lib.rs deleted file mode 100644 index a4299558..00000000 --- a/libs/hc_core/src/lib.rs +++ /dev/null @@ -1,206 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -pub use hc_analysis::{ - report_builder::{AnyReport, Format, PrReport, Report}, - session::{resolve_config, resolve_data, resolve_home, Check, CheckType}, -}; -pub use hc_shell::{ColorChoice, Output, Shell, Verbosity}; -pub use hc_version as version; - -use hc_analysis::{ - report_builder::{build_pr_report, build_report}, - score::{score_pr_results, score_results}, - session::Session, -}; -use hc_common::{ - context::Context as _, - error::{Error, Result}, -}; -use std::path::PathBuf; - -/// Run Hipcheck. -/// -/// Parses arguments, sets up shell output, and then runs the main logic. -#[allow(clippy::too_many_arguments)] -pub fn run( - output: Output, - error_output: Output, - verbosity: Verbosity, - check: Check, - config_path: Option, - data_path: Option, - home_dir: Option, - format: Format, - raw_version: &str, -) -> (Shell, Result) { - // Setup wrapper for shell output. - let shell = Shell::new(output, error_output, verbosity); - - // Run and print / report errors. - run_with_shell( - shell, - check, - config_path, - data_path, - home_dir, - format, - raw_version, - ) -} - -// This is pub for testing purposes. -/// Now that we're fully-initialized, run Hipcheck's analyses. -#[allow(clippy::too_many_arguments)] -#[doc(hidden)] -pub fn run_with_shell( - shell: Shell, - check: Check, - config_path: Option, - data_path: Option, - home_dir: Option, - format: Format, - raw_version: &str, -) -> (Shell, Result) { - // Initialize the session. - let session = match Session::new( - shell, - &check, - &check.check_value, - config_path, - data_path, - home_dir, - format, - raw_version, - ) { - Ok(session) => session, - Err((shell, err)) => return (shell, Err(err)), - }; - - match check.check_type { - CheckType::RepoSource | CheckType::SpdxDocument => { - // Run analyses against a repo and score the results (score calls analyses that call metrics). - let mut phase = match session.shell.phase("analyzing and scoring results") { - Ok(phase) => phase, - Err(err) => return (session.end(), Err(err)), - }; - - let scoring = match score_results(&mut phase, &session) { - Ok(scoring) => scoring, - _ => { - return ( - session.end(), - Err(Error::msg("Trouble scoring and analyzing results")), - ) - } - }; - - match phase.finish() { - Ok(()) => {} - Err(err) => return (session.end(), Err(err)), - }; - - // Build the final report. - let report = - match build_report(&session, &scoring).context("failed to build final report") { - Ok(report) => report, - Err(err) => return (session.end(), Err(err)), - }; - - (session.end(), Ok(AnyReport::Report(report))) - } - CheckType::PackageVersion => { - // Run analyses against a repo and score the results (score calls analyses that call metrics). - let mut phase = match session.shell.phase("analyzing and scoring results") { - Ok(phase) => phase, - Err(err) => return (session.end(), Err(err)), - }; - - let scoring = match score_results(&mut phase, &session) { - Ok(scoring) => scoring, - _ => { - return ( - session.end(), - Err(Error::msg("Trouble scoring and analyzing results")), - ) - } - }; - - match phase.finish() { - Ok(()) => {} - Err(err) => return (session.end(), Err(err)), - }; - - // Build the final report. - let report = - match build_report(&session, &scoring).context("failed to build final report") { - Ok(report) => report, - Err(err) => return (session.end(), Err(err)), - }; - - (session.end(), Ok(AnyReport::Report(report))) - } - CheckType::PrUri => { - // Run analyses against a pull request and score the results (score calls analyses that call metrics). - let mut phase = match session.shell.phase("scoring and analyzing results") { - Ok(phase) => phase, - Err(err) => return (session.end(), Err(err)), - }; - - let score = match score_pr_results(&mut phase, &session) { - Ok(score) => score, - _ => { - return ( - session.end(), - Err(Error::msg("Trouble scoring and analyzing results")), - ) - } - }; - - match phase.finish() { - Ok(()) => {} - Err(err) => return (session.end(), Err(err)), - }; - - // Build the final report. - let pr_report = - match build_pr_report(&session, &score).context("failed to build final report") { - Ok(pr_report) => pr_report, - Err(err) => return (session.end(), Err(err)), - }; - - (session.end(), Ok(AnyReport::PrReport(pr_report))) - } - _ => ( - session.end(), - Err(Error::msg( - "Hipcheck attempted to analyze an unsupported type", - )), - ), - } -} - -/// Print errors which occur before the `Shell` type can be setup. -pub fn print_error(err: &Error) { - let mut chain = err.chain(); - - // PANIC: First error is guaranteed to be present. - eprintln!("error: {}", chain.next().unwrap()); - - for err in chain { - eprintln!(" {}", err); - } -} - -pub enum Outcome { - Ok, - Err, -} - -impl Outcome { - pub fn exit_code(&self) -> i32 { - match self { - Outcome::Ok => 0, - Outcome::Err => 1, - } - } -} diff --git a/libs/hc_data/Cargo.toml b/libs/hc_data/Cargo.toml deleted file mode 100644 index c338b195..00000000 --- a/libs/hc_data/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "hc_data" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -dirs = "5.0.1" -graphql_client = "0.14.0" -hc_common = { path = "../hc_common" } -hc_config = { path = "../hc_config" } -hc_shell = { path = "../hc_shell" } -hc_version = { path = "../hc_version" } -nom = "7.1.3" -petgraph = { version = "0.6.0", features = ["serde-1"] } -serde = { path = "../hc_serde", package = "hc_serde" } -ureq = { version = "2.9.7", default-features = false, features = ["json", "native-tls"] } - -[dev-dependencies] -dirs = "5.0.1" -tempfile = "3.2.0" diff --git a/libs/hc_data/src/query/mod.rs b/libs/hc_data/src/query/mod.rs deleted file mode 100644 index 91eb2b6f..00000000 --- a/libs/hc_data/src/query/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! A collection of Salsa query groups for accessing the data used in -//! Hipcheck's analyses. - -mod code_quality; -mod dependencies; -mod fuzz; -mod github; -mod module; -mod pr_review; - -pub use code_quality::{CodeQualityProvider, CodeQualityProviderStorage}; -pub use dependencies::{DependenciesProvider, DependenciesProviderStorage}; -pub use fuzz::{FuzzProvider, FuzzProviderStorage}; -pub use github::{GitHubProvider, GitHubProviderStorage}; -pub use module::{ModuleCommitMap, ModuleProvider, ModuleProviderStorage}; -pub use pr_review::{PullRequestReviewProvider, PullRequestReviewProviderStorage}; diff --git a/libs/hc_report/Cargo.toml b/libs/hc_report/Cargo.toml deleted file mode 100644 index 8d392dbd..00000000 --- a/libs/hc_report/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "hc_report" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -hc_common = { path = "../hc_common" } -hc_version = { path = "../hc_version" } -paste = "1.0.7" diff --git a/libs/hc_report/src/query.rs b/libs/hc_report/src/query.rs deleted file mode 100644 index 3a93037e..00000000 --- a/libs/hc_report/src/query.rs +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Query groups for how Hipcheck reports and dumps session results. - -pub use hc_version::VersionQuery; - -use crate::Format; -use hc_common::{chrono::prelude::*, salsa}; - -/// Queries for how Hipcheck reports session results -#[salsa::query_group(ReportParamsStorage)] -pub trait ReportParams: VersionQuery { - /// Returns the time the current Hipcheck session started - #[salsa::input] - fn started_at(&self) -> DateTime; - - /// Returns the format of the final report - #[salsa::input] - fn format(&self) -> Format; -} diff --git a/libs/hc_serde/Cargo.toml b/libs/hc_serde/Cargo.toml deleted file mode 100644 index 32189b16..00000000 --- a/libs/hc_serde/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "hc_serde" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -serde = { version = "1.0.137", features = ["derive", "rc"] } diff --git a/libs/hc_serde/src/lib.rs b/libs/hc_serde/src/lib.rs deleted file mode 100644 index 4d56de19..00000000 --- a/libs/hc_serde/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! Provides common access to the `serde` crate, used widely -//! throughout Hipcheck. -//! -//! This dependency has not been included in `hc_common` in order to -//! support use of `graphql_client` derive macros, which require that -//! `serde` be a direct dependency of the containing crate. By -//! placing the direct `serde` dependency here, we can alias this -//! crate as `serde` when we need to. -//! -//! Note that `hc_common` re-exports this crate's own `serde` export. -//! Use `hc_common` over this whenever possible. - -pub use serde::{self, *}; diff --git a/libs/hc_shell/Cargo.toml b/libs/hc_shell/Cargo.toml deleted file mode 100644 index 780af4bb..00000000 --- a/libs/hc_shell/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "hc_shell" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false - -[dependencies] -duct = "0.13.5" -hc_common = { path = "../hc_common" } -hc_report = { path = "../hc_report" } -libc = "0.2.154" -termcolor = "1.1.3" - -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" -features = [ - "handleapi", - "processenv", - "winbase", - "wincon", - "winnt", -] diff --git a/libs/hc_version/Cargo.toml b/libs/hc_version/Cargo.toml deleted file mode 100644 index 039dd8a8..00000000 --- a/libs/hc_version/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "hc_version" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" -publish = false -build = "src/build.rs" - -[dependencies] -hc_common = { path = "../hc_common" } - -[build-dependencies] -hc_common = { path = "../hc_common" } \ No newline at end of file diff --git a/libs/hc_version/src/query.rs b/libs/hc_version/src/query.rs deleted file mode 100644 index e1b05b1d..00000000 --- a/libs/hc_version/src/query.rs +++ /dev/null @@ -1,24 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 - -//! A query group for current versions of Hipcheck and tool -//! dependencies. - -use hc_common::salsa; -use std::rc::Rc; - -/// Queries for current versions of Hipcheck and tool dependencies -#[salsa::query_group(VersionQueryStorage)] -pub trait VersionQuery: salsa::Database { - /// Returns the current Hipcheck version - #[salsa::input] - fn hc_version(&self) -> Rc; - /// Returns the version of npm currently running on user's machine - #[salsa::input] - fn npm_version(&self) -> Rc; - /// Returns the version of eslint currently running on user's machine - #[salsa::input] - fn eslint_version(&self) -> Rc; - /// Returns the version of git currently running on user's machine - #[salsa::input] - fn git_version(&self) -> Rc; -} diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 7ca328be..00000000 --- a/tests/README.md +++ /dev/null @@ -1,5 +0,0 @@ - -# Hipcheck Integration Tests - -The tests in this folder are integration tests for all of Hipcheck. Any new tests -here need to be added to `libs/hc_core` as a new `[[test]]`. diff --git a/tests/can_run.rs b/tests/can_run.rs deleted file mode 100644 index 1892f28d..00000000 --- a/tests/can_run.rs +++ /dev/null @@ -1,69 +0,0 @@ -use hc_common::{error::Result, CheckKind}; -use hc_core::*; -use std::ffi::OsString; -use tempfile::tempdir; - -// Don't run these tests by default, since they're slow. - -/// Check if Hipcheck can run against its own repository. -#[test] -#[ignore] -fn hc_can_run() { - // Run Hipcheck on its own repo. - check_can_run(".").unwrap(); -} - -/// Check if Hipcheck can run against an empty repository. -#[test] -#[should_panic( - expected = "called `Result::unwrap()` on an `Err` value: can't get head commit for local source" -)] -#[ignore] -fn hc_properly_errors_on_empty_repo() { - // Create an empty git repo. - let dir = tempdir().unwrap(); - let _ = duct::cmd!("git", "init", dir.path()); - let result = check_can_run(dir.path()); - dir.close().unwrap(); - result.unwrap(); -} - -fn check_can_run>(repo: S) -> Result<()> { - let shell = { - // Silent mode to ensure no output at all. - let verbosity = Verbosity::Silent; - let color_choice = ColorChoice::Never; - - Shell::new( - Output::stdout(color_choice), - Output::stderr(color_choice), - verbosity, - ) - }; - - let check = Check { - check_type: CheckType::RepoSource, - check_value: repo.into(), - parent_command_value: CheckKind::Repo.name().to_string(), - }; - - let config_path = None; - let data_path = None; - let home_dir = None; - let format = Format::Human; - let raw_version = "0.0.0"; - - // Get the result, drop the `Shell`. - let (_, result) = run_with_shell( - shell, - check, - config_path, - data_path, - home_dir, - format, - raw_version, - ); - - // Ignore contents of Result::Ok - result.map(|_| ()) -} diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index d956babb..2e2f3ada 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,8 +7,12 @@ edition = "2021" publish = false [dependencies] -hc_common = { path = "../libs/hc_common" } -clap = { version = "4.5.4", default-features = false, features = ["cargo", "std"] } +clap = { version = "4.5.4", default-features = false, features = [ + "cargo", + "std", +] } +anyhow = "1.0.83" +pathbuf = "1.0.0" glob = "0.3.0" serde = { version = "1.0.133", features = ["derive"] } toml = "0.8.12" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 51bb08e5..0553647a 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -4,10 +4,16 @@ mod exit; mod task; mod workspace; -use crate::exit::{EXIT_FAILURE, EXIT_SUCCESS}; +use crate::exit::EXIT_FAILURE; +use crate::exit::EXIT_SUCCESS; use crate::task::doc::OpenDoc; -use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; -use hc_common::error::{Error, Result}; +use anyhow::Error; +use anyhow::Result; +use clap::crate_version; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; use std::process::exit; fn main() { diff --git a/xtask/src/task/bench.rs b/xtask/src/task/bench.rs index 21e5c882..ed0cfaf5 100644 --- a/xtask/src/task/bench.rs +++ b/xtask/src/task/bench.rs @@ -4,11 +4,10 @@ use crate::exit::EXIT_SUCCESS; use crate::task::ci::Printer; +use anyhow::anyhow as hc_error; +use anyhow::Error; +use anyhow::Result; use duct::cmd; -use hc_common::{ - error::{Error, Result}, - hc_error, -}; use std::io; use std::mem::drop; use std::process::exit; diff --git a/xtask/src/task/ci.rs b/xtask/src/task/ci.rs index 9306d93c..8873fc91 100644 --- a/xtask/src/task/ci.rs +++ b/xtask/src/task/ci.rs @@ -3,12 +3,14 @@ //! A task to simulate a CI run locally. use crate::exit::EXIT_SUCCESS; +use anyhow::anyhow as hc_error; +use anyhow::Error; +use anyhow::Result; use duct::cmd; -use hc_common::{ - error::{Error, Result}, - hc_error, -}; -use std::io::{self, Stderr, Stdout, Write as _}; +use std::io; +use std::io::Stderr; +use std::io::Stdout; +use std::io::Write as _; use std::mem::drop; use std::ops::Not as _; use std::process::exit; @@ -201,7 +203,7 @@ fn run_fmt(printer: &mut Printer) -> Result<()> { .run() .map(drop) .map_err(reason( - "call to cargo fmt failed. To automatically fix cargo fmt issues most likely due to white space or tab issues, run + "call to cargo fmt failed. To automatically fix cargo fmt issues most likely due to white space or tab issues, run cargo fmt --all", )) } diff --git a/xtask/src/task/doc.rs b/xtask/src/task/doc.rs index 5c1f1f2a..a90b3354 100644 --- a/xtask/src/task/doc.rs +++ b/xtask/src/task/doc.rs @@ -3,11 +3,11 @@ //! A task to simulate a CI run locally. use crate::exit::EXIT_SUCCESS; +use anyhow::anyhow as hc_error; +use anyhow::Error; +use anyhow::Result; use duct::cmd; -use hc_common::{ - error::{Error, Result}, - hc_error, pathbuf, -}; +use pathbuf::pathbuf; use std::io; use std::mem::drop; use std::path::PathBuf; diff --git a/xtask/src/task/install.rs b/xtask/src/task/install.rs index 82deac3e..43024f9c 100644 --- a/xtask/src/task/install.rs +++ b/xtask/src/task/install.rs @@ -3,11 +3,10 @@ //! Installs binaries from the workspace. use crate::exit::EXIT_SUCCESS; +use anyhow::anyhow as hc_error; +use anyhow::Error; +use anyhow::Result; use duct::cmd; -use hc_common::{ - error::{Error, Result}, - hc_error, -}; use std::io; use std::mem::drop; use std::process::exit; diff --git a/xtask/src/task/validate.rs b/xtask/src/task/validate.rs index 25a21a17..c646873a 100644 --- a/xtask/src/task/validate.rs +++ b/xtask/src/task/validate.rs @@ -2,20 +2,29 @@ //! Validate the configuration of all Hipcheck crates. -use crate::exit::{EXIT_FAILURE, EXIT_SUCCESS}; +use crate::exit::EXIT_FAILURE; +use crate::exit::EXIT_SUCCESS; use crate::workspace; +use anyhow::anyhow as hc_error; +use anyhow::Context as _; +use anyhow::Result; use glob::glob; -use hc_common::{error::Result, filesystem::read_toml, hc_error, pathbuf}; +use pathbuf::pathbuf; +use serde::de::DeserializeOwned; use serde::Deserialize; -use std::fmt::{self, Debug, Display, Formatter}; +use std::collections::BTreeSet; +use std::fmt; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fs; +use std::fs::File; +use std::io::BufRead; +use std::io::BufReader; use std::ops::Not as _; -use std::path::{Path, PathBuf}; +use std::path::Path; +use std::path::PathBuf; use std::process::exit; -use std::{ - collections::BTreeSet, - fs::File, - io::{BufRead, BufReader}, -}; /// Print list of validation failures for crates in the workspace. pub fn run() -> Result<()> { @@ -532,3 +541,21 @@ fn resolve_configs(dir: &Path) -> Result> { Ok(configs) } + +/// Read file to a struct that can be deserialized from TOML format. +fn read_toml, T: DeserializeOwned>(path: P) -> Result { + let path = path.as_ref(); + let contents = read_string(path)?; + toml::de::from_str(&contents) + .with_context(|| format!("failed to read as TOML '{}'", path.display())) +} + +/// Read a file to a string. +fn read_string>(path: P) -> Result { + fn inner(path: &Path) -> Result { + fs::read_to_string(path) + .with_context(|| format!("failed to read as UTF-8 string '{}'", path.display())) + } + + inner(path.as_ref()) +} diff --git a/xtask/src/workspace.rs b/xtask/src/workspace.rs index 964184e9..16277e40 100644 --- a/xtask/src/workspace.rs +++ b/xtask/src/workspace.rs @@ -1,7 +1,9 @@ // SPDX-License-Identifier: Apache-2.0 -use hc_common::{error::Result, hc_error}; -use std::path::{Path, PathBuf}; +use anyhow::anyhow as hc_error; +use anyhow::Result; +use std::path::Path; +use std::path::PathBuf; pub fn root() -> Result { Path::new(&env!("CARGO_MANIFEST_DIR"))