diff --git a/src/core/actions/analyze_project_dependencies.rs b/src/core/actions/analyze_project_dependencies.rs index 2be54f1..c2f3179 100644 --- a/src/core/actions/analyze_project_dependencies.rs +++ b/src/core/actions/analyze_project_dependencies.rs @@ -3,16 +3,13 @@ use futures::future; use tracing::instrument::WithSubscriber; use tracing::Instrument; -use crate::{ - core::{ - application::Application, - database::pk, - engine::{ - repository::{ProjectRepositorySnapshot, ProjectRepositoryView}, - DependencyUpdateOption, DiscoveredDependency, - }, +use crate::core::{ + application::Application, + database::pk, + engine::{ + repository::{ProjectRepositorySnapshot, ProjectRepositoryView}, + DependencyUpdateOption, DiscoveredDependency, }, - tui::views, }; #[derive(Clone)] diff --git a/src/core/clients/github_release_notes.rs b/src/core/clients/github_release_notes.rs index e5548fb..cfab82d 100644 --- a/src/core/clients/github_release_notes.rs +++ b/src/core/clients/github_release_notes.rs @@ -22,7 +22,7 @@ impl GithubReleaseNotesResolver { let clean_url = clean_url.trim_end_matches(".git"); let parts: Vec<&str> = clean_url.split('/').collect(); - let owner = parts.get(0).unwrap_or(&"").to_string(); + let owner = parts.first().unwrap_or(&"").to_string(); let repo = parts.get(1).unwrap_or(&"").to_string(); Self { @@ -206,12 +206,12 @@ impl GithubReleaseNotesResolver { }; let base_version = version.split('+').next().unwrap_or(version); - let mut lines = markdown.lines(); + let lines = markdown.lines(); let mut extracted = String::new(); let mut found = false; let mut target_level = 0; - while let Some(line) = lines.next() { + for line in lines { let trimmed = line.trim(); let mut is_heading = false; @@ -269,7 +269,7 @@ pub fn shift_markdown_headings(markdown: &str, target_top_level: usize, version: let mut lines = markdown.lines(); let mut remaining_markdown: Vec<&str> = Vec::new(); - while let Some(line) = lines.next() { + for line in lines.by_ref() { let trimmed = line.trim(); if trimmed.is_empty() { continue; diff --git a/src/core/clients/npm.rs b/src/core/clients/npm.rs index 2ece591..9dfa90b 100644 --- a/src/core/clients/npm.rs +++ b/src/core/clients/npm.rs @@ -267,7 +267,7 @@ fn clean_repo_url(url: &str) -> String { if clean_url.contains("github.com/") { let parts: Vec<&str> = clean_url.split("github.com/").collect(); if parts.len() == 2 { - let mut sub_parts = parts[1].split(|c| c == '/' || c == '#' || c == '?'); + let mut sub_parts = parts[1].split(['/', '#', '?']); let owner = sub_parts.next().unwrap_or(""); let repo = sub_parts.next().unwrap_or(""); if !owner.is_empty() && !repo.is_empty() { diff --git a/src/core/clients/tangled.rs b/src/core/clients/tangled.rs index ce55984..e23185a 100644 --- a/src/core/clients/tangled.rs +++ b/src/core/clients/tangled.rs @@ -90,7 +90,7 @@ impl Tangled { if let ipld_core::ipld::Ipld::String(name) = &**val { if name == repo_name { found_rkey = - Some(record.uri.split('/').last().unwrap_or("").to_string()); + Some(record.uri.split('/').next_back().unwrap_or("").to_string()); found_uri = Some(record.uri.clone()); break; } @@ -619,7 +619,7 @@ impl ProjectRepositoryMutator for TangledProjectRepositoryMutator { record .uri .split('/') - .last() + .next_back() .unwrap_or("unknown") .to_string(), ); diff --git a/src/core/engine/ecosystems/cargo/mod.rs b/src/core/engine/ecosystems/cargo/mod.rs index 1060518..7b907ca 100644 --- a/src/core/engine/ecosystems/cargo/mod.rs +++ b/src/core/engine/ecosystems/cargo/mod.rs @@ -66,6 +66,12 @@ impl CargoPatcher { } } +impl Default for CargoPatcher { + fn default() -> Self { + Self::new() + } +} + #[async_trait] impl Patcher for CargoPatcher { fn updated_requirement(&self, old_req: &str, target_version: &str) -> Option { diff --git a/src/core/engine/ecosystems/github_actions/internal/query_dependency_update_options.rs b/src/core/engine/ecosystems/github_actions/internal/query_dependency_update_options.rs index 0cc941b..4aabae7 100644 --- a/src/core/engine/ecosystems/github_actions/internal/query_dependency_update_options.rs +++ b/src/core/engine/ecosystems/github_actions/internal/query_dependency_update_options.rs @@ -214,7 +214,7 @@ fn coerce_version(v: &str) -> Option { return Some(ver); } - let (base, rest) = if let Some(idx) = v.find(|c| c == '-' || c == '+') { + let (base, rest) = if let Some(idx) = v.find(['-', '+']) { (&v[..idx], &v[idx..]) } else { (v, "") diff --git a/src/core/engine/ecosystems/npm/internal/discover_project_dependencies.rs b/src/core/engine/ecosystems/npm/internal/discover_project_dependencies.rs index f29bcf2..14bff9c 100644 --- a/src/core/engine/ecosystems/npm/internal/discover_project_dependencies.rs +++ b/src/core/engine/ecosystems/npm/internal/discover_project_dependencies.rs @@ -23,10 +23,7 @@ pub async fn run(repo: &dyn ProjectRepositorySnapshot) -> Result Some(yaml), - Err(_) => None, - }; + let workspace_yaml = repo.read_file("pnpm-workspace.yaml").await.ok(); let mut minimum_release_age = None; if let Some(workspace_yaml) = workspace_yaml { @@ -119,7 +116,7 @@ pub async fn run(repo: &dyn ProjectRepositorySnapshot) -> Result Result UpdateType { }; if latest_allowed_ver > current_ver { - if latest_allowed_ver.major > current_ver.major { - UpdateType::Major - } else if current_ver.major == 0 && latest_allowed_ver.minor > current_ver.minor { - UpdateType::Major - } else if current_ver.major == 0 - && current_ver.minor == 0 - && latest_allowed_ver.patch > current_ver.patch + if (latest_allowed_ver.major > current_ver.major) + || (current_ver.major == 0 && latest_allowed_ver.minor > current_ver.minor) + || (current_ver.major == 0 + && current_ver.minor == 0 + && latest_allowed_ver.patch > current_ver.patch) { UpdateType::Major } else if latest_allowed_ver.minor > current_ver.minor { diff --git a/src/core/engine/ecosystems/npm/mod.rs b/src/core/engine/ecosystems/npm/mod.rs index e6a051a..226c0c3 100644 --- a/src/core/engine/ecosystems/npm/mod.rs +++ b/src/core/engine/ecosystems/npm/mod.rs @@ -259,7 +259,7 @@ impl crate::core::engine::ecosystems::Patcher for NpmPatcher { (pkg_name.as_str(), pkg_info.as_mapping()) { if let Some(version_val) = info - .get(&serde_yml::Value::String("version".to_string())) + .get(serde_yml::Value::String("version".to_string())) { if let Some(version_str) = version_val.as_str() { let clean_version = version_str @@ -563,7 +563,7 @@ impl crate::core::engine::ecosystems::Patcher for NpmPatcher { Vec<(semver::Version, chrono::DateTime)>, > = std::collections::HashMap::new(); - for (_id, adv) in &baseline_advisories { + for adv in baseline_advisories.values() { if let (Some(module), Some(vulnerable)) = ( adv.get("module_name").and_then(|m| m.as_str()), adv.get("vulnerable_versions").and_then(|p| p.as_str()), @@ -859,7 +859,7 @@ impl crate::core::engine::ecosystems::Patcher for NpmPatcher { extract_versions_from_lock(updated_lock.as_deref().unwrap_or_default()); let mut still_vulnerable = std::collections::HashSet::new(); - for (id, _adv) in &baseline_advisories { + for id in baseline_advisories.keys() { if after_advisories.contains(id) { still_vulnerable.insert(id.clone()); } @@ -1018,8 +1018,8 @@ pub(crate) fn extract_versions_from_lock( if let Some(packages) = lock_val.get("packages").and_then(|p| p.as_mapping()) { for (k, _) in packages { if let Some(path) = k.as_str() { - if path.starts_with('/') { - let parts: Vec<&str> = path[1..].split('@').collect(); + if let Some(stripped) = path.strip_prefix('/') { + let parts: Vec<&str> = stripped.split('@').collect(); if parts.len() == 2 { let name = parts[0]; let version = parts[1].split('(').next().unwrap_or("").to_string(); @@ -1028,7 +1028,7 @@ pub(crate) fn extract_versions_from_lock( .or_insert_with(std::collections::HashSet::new) .insert(version); } else { - let parts: Vec<&str> = path[1..].split('/').collect(); + let parts: Vec<&str> = stripped.split('/').collect(); if parts.len() >= 2 { let version = parts .last() diff --git a/src/core/engine/pull_request_generator/mod.rs b/src/core/engine/pull_request_generator/mod.rs index e3f12bc..03bc013 100644 --- a/src/core/engine/pull_request_generator/mod.rs +++ b/src/core/engine/pull_request_generator/mod.rs @@ -165,7 +165,7 @@ impl AuditPullRequestGenerator for DefaultAuditPullRequestGenerator { pr_body.push_str(&format!("### `{}`\n", module_name)); if bump.before_versions.is_empty() && bump.after_versions.is_empty() { - pr_body.push_str(&format!("- Bumped\n")); + pr_body.push_str("- Bumped\n"); } else { let before_str = bump.before_versions.join(", "); let after_str = bump.after_versions.join(", "); @@ -205,7 +205,7 @@ impl AuditPullRequestGenerator for DefaultAuditPullRequestGenerator { pr_body.push_str(&line); } } - pr_body.push_str("\n"); + pr_body.push('\n'); } Ok(pr_body) diff --git a/src/core/engine/pull_request_generator/sections/advisories.rs b/src/core/engine/pull_request_generator/sections/advisories.rs index 5cdbd99..2507876 100644 --- a/src/core/engine/pull_request_generator/sections/advisories.rs +++ b/src/core/engine/pull_request_generator/sections/advisories.rs @@ -40,7 +40,7 @@ impl PullRequestSectionGenerator for AdvisoriesSection { let mut body = String::new(); body.push_str("> [!NOTE]\n> This update resolves the following security advisories:\n"); body.push_str(&advisories_md); - body.push_str("\n"); + body.push('\n'); Ok(Some(body)) } else { Ok(None) diff --git a/src/core/engine/pull_request_generator/sections/summary.rs b/src/core/engine/pull_request_generator/sections/summary.rs index bbb7cd4..db7e83c 100644 --- a/src/core/engine/pull_request_generator/sections/summary.rs +++ b/src/core/engine/pull_request_generator/sections/summary.rs @@ -125,7 +125,7 @@ impl PullRequestSectionGenerator for SummarySection { body.push_str(&format!("- `{}`\n", t.name)); } } - body.push_str("\n"); + body.push('\n'); } else { body.push_str(&format!( "This PR updates {} dependencies from the **{}** group.\n\n", @@ -191,7 +191,7 @@ impl PullRequestSectionGenerator for SummarySection { )); } } - body.push_str("\n"); + body.push('\n'); } } diff --git a/src/core/http_agent.rs b/src/core/http_agent.rs index 196ab9c..2ce83b0 100644 --- a/src/core/http_agent.rs +++ b/src/core/http_agent.rs @@ -33,7 +33,7 @@ impl HttpAgent { .build(); Self { - client: client, + client, semaphore: Arc::new(Semaphore::new(10)), cache: Arc::new(RwLock::new(HashMap::new())), } @@ -129,3 +129,9 @@ impl HttpAgent { Ok(json) } } + +impl Default for HttpAgent { + fn default() -> Self { + Self::new() + } +} diff --git a/src/core/platform.rs b/src/core/platform.rs index 2349bc4..778a763 100644 --- a/src/core/platform.rs +++ b/src/core/platform.rs @@ -136,3 +136,9 @@ impl PlatformRegistry { .ok_or_else(|| anyhow::anyhow!("Unsupported project platform: {}", id)) } } + +impl Default for PlatformRegistry { + fn default() -> Self { + Self::new() + } +} diff --git a/src/tui/app.rs b/src/tui/app.rs index 8bf3815..fce1ea5 100644 --- a/src/tui/app.rs +++ b/src/tui/app.rs @@ -144,41 +144,46 @@ impl App { pub fn update(&mut self, event: Event) -> Vec { let mut external_effects = Vec::new(); match event { - Event::Term(ref term_event) => match term_event { - crossterm::event::Event::Key(key) => match key.code { - KeyCode::Char('q') => { - self.lifecycle = Lifecycle::Exiting; - } - _ => { - let actions = match self.current_view_type { - ViewType::Overview => self.overview_view.update(&event, &self.backend), - ViewType::Project(_) => self.project_view.update(&event, &self.backend), - }; - - for action in actions { - match action { - ViewAction::SwitchView(new_view) => { - self.current_view_type = new_view; - if let ViewType::Project(id) = &self.current_view_type { - if id != &self.project_view.project_id { - self.project_view.project_id = id.clone(); - self.project_view.selected_bump_index = 0; - self.project_view.bump_table_state = - TableState::default(); - self.project_view.bump_table_state.select(Some(0)); + Event::Term(ref term_event) => { + if let crossterm::event::Event::Key(key) = term_event { + match key.code { + KeyCode::Char('q') => { + self.lifecycle = Lifecycle::Exiting; + } + _ => { + let actions = match self.current_view_type { + ViewType::Overview => { + self.overview_view.update(&event, &self.backend) + } + ViewType::Project(_) => { + self.project_view.update(&event, &self.backend) + } + }; + + for action in actions { + match action { + ViewAction::SwitchView(new_view) => { + self.current_view_type = new_view; + if let ViewType::Project(id) = &self.current_view_type { + if id != &self.project_view.project_id { + self.project_view.project_id = id.clone(); + self.project_view.selected_bump_index = 0; + self.project_view.bump_table_state = + TableState::default(); + self.project_view.bump_table_state.select(Some(0)); + } } } - } - ViewAction::SendPayload(payload) => { - external_effects.push(Effect::SendPayload(payload)); + ViewAction::SendPayload(payload) => { + external_effects.push(Effect::SendPayload(payload)); + } } } + self.dirty = true; } - self.dirty = true; } - }, - _ => {} - }, + } + } Event::Core(core_event) => { self.backend.process_server_event(core_event); diff --git a/src/tui/views/overview.rs b/src/tui/views/overview.rs index 6ca1347..8488f5a 100644 --- a/src/tui/views/overview.rs +++ b/src/tui/views/overview.rs @@ -25,6 +25,12 @@ impl OverviewView { } } +impl Default for OverviewView { + fn default() -> Self { + Self::new() + } +} + impl View for OverviewView { fn update(&mut self, event: &Event, backend: &Backend) -> Vec { if let Event::Term(crossterm::event::Event::Key(key)) = event { diff --git a/src/tui/views/project.rs b/src/tui/views/project.rs index 50965ee..64e8aaf 100644 --- a/src/tui/views/project.rs +++ b/src/tui/views/project.rs @@ -28,121 +28,111 @@ impl ProjectView { impl View for ProjectView { fn update(&mut self, event: &Event, backend: &Backend) -> Vec { - if let Event::Term(ref term_event) = event { - if let crossterm::event::Event::Key(key) = term_event { - match key.code { - KeyCode::Up => { - let mut bumps: Vec = backend - .db - .iter() - .filter(|(path, _)| path.starts_with("bump/")) - .filter_map(|(_, value)| { - serde_json::from_value::(value.clone()).ok() - }) - .filter(|b| b.project_id == self.project_id) - .collect(); - bumps.sort_by(|a, b| a.name.cmp(&b.name)); + if let Event::Term(crossterm::event::Event::Key(key)) = event { + match key.code { + KeyCode::Up => { + let mut bumps: Vec = backend + .db + .iter() + .filter(|(path, _)| path.starts_with("bump/")) + .filter_map(|(_, value)| serde_json::from_value::(value.clone()).ok()) + .filter(|b| b.project_id == self.project_id) + .collect(); + bumps.sort_by(|a, b| a.name.cmp(&b.name)); - if !bumps.is_empty() { - if self.selected_bump_index > 0 { - self.selected_bump_index -= 1; - } else { - self.selected_bump_index = bumps.len() - 1; - } - self.bump_table_state.select(Some(self.selected_bump_index)); - } - } - KeyCode::Down => { - let mut bumps: Vec = backend - .db - .iter() - .filter(|(path, _)| path.starts_with("bump/")) - .filter_map(|(_, value)| { - serde_json::from_value::(value.clone()).ok() - }) - .filter(|b| b.project_id == self.project_id) - .collect(); - bumps.sort_by(|a, b| a.name.cmp(&b.name)); - - if !bumps.is_empty() { - if self.selected_bump_index < bumps.len() - 1 { - self.selected_bump_index += 1; - } else { - self.selected_bump_index = 0; - } - self.bump_table_state.select(Some(self.selected_bump_index)); + if !bumps.is_empty() { + if self.selected_bump_index > 0 { + self.selected_bump_index -= 1; + } else { + self.selected_bump_index = bumps.len() - 1; } + self.bump_table_state.select(Some(self.selected_bump_index)); } - KeyCode::Left => { - return vec![ViewAction::SwitchView(ViewType::Overview)]; - } - KeyCode::Char(' ') => { - let mut bumps: Vec = backend - .db - .iter() - .filter(|(path, _)| path.starts_with("bump/")) - .filter_map(|(_, value)| { - serde_json::from_value::(value.clone()).ok() - }) - .filter(|b| b.project_id == self.project_id) - .collect(); - bumps.sort_by(|a, b| a.name.cmp(&b.name)); + } + KeyCode::Down => { + let mut bumps: Vec = backend + .db + .iter() + .filter(|(path, _)| path.starts_with("bump/")) + .filter_map(|(_, value)| serde_json::from_value::(value.clone()).ok()) + .filter(|b| b.project_id == self.project_id) + .collect(); + bumps.sort_by(|a, b| a.name.cmp(&b.name)); - if let Some(bump) = bumps.get(self.selected_bump_index) { - let payload = if bump.approved { - Payload::RetractBumpApproval { - bump_id: bump.id.clone(), - } - } else { - Payload::ApproveBump { - bump_id: bump.id.clone(), - } - }; - return vec![ViewAction::SendPayload(payload)]; + if !bumps.is_empty() { + if self.selected_bump_index < bumps.len() - 1 { + self.selected_bump_index += 1; + } else { + self.selected_bump_index = 0; } + self.bump_table_state.select(Some(self.selected_bump_index)); } - KeyCode::Char('s') | KeyCode::Char('S') => { - return vec![ViewAction::SendPayload( - Payload::AnalyzeProjectDependencies { - project_id: self.project_id.clone(), - trigger_bumps: false, - }, - )]; - } - KeyCode::Char('p') | KeyCode::Char('P') => { - let mut bumps: Vec = backend - .db - .iter() - .filter(|(path, _)| path.starts_with("bump/")) - .filter_map(|(_, value)| { - serde_json::from_value::(value.clone()).ok() - }) - .filter(|b| b.project_id == self.project_id) - .collect(); - bumps.sort_by(|a, b| a.name.cmp(&b.name)); + } + KeyCode::Left => { + return vec![ViewAction::SwitchView(ViewType::Overview)]; + } + KeyCode::Char(' ') => { + let mut bumps: Vec = backend + .db + .iter() + .filter(|(path, _)| path.starts_with("bump/")) + .filter_map(|(_, value)| serde_json::from_value::(value.clone()).ok()) + .filter(|b| b.project_id == self.project_id) + .collect(); + bumps.sort_by(|a, b| a.name.cmp(&b.name)); - if let Some(bump) = bumps.get(self.selected_bump_index) { - return vec![ViewAction::SendPayload(Payload::ProcessBump { + if let Some(bump) = bumps.get(self.selected_bump_index) { + let payload = if bump.approved { + Payload::RetractBumpApproval { bump_id: bump.id.clone(), - })]; - } - } - KeyCode::Char('a') | KeyCode::Char('A') => { - return vec![ViewAction::SendPayload( - Payload::UpdateVulnerableDependencies { - project_id: self.project_id.clone(), - }, - )]; + } + } else { + Payload::ApproveBump { + bump_id: bump.id.clone(), + } + }; + return vec![ViewAction::SendPayload(payload)]; } - KeyCode::Char('t') | KeyCode::Char('T') => { - return vec![ViewAction::SendPayload( - Payload::UpdateTransitiveDependencies { - project_id: self.project_id.clone(), - }, - )]; + } + KeyCode::Char('s') | KeyCode::Char('S') => { + return vec![ViewAction::SendPayload( + Payload::AnalyzeProjectDependencies { + project_id: self.project_id.clone(), + trigger_bumps: false, + }, + )]; + } + KeyCode::Char('p') | KeyCode::Char('P') => { + let mut bumps: Vec = backend + .db + .iter() + .filter(|(path, _)| path.starts_with("bump/")) + .filter_map(|(_, value)| serde_json::from_value::(value.clone()).ok()) + .filter(|b| b.project_id == self.project_id) + .collect(); + bumps.sort_by(|a, b| a.name.cmp(&b.name)); + + if let Some(bump) = bumps.get(self.selected_bump_index) { + return vec![ViewAction::SendPayload(Payload::ProcessBump { + bump_id: bump.id.clone(), + })]; } - _ => {} } + KeyCode::Char('a') | KeyCode::Char('A') => { + return vec![ViewAction::SendPayload( + Payload::UpdateVulnerableDependencies { + project_id: self.project_id.clone(), + }, + )]; + } + KeyCode::Char('t') | KeyCode::Char('T') => { + return vec![ViewAction::SendPayload( + Payload::UpdateTransitiveDependencies { + project_id: self.project_id.clone(), + }, + )]; + } + _ => {} } } vec![] @@ -245,7 +235,7 @@ impl View for ProjectView { let mut v = currents[0].clone(); if v.len() > 15 { v.truncate(14); - v.push_str("…"); + v.push('…'); } v } else { @@ -258,7 +248,7 @@ impl View for ProjectView { let mut v = targets[0].clone(); if v.len() > 15 { v.truncate(14); - v.push_str("…"); + v.push('…'); } v } else { @@ -271,7 +261,7 @@ impl View for ProjectView { let mut v = heads[0].clone(); if v.len() > 15 { v.truncate(14); - v.push_str("…"); + v.push('…'); } v } else {