added tests for --branch and --since-commit feature

This commit is contained in:
Mick Grove 2025-10-23 17:02:31 -07:00
commit 9f91cbdab6
9 changed files with 296 additions and 17 deletions

View file

@ -71,7 +71,7 @@ pub struct BitbucketRepoSpecifiers {
pub exclude_repos: Vec<String>,
/// Enumerate all accessible workspaces or projects
#[arg(long, alias = "all-bitbucket-workspaces", requires = "bitbucket_api_url")]
#[arg(long, alias = "all-bitbucket-workspaces", requires = "api_url")]
pub all_workspaces: bool,
/// Filter repositories by type

View file

@ -59,7 +59,7 @@ pub struct GitHubRepoSpecifiers {
alias = "all-orgs",
alias = "all-github-organizations",
alias = "all-github-orgs",
requires = "github_api_url"
requires = "api_url"
)]
pub all_organizations: bool,

View file

@ -59,7 +59,7 @@ pub struct GitLabRepoSpecifiers {
pub exclude_repos: Vec<String>,
/// Repositories for all groups (Enterprise only)
#[arg(long, alias = "all-groups", alias = "all-gitlab-groups", requires = "gitlab_api_url")]
#[arg(long, alias = "all-groups", alias = "all-gitlab-groups", requires = "api_url")]
pub all_groups: bool,
/// Filter by repository type

View file

@ -1,6 +1,6 @@
use anyhow::bail;
use clap::{Args, Subcommand, ValueEnum, ValueHint};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use strum::Display;
use tracing::debug;
use url::Url;
@ -210,7 +210,7 @@ impl ScanCommandArgs {
ScanInputCommand::Github(args) => {
if args.specifiers.is_empty() {
bail!(
"Specify at least one --user, --org, or use --all-orgs when scanning GitHub"
"You must specify at least one --user, --org, or use --all-orgs when scanning GitHub"
);
}
if args.list_only {
@ -234,7 +234,7 @@ impl ScanCommandArgs {
ScanInputCommand::Gitlab(args) => {
if args.specifiers.is_empty() {
bail!(
"Specify at least one --user, --group, or use --all-groups when scanning GitLab"
"You must specify at least one --user, --group, or use --all-groups when scanning GitLab"
);
}
if args.list_only {
@ -283,7 +283,7 @@ impl ScanCommandArgs {
ScanInputCommand::Bitbucket(args) => {
if args.specifiers.is_empty() {
bail!(
"Specify at least one --user, --workspace, --project, or use --all-workspaces when scanning Bitbucket"
"You must specify at least one --user, --workspace, --project, or use --all-workspaces when scanning Bitbucket"
);
}
if args.list_only {
@ -309,7 +309,7 @@ impl ScanCommandArgs {
ScanInputCommand::Azure(args) => {
if args.specifiers.is_empty() {
bail!(
"Specify at least one --organization, --project, or use --all-projects when scanning Azure DevOps"
"You must specify at least one --organization, --project, or use --all-projects when scanning Azure DevOps"
);
}
if args.list_only {
@ -333,7 +333,7 @@ impl ScanCommandArgs {
ScanInputCommand::Huggingface(args) => {
if args.specifiers.is_empty() {
bail!(
"Specify at least one --user, --org, --model, --dataset, or --space when scanning Hugging Face"
"You must specify at least one --user, --org, --model, --dataset, or --space when scanning Hugging Face"
);
}
if args.list_only {
@ -402,6 +402,16 @@ impl ScanCommandArgs {
);
}
for path in &self.scan_args.input_specifier_args.path_inputs {
if path.as_path() == Path::new("-") {
continue;
}
if !path.exists() {
bail!("Error: unrecognized scan target or path does not exist: {}", path.display());
}
}
if !used_provider_subcommand {
self.scan_args.input_specifier_args.emit_deprecated_warnings();
}

View file

@ -20,6 +20,7 @@ use globset::{Glob, GlobSet, GlobSetBuilder};
use indicatif::{ProgressBar, ProgressStyle};
use serde::Deserialize;
use serde_json::Value;
use tokio::task;
use tracing::warn;
use url::{form_urlencoded, Url};
@ -50,7 +51,7 @@ pub enum RepoType {
}
/// A struct to hold GitLab repository query specifications
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct RepoSpecifiers {
pub user: Vec<String>,
pub group: Vec<String>,
@ -209,7 +210,23 @@ pub async fn enumerate_repo_urls(
repo_specifiers: &RepoSpecifiers,
gitlab_url: Url,
ignore_certs: bool,
mut progress: Option<&mut ProgressBar>,
progress: Option<ProgressBar>,
) -> Result<Vec<String>> {
let specifiers = repo_specifiers.clone();
let repo_urls = task::spawn_blocking(move || {
let progress_ref = progress.as_ref();
enumerate_repo_urls_blocking(&specifiers, gitlab_url, ignore_certs, progress_ref)
})
.await??;
Ok(repo_urls)
}
fn enumerate_repo_urls_blocking(
repo_specifiers: &RepoSpecifiers,
gitlab_url: Url,
ignore_certs: bool,
progress: Option<&ProgressBar>,
) -> Result<Vec<String>> {
let client = create_gitlab_client(&gitlab_url, ignore_certs)?;
let mut repo_urls = Vec::new();
@ -249,7 +266,7 @@ pub async fn enumerate_repo_urls(
repo_urls.push(proj.http_url_to_repo);
}
if let Some(pb) = progress.as_mut() {
if let Some(pb) = progress {
pb.inc(1);
}
}
@ -286,7 +303,7 @@ pub async fn enumerate_repo_urls(
}
repo_urls.push(proj.http_url_to_repo);
}
if let Some(pb) = progress.as_mut() {
if let Some(pb) = progress {
pb.inc(1);
}
}
@ -319,7 +336,7 @@ pub async fn list_repositories(
};
// Create a progress bar for displaying status
let mut progress = if progress_enabled {
let progress = if progress_enabled {
let style = ProgressStyle::with_template("{spinner} {msg} [{elapsed_precise}]")
.expect("progress bar style template should compile");
let pb = ProgressBar::new_spinner().with_style(style).with_message("Fetching repositories");
@ -330,7 +347,8 @@ pub async fn list_repositories(
};
let repo_urls =
enumerate_repo_urls(&repo_specifiers, api_url, ignore_certs, Some(&mut progress)).await?;
enumerate_repo_urls(&repo_specifiers, api_url, ignore_certs, Some(progress.clone()))
.await?;
// Print repositories
for url in repo_urls {

View file

@ -214,7 +214,7 @@ pub async fn enumerate_gitlab_repos(
&repo_specifiers,
api_url,
global_args.ignore_certs,
Some(&mut progress),
Some(progress.clone()),
)
.await
.context("Failed to enumerate GitLab repositories")?;