From 91d9f431c5e0e49ee543c172a0b0ee4b48bb6c35 Mon Sep 17 00:00:00 2001 From: Mick Grove Date: Mon, 18 May 2026 14:27:01 -0700 Subject: [PATCH] preparing for v1.100.0 --- src/github.rs | 26 ++++++++++++++++---------- src/scanner/enumerate.rs | 2 +- src/scanner/validation.rs | 19 +++++++++---------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/github.rs b/src/github.rs index added70..cd9f921 100644 --- a/src/github.rs +++ b/src/github.rs @@ -171,6 +171,10 @@ async fn ensure_github_success(resp: reqwest::Response, action: &str) -> Result< anyhow::bail!("GitHub API request failed while {action}: HTTP {status} ({url}): {body}"); } +fn is_github_soft_limit_status(status: StatusCode) -> bool { + matches!(status, StatusCode::FORBIDDEN | StatusCode::TOO_MANY_REQUESTS) +} + fn github_next_link(headers: &HeaderMap) -> Option { let raw = headers.get(reqwest::header::LINK)?.to_str().ok()?; raw.split(',').find_map(|part| { @@ -267,11 +271,12 @@ pub async fn enumerate_contributor_repo_urls( .join(&format!("repos/{owner}/{repo}/contributors")) .context("Failed to build GitHub contributors URL")?; url.query_pairs_mut().append_pair("per_page", "100").append_pair("page", &page.to_string()); - let resp = ensure_github_success( - github_get(&client, url, token.as_deref()).send().await?, - "listing contributors", - ) - .await?; + let resp = github_get(&client, url, token.as_deref()).send().await?; + if is_github_soft_limit_status(resp.status()) { + warn_on_rate_limit("GitHub", resp.status(), "listing contributors"); + break; + } + let resp = ensure_github_success(resp, "listing contributors").await?; let contributors: Vec = resp.json().await?; if contributors.is_empty() { break; @@ -324,11 +329,12 @@ pub async fn enumerate_contributor_repo_urls( .append_pair("type", "all") .append_pair("sort", "updated") .append_pair("direction", "desc"); - let resp = ensure_github_success( - github_get(&client, url, token.as_deref()).send().await?, - "listing user repositories", - ) - .await?; + let resp = github_get(&client, url, token.as_deref()).send().await?; + if is_github_soft_limit_status(resp.status()) { + warn_on_rate_limit("GitHub", resp.status(), "listing user repositories"); + break; + } + let resp = ensure_github_success(resp, "listing user repositories").await?; let repos: Vec = resp.json().await?; if repos.is_empty() { break; diff --git a/src/scanner/enumerate.rs b/src/scanner/enumerate.rs index d063ea0..4702711 100644 --- a/src/scanner/enumerate.rs +++ b/src/scanner/enumerate.rs @@ -715,7 +715,7 @@ fn try_extract_git_blob_archive( }, }; - Ok(Some(entries)) + if entries.is_empty() { Ok(None) } else { Ok(Some(entries)) } } // A marker so the struct itself carries the lifetime. diff --git a/src/scanner/validation.rs b/src/scanner/validation.rs index c52ad8c..8e4149f 100644 --- a/src/scanner/validation.rs +++ b/src/scanner/validation.rs @@ -962,16 +962,6 @@ fn build_cache_key( dep_vars: &FxHashMap>, ) -> String { // Build key - let dep_vars_str = dep_vars - .get(om.rule.id()) - .map(|hm| { - let mut sorted: Vec<_> = hm.iter().collect(); - sorted.sort_by(|(k, _), (k2, _)| k.cmp(k2)); - sorted.into_iter().map(|(k, v)| format!("{}={}", k, v)).collect::>().join("|") - }) - .unwrap_or_default(); - // For demonstration, we’ll do a simplistic approach - // You can adapt from your existing logic let capture0 = om.captures.captures.get(0).map_or(String::new(), |c| c.raw_value().to_string()); if !om.rule.syntax().depends_on_rule.is_empty() { @@ -985,6 +975,15 @@ fn build_cache_key( ); } + let dep_vars_str = dep_vars + .get(om.rule.id()) + .map(|hm| { + let mut sorted: Vec<_> = hm.iter().collect(); + sorted.sort_by(|(k, _), (k2, _)| k.cmp(k2)); + sorted.into_iter().map(|(k, v)| format!("{}={}", k, v)).collect::>().join("|") + }) + .unwrap_or_default(); + format!("{}|{}|{}", om.rule.name(), capture0, dep_vars_str) }