diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-06 10:12:26 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-06 10:59:24 +0100 |
| commit | f1aa1be738af0dc80eb3b5827249bb537de1e0cd (patch) | |
| tree | 4974673e04f6b05484450bbad44c545ca73bd27b /src/git_remote_helper.rs | |
| parent | 5ee6a65d7f095d5ba2d40e47bd97b2e65ed2443f (diff) | |
feat(remote): `list` includes open proposals
and filters out other branches in `prs/*` namespace
Diffstat (limited to 'src/git_remote_helper.rs')
| -rw-r--r-- | src/git_remote_helper.rs | 100 |
1 files changed, 95 insertions, 5 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs index a930617..f851c90 100644 --- a/src/git_remote_helper.rs +++ b/src/git_remote_helper.rs | |||
| @@ -15,17 +15,25 @@ use std::{ | |||
| 15 | use anyhow::{bail, Context, Result}; | 15 | use anyhow::{bail, Context, Result}; |
| 16 | use auth_git2::GitAuthenticator; | 16 | use auth_git2::GitAuthenticator; |
| 17 | use client::{ | 17 | use client::{ |
| 18 | consolidate_fetch_reports, get_repo_ref_from_cache, get_state_from_cache, sign_event, Connect, | 18 | consolidate_fetch_reports, get_events_from_cache, get_repo_ref_from_cache, |
| 19 | STATE_KIND, | 19 | get_state_from_cache, sign_event, Connect, STATE_KIND, |
| 20 | }; | 20 | }; |
| 21 | use git::RepoActions; | 21 | use git::RepoActions; |
| 22 | use git2::{Oid, Repository}; | 22 | use git2::{Oid, Repository}; |
| 23 | use nostr::nips::nip01::Coordinate; | 23 | use nostr::nips::nip01::Coordinate; |
| 24 | use nostr_sdk::{hashes::sha1::Hash as Sha1Hash, EventBuilder, PublicKey, Tag, Url}; | 24 | use nostr_sdk::{ |
| 25 | hashes::sha1::Hash as Sha1Hash, Event, EventBuilder, EventId, Kind, PublicKey, Tag, Url, | ||
| 26 | }; | ||
| 25 | use nostr_signer::NostrSigner; | 27 | use nostr_signer::NostrSigner; |
| 26 | use repo_ref::RepoRef; | 28 | use repo_ref::RepoRef; |
| 27 | use repo_state::RepoState; | 29 | use repo_state::RepoState; |
| 28 | use sub_commands::send::send_events; | 30 | use sub_commands::{ |
| 31 | list::{ | ||
| 32 | get_all_proposal_patch_events_from_cache, get_commit_id_from_patch, | ||
| 33 | get_most_recent_patch_with_ancestors, get_proposals_and_revisions_from_cache, status_kinds, | ||
| 34 | }, | ||
| 35 | send::{event_is_revision_root, event_to_cover_letter, send_events}, | ||
| 36 | }; | ||
| 29 | 37 | ||
| 30 | #[cfg(not(test))] | 38 | #[cfg(not(test))] |
| 31 | use crate::client::Client; | 39 | use crate::client::Client; |
| @@ -231,7 +239,7 @@ async fn list( | |||
| 231 | 239 | ||
| 232 | let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server)?; | 240 | let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server)?; |
| 233 | 241 | ||
| 234 | let state = if let Some(nostr_state) = nostr_state { | 242 | let mut state = if let Some(nostr_state) = nostr_state { |
| 235 | for (name, value) in &nostr_state.state { | 243 | for (name, value) in &nostr_state.state { |
| 236 | for (url, remote_state) in &remote_states { | 244 | for (url, remote_state) in &remote_states { |
| 237 | let remote_name = get_short_git_server_name(git_repo, url); | 245 | let remote_name = get_short_git_server_name(git_repo, url); |
| @@ -272,6 +280,27 @@ async fn list( | |||
| 272 | .clone() | 280 | .clone() |
| 273 | }; | 281 | }; |
| 274 | 282 | ||
| 283 | state.retain(|k, _| !k.starts_with("refs/heads/prs/")); | ||
| 284 | |||
| 285 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | ||
| 286 | |||
| 287 | for (_, (proposal, patches)) in open_proposals { | ||
| 288 | if let Ok(cl) = event_to_cover_letter(&proposal) { | ||
| 289 | if let Ok(branch_name) = cl.get_branch_name() { | ||
| 290 | if let Some(patch) = patches.first() { | ||
| 291 | // TODO this isn't resilient because the commit id stated may not be correct | ||
| 292 | // we will need to check whether the commit id exists in the repo or apply the | ||
| 293 | // proposal and each patch to check | ||
| 294 | if let Ok(commit_id) = get_commit_id_from_patch(patch) { | ||
| 295 | state.insert(branch_name, commit_id); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | // TODO 'for push' should we check with the git servers to see if any of them | ||
| 303 | // allow push from the user? | ||
| 275 | for (name, value) in state { | 304 | for (name, value) in state { |
| 276 | if value.starts_with("ref: ") { | 305 | if value.starts_with("ref: ") { |
| 277 | if !for_push { | 306 | if !for_push { |
| @@ -341,6 +370,67 @@ fn get_ahead_behind( | |||
| 341 | git_repo.get_commits_ahead_behind(&base, &latest) | 370 | git_repo.get_commits_ahead_behind(&base, &latest) |
| 342 | } | 371 | } |
| 343 | 372 | ||
| 373 | async fn get_open_proposals( | ||
| 374 | git_repo: &Repo, | ||
| 375 | repo_ref: &RepoRef, | ||
| 376 | ) -> Result<HashMap<EventId, (Event, Vec<Event>)>> { | ||
| 377 | let git_repo_path = git_repo.get_path()?; | ||
| 378 | let proposals: Vec<nostr::Event> = | ||
| 379 | get_proposals_and_revisions_from_cache(git_repo_path, repo_ref.coordinates()) | ||
| 380 | .await? | ||
| 381 | .iter() | ||
| 382 | .filter(|e| !event_is_revision_root(e)) | ||
| 383 | .cloned() | ||
| 384 | .collect(); | ||
| 385 | |||
| 386 | let statuses: Vec<nostr::Event> = { | ||
| 387 | let mut statuses = get_events_from_cache( | ||
| 388 | git_repo_path, | ||
| 389 | vec![ | ||
| 390 | nostr::Filter::default() | ||
| 391 | .kinds(status_kinds().clone()) | ||
| 392 | .events(proposals.iter().map(nostr::Event::id)), | ||
| 393 | ], | ||
| 394 | ) | ||
| 395 | .await?; | ||
| 396 | statuses.sort_by_key(|e| e.created_at); | ||
| 397 | statuses.reverse(); | ||
| 398 | statuses | ||
| 399 | }; | ||
| 400 | let mut open_proposals = HashMap::new(); | ||
| 401 | |||
| 402 | for proposal in proposals { | ||
| 403 | let status = if let Some(e) = statuses | ||
| 404 | .iter() | ||
| 405 | .filter(|e| { | ||
| 406 | status_kinds().contains(&e.kind()) | ||
| 407 | && e.iter_tags() | ||
| 408 | .any(|t| t.as_vec()[1].eq(&proposal.id.to_string())) | ||
| 409 | }) | ||
| 410 | .collect::<Vec<&nostr::Event>>() | ||
| 411 | .first() | ||
| 412 | { | ||
| 413 | e.kind() | ||
| 414 | } else { | ||
| 415 | Kind::GitStatusOpen | ||
| 416 | }; | ||
| 417 | if status.eq(&Kind::GitStatusOpen) { | ||
| 418 | if let Ok(commits_events) = | ||
| 419 | get_all_proposal_patch_events_from_cache(git_repo_path, repo_ref, &proposal.id) | ||
| 420 | .await | ||
| 421 | { | ||
| 422 | if let Ok(most_recent_proposal_patch_chain) = | ||
| 423 | get_most_recent_patch_with_ancestors(commits_events.clone()) | ||
| 424 | { | ||
| 425 | open_proposals | ||
| 426 | .insert(proposal.id(), (proposal, most_recent_proposal_patch_chain)); | ||
| 427 | } | ||
| 428 | } | ||
| 429 | } | ||
| 430 | } | ||
| 431 | Ok(open_proposals) | ||
| 432 | } | ||
| 433 | |||
| 344 | fn fetch(git_repo: &Repository, repo_ref: &RepoRef, stdin: &Stdin, oid: &str) -> Result<()> { | 434 | fn fetch(git_repo: &Repository, repo_ref: &RepoRef, stdin: &Stdin, oid: &str) -> Result<()> { |
| 345 | let oids = get_oids_from_fetch_batch(stdin, oid)?; | 435 | let oids = get_oids_from_fetch_batch(stdin, oid)?; |
| 346 | 436 | ||