From 939ea82d50a308154f354dab937b614e241293c4 Mon Sep 17 00:00:00 2001 From: Jeffrey Huynh Date: Tue, 3 Oct 2023 15:55:57 -0700 Subject: [PATCH] Removing integration try from and implementing custom validation function. Creating methods for BranchImportStrategy and TagImportStrategy --- docs/dev/README.md | 4 ++-- docs/reference/config.md | 6 +++--- src/api/remote.rs | 42 ++++++++++++++++++++++++++++++++++++++-- src/cmd/run.rs | 4 ++-- src/config/file/v1.rs | 42 ++++++++++++++++++---------------------- src/db/sqlite.rs | 11 ++++------- 6 files changed, 70 insertions(+), 39 deletions(-) diff --git a/docs/dev/README.md b/docs/dev/README.md index 23085fac..f24f45be 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md @@ -200,6 +200,6 @@ In order to allow Broker to scan tags in your remote, `import_tags` must be set ### toggling fields -Toggling `import_branches` from `true` to `false` will remove all existing uploaded scans for ALL branches of that particular remote in your database. If toggled from `false` to `true`, Broker will perform as if it is scanning the listed `watched_branches` for the first time. +Toggling `import_branches` from `true` to `false` will remove all existing uploaded scans for ALL branches of that particular remote in your local database (this does NOT delete your scans in the FOSSA UI). If toggled from `false` to `true`, Broker will perform as if it is scanning the listed `watched_branches` for the first time. On subsequent poll cycles, Broker will import the latest changes from your configured branches since the last revision (skipping any intermediate commits). -Toggling `import_tags` from `true` to `false` will remove all existing uploaded scans for ALL tags of that particular remote in your database. If toggled from `false` to `true`, Broker will perform as if it is scanning all the remote's tags for the first time. This would mean that all tags for that remote would be scanned. +Toggling `import_tags` from `true` to `false` will remove all existing uploaded scans for ALL tags of that particular remote in your local database (this does NOT delete your scans in the FOSSA UI). If toggled from `false` to `true`, Broker will perform as if it is scanning all the remote's tags for the first time. This would mean that all tags for that remote would be scanned. On subsequent poll cycles, Broker will import all created or changed tags since the last poll cycle. diff --git a/docs/reference/config.md b/docs/reference/config.md index e1f5b92e..1661036a 100644 --- a/docs/reference/config.md +++ b/docs/reference/config.md @@ -74,7 +74,7 @@ This block specifies how to configure Broker to communicate with a git server fo | `auth` | Required | Required authentication to clone this repository. | N/A | N/A | | `team` | Optional | The team in FOSSA to which this project should be assigned.2 | N/A | N/A | | `title` | Optional | Specify a custom title for the project instead of using the default.3 | N/A | N/A | -|`import_branches` | Optional | Initialize to scan specific branches for the remote repository | N/A | N/A | +| `import_branches` | Optional | Initialize to scan specific branches for the remote repository | N/A | N/A | | `import_tags` | Optional | Initialize to scan tags for the remote repository | N/A | N/A | | `watched_branches`| Optional | The name of the branches that you intend to scan | N/A | N/A | @@ -155,9 +155,9 @@ In order to allow Broker to scan tags in your remote, `import_tags` must be set ### toggling fields -Toggling `import_branches` from `true` to `false` will remove all existing uploaded scans for ALL branches of that particular remote in your database. If toggled from `false` to `true`, Broker will perform as if it is scanning the listed `watched_branches` for the first time. +Toggling `import_branches` from `true` to `false` will remove all existing uploaded scans for ALL branches of that particular remote in your local database (this does NOT delete your scans in the FOSSA UI). If toggled from `false` to `true`, Broker will perform as if it is scanning the listed `watched_branches` for the first time. On subsequent poll cycles, Broker will import the latest changes from your configured branches since the last revision (skipping any intermediate commits). -Toggling `import_tags` from `true` to `false` will remove all existing uploaded scans for ALL tags of that particular remote in your database. If toggled from `false` to `true`, Broker will perform as if it is scanning all the remote's tags for the first time. This would mean that all tags for that remote would be scanned. +Toggling `import_tags` from `true` to `false` will remove all existing uploaded scans for ALL tags of that particular remote in your local database (this does NOT delete your scans in the FOSSA UI). If toggled from `false` to `true`, Broker will perform as if it is scanning all the remote's tags for the first time. This would mean that all tags for that remote would be scanned. On subsequent poll cycles, Broker will import all created or changed tags since the last poll cycle. ## Integration authentication diff --git a/src/api/remote.rs b/src/api/remote.rs index a80e2f16..93b00820 100644 --- a/src/api/remote.rs +++ b/src/api/remote.rs @@ -258,7 +258,7 @@ impl TryFrom for PollInterval { } /// Specificies if we want to scan branches -#[derive(Debug, Clone, PartialEq, Eq, Display, Deserialize, Serialize, new)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Deserialize, Serialize, new)] pub enum BranchImportStrategy { /// Scanning branches is not allowed Disabled, @@ -276,8 +276,36 @@ impl From> for BranchImportStrategy { } } +impl BranchImportStrategy { + /// Validates branch import configurations + pub fn is_valid(&self, watched_branches: &[WatchedBranch]) -> bool { + match self { + BranchImportStrategy::Disabled => watched_branches.is_empty(), + // On the Enabled variant, we can't check if watched branches is not empty here because Broker will try to infer watched branches + // Therefore just have the Enabled case map to true, and the validation on the enabled case will be checked later + BranchImportStrategy::Enabled => true, + } + } + + /// Checks if we need to infer watched branches based on configuration + pub fn infer_watched_branches(&self, watched_branches: &[WatchedBranch]) -> bool { + match self { + BranchImportStrategy::Disabled => false, + BranchImportStrategy::Enabled => watched_branches.is_empty(), + } + } + + /// Checks if scanning on branches should be skipped based on the enum variant + pub fn should_skip_branches(&self) -> bool { + match self { + BranchImportStrategy::Disabled => true, + BranchImportStrategy::Enabled => false, + } + } +} + /// Specifies if the we want to scan tags -#[derive(Debug, Clone, PartialEq, Eq, Display, Deserialize, Serialize, new)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Deserialize, Serialize, new)] pub enum TagImportStrategy { /// Scanning tags is not allowed Disabled, @@ -295,6 +323,16 @@ impl From> for TagImportStrategy { } } +impl TagImportStrategy { + /// Checks if scanning tags should be skipped based on the enum variant + pub fn should_skip_tags(&self) -> bool { + match self { + TagImportStrategy::Disabled => true, + TagImportStrategy::Enabled => false, + } + } +} + /// The integration's branch that you intend to scan #[derive(Debug, Clone, PartialEq, Eq, AsRef, Display, Deserialize, Serialize, new)] pub struct WatchedBranch(String); diff --git a/src/cmd/run.rs b/src/cmd/run.rs index 9031e94e..eb8248fd 100644 --- a/src/cmd/run.rs +++ b/src/cmd/run.rs @@ -308,13 +308,13 @@ async fn execute_poll_integration( Reference::Git(git_reference) => match git_reference { git::Reference::Branch {..} => { // Skipping because integration is not configured to scan branches or branch was not in the integration's watched branches - if integration.import_branches() == &BranchImportStrategy::Disabled || !integration.should_scan_reference(reference.name()){ + if integration.import_branches().should_skip_branches() || !integration.should_scan_reference(reference.name()){ return None } }, git::Reference::Tag{..} => { // Skipping because integration was not configured to scan tags - if let TagImportStrategy::Disabled = integration.import_tags() { + if integration.import_tags().should_skip_tags() { return None } }, diff --git a/src/config/file/v1.rs b/src/config/file/v1.rs index b1a67360..1ffac45e 100644 --- a/src/config/file/v1.rs +++ b/src/config/file/v1.rs @@ -4,7 +4,7 @@ use error_stack::{report, Report, ResultExt}; use futures::future::join_all; use serde::Deserialize; use std::path::PathBuf; -use tokio::task; +use tap::Pipe; use tracing::warn; use crate::{ @@ -76,16 +76,13 @@ async fn validate(config: RawConfigV1) -> Result> { let key = fossa::Key::try_from(config.integration_key).change_context(Error::Validate)?; let api = fossa::Config::new(endpoint, key); let debugging = debug::Config::try_from(config.debugging).change_context(Error::Validate)?; - - // Spawn_blocking is used to allow try_from to operate as a blocking function. - // Try_from is a trait and cannot operate as an async function, but spawn_blocking allows you to bypass this. - let integrations = config.integrations.into_iter().map(|val| async { - task::spawn_blocking(move || remote::Integration::try_from(val)).await - }); - let integrations = join_all(integrations) + let integrations = config + .integrations + .into_iter() + .map(|integration| async { remote::Integration::validate(integration).await }) + .pipe(join_all) .await .into_iter() - .flatten() .collect::, Report>>() .change_context(Error::Validate) .map(remote::Integrations::new)?; @@ -150,14 +147,15 @@ pub(super) enum Integration { auth: Auth, import_branches: Option, import_tags: Option, + // Option> is generally not meaningful, because None is generally equivalent to an empty vector. + // However, this needs to be an option due to serde deny_unknown_fields. + // An empty vector will throw errors, which is not the intended action for users on these new changes watched_branches: Option>, }, } -impl TryFrom for remote::Integration { - type Error = Report; - - fn try_from(value: Integration) -> Result { +impl remote::Integration { + async fn validate(value: Integration) -> Result> { let mut integration = match value { Integration::Git { poll_interval, @@ -179,13 +177,11 @@ impl TryFrom for remote::Integration { .map(remote::WatchedBranch::new) .collect::>(); - if import_branches == remote::BranchImportStrategy::Disabled - && !watched_branches.is_empty() - { - report!(remote::ValidationError::ImportBranches) + if !import_branches.is_valid(&watched_branches) { + return report!(remote::ValidationError::ImportBranches) .wrap_err() .help("import branches must be 'true' if watched branches are provided") - .describe_lazy(|| "import branches: 'false'".to_string())? + .describe_lazy(|| "import branches: 'false'".to_string()); } let protocol = match auth { @@ -233,11 +229,11 @@ impl TryFrom for remote::Integration { } }; - if integration.watched_branches().is_empty() - && integration.import_branches() == &remote::BranchImportStrategy::Enabled + if integration + .import_branches() + .infer_watched_branches(integration.watched_branches()) { - let references = - futures::executor::block_on(integration.references()).unwrap_or_default(); + let references = integration.references().await.unwrap_or_default(); let primary_branch = references .iter() .find(|r| r.name() == MAIN_BRANCH || r.name() == MASTER_BRANCH) @@ -254,7 +250,7 @@ impl TryFrom for remote::Integration { } Some(branch) => { let primary_branch_name = branch.name(); - warn!("Inferred '{primary_branch_name}' as the primary branch for '{integration:#?}'. Broker imports only the primary branch when inferred; if desired this can be customized with the integration configuration."); + warn!("Inferred '{primary_branch_name}' as the primary branch for '{integration}'. Broker imports only the primary branch when inferred; if desired this can be customized with the integration configuration."); let watched_branch = remote::WatchedBranch::new(branch.name().to_string()); integration.add_watched_branch(watched_branch); } diff --git a/src/db/sqlite.rs b/src/db/sqlite.rs index b156561b..3ad8eefd 100644 --- a/src/db/sqlite.rs +++ b/src/db/sqlite.rs @@ -38,7 +38,6 @@ use sqlx::{ }; use tap::TapFallible; use thiserror::Error; -use tracing::warn; use crate::{ doc::{crate_name, crate_version}, @@ -218,12 +217,10 @@ impl super::Database for Database { "}) .help("try again with the latest version of Broker") } - Some(db_version) if current_version > db_version => { - warn!("Broker currently runnning on {db_version:?}. Updating Broker to run on {current_version:?}"); - self.update_db_version(¤t_version) - .await - .change_context(super::Error::Interact) - } + Some(db_version) if current_version > db_version => self + .update_db_version(¤t_version) + .await + .change_context(super::Error::Interact), Some(_) => Ok(()), } }