diff options
Diffstat (limited to 'src/bin/ngit/sub_commands')
| -rw-r--r-- | src/bin/ngit/sub_commands/list.rs | 129 |
1 files changed, 103 insertions, 26 deletions
diff --git a/src/bin/ngit/sub_commands/list.rs b/src/bin/ngit/sub_commands/list.rs index 0083c91..2de3151 100644 --- a/src/bin/ngit/sub_commands/list.rs +++ b/src/bin/ngit/sub_commands/list.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | use std::{io::Write, ops::Add}; | 1 | use std::{collections::HashSet, io::Write, ops::Add}; |
| 2 | 2 | ||
| 3 | use anyhow::{Context, Result, bail}; | 3 | use anyhow::{Context, Result, bail}; |
| 4 | use ngit::{ | 4 | use ngit::{ |
| @@ -6,10 +6,12 @@ use ngit::{ | |||
| 6 | Params, get_all_proposal_patch_pr_pr_update_events_from_cache, | 6 | Params, get_all_proposal_patch_pr_pr_update_events_from_cache, |
| 7 | get_proposals_and_revisions_from_cache, | 7 | get_proposals_and_revisions_from_cache, |
| 8 | }, | 8 | }, |
| 9 | fetch::fetch_from_git_server, | ||
| 9 | git_events::{ | 10 | git_events::{ |
| 10 | KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE, get_commit_id_from_patch, | 11 | KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE, get_commit_id_from_patch, |
| 11 | get_pr_tip_event_or_most_recent_patch_with_ancestors, get_status, status_kinds, tag_value, | 12 | get_pr_tip_event_or_most_recent_patch_with_ancestors, get_status, status_kinds, tag_value, |
| 12 | }, | 13 | }, |
| 14 | repo_ref::{RepoRef, is_grasp_server_in_list}, | ||
| 13 | }; | 15 | }; |
| 14 | use nostr_sdk::Kind; | 16 | use nostr_sdk::Kind; |
| 15 | 17 | ||
| @@ -204,40 +206,65 @@ pub async fn launch() -> Result<()> { | |||
| 204 | .iter() | 206 | .iter() |
| 205 | .any(|e| [KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE].contains(&e.kind)) | 207 | .any(|e| [KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE].contains(&e.kind)) |
| 206 | { | 208 | { |
| 209 | let branch_name = cover_letter.get_branch_name_with_pr_prefix_and_shorthand_id()?; | ||
| 210 | let local_branch_tip = git_repo.get_tip_of_branch(&branch_name).ok(); | ||
| 211 | let proposal_tip_event = most_recent_proposal_patch_chain_or_pr_or_pr_update | ||
| 212 | .first() | ||
| 213 | .context("most_recent_proposal_patch_chain_or_pr_or_pr_update will always contain a event with c tag")?; | ||
| 214 | let proposal_tip = tag_value(proposal_tip_event, "c")?; | ||
| 215 | |||
| 207 | match Interactor::default().choice( | 216 | match Interactor::default().choice( |
| 208 | PromptChoiceParms::default() | 217 | PromptChoiceParms::default() |
| 209 | .with_prompt( | ||
| 210 | "this is new PR event kind which isn't supported in `ngit list` yet", | ||
| 211 | ) | ||
| 212 | .with_default(0) | 218 | .with_default(0) |
| 213 | .with_choices( | 219 | .with_choices(vec![ |
| 214 | if [Kind::GitStatusOpen, Kind::GitStatusDraft].contains(&selected_status) | 220 | if let Some(local_branch_tip) = local_branch_tip { |
| 215 | && git_repo | 221 | if local_branch_tip.to_string() == proposal_tip { |
| 216 | .get_first_nostr_remote_when_in_ngit_binary() | 222 | format!("checkout up-to-date proposal branch '{branch_name}'") |
| 217 | .await | 223 | } else { |
| 218 | .is_ok_and(|r| r.is_some()) | 224 | format!("checkout proposal branch and pull changes '{branch_name}'") |
| 219 | { | 225 | } |
| 220 | vec![ | ||
| 221 | format!( | ||
| 222 | "I'll manually checkout the proposal at remote branch '{}'", | ||
| 223 | cover_letter | ||
| 224 | .get_branch_name_with_pr_prefix_and_shorthand_id() | ||
| 225 | .unwrap() | ||
| 226 | ), | ||
| 227 | // TODO fetch oids and follow similar logic for dealing with | ||
| 228 | // conflcts as with patches below | ||
| 229 | "back to proposals".to_string(), | ||
| 230 | ] | ||
| 231 | } else { | 226 | } else { |
| 232 | vec!["back to proposals".to_string()] | 227 | format!("create and checkout as branch '{branch_name}'") |
| 233 | }, | 228 | }, |
| 234 | ), | 229 | "back to proposals".to_string(), |
| 230 | ]), | ||
| 235 | )? { | 231 | )? { |
| 236 | 0 => continue, | 232 | 0 => { |
| 233 | if let Some(local_branch_tip) = local_branch_tip { | ||
| 234 | git_repo | ||
| 235 | .checkout(&branch_name) | ||
| 236 | .context("cannot checkout existing proposal branch")?; | ||
| 237 | if local_branch_tip.to_string() == proposal_tip { | ||
| 238 | println!("checked out up-to-date proposal branch '{branch_name}'"); | ||
| 239 | return Ok(()); | ||
| 240 | } | ||
| 241 | if git_repo.does_commit_exist(&proposal_tip)? { | ||
| 242 | println!("checked out proposal branch and updated tip '{branch_name}'"); | ||
| 243 | return Ok(()); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | fetch_oid_for_from_servers_for_pr( | ||
| 247 | &proposal_tip, | ||
| 248 | &git_repo, | ||
| 249 | &repo_ref, | ||
| 250 | proposal_tip_event, | ||
| 251 | )?; | ||
| 252 | git_repo.create_branch_at_commit(&branch_name, &proposal_tip)?; | ||
| 253 | git_repo.checkout(&branch_name)?; | ||
| 254 | if local_branch_tip.is_some() { | ||
| 255 | println!("created and checked out proposal branch '{branch_name}'"); | ||
| 256 | } else { | ||
| 257 | println!("checked out proposal branch and pulled updates '{branch_name}'"); | ||
| 258 | } | ||
| 259 | return Ok(()); | ||
| 260 | } | ||
| 261 | 1 => { | ||
| 262 | continue; | ||
| 263 | } | ||
| 237 | _ => { | 264 | _ => { |
| 238 | bail!("unexpected choice") | 265 | bail!("unexpected choice") |
| 239 | } | 266 | } |
| 240 | }; | 267 | } |
| 241 | } | 268 | } |
| 242 | 269 | ||
| 243 | let binding_patch_text_ref = format!( | 270 | let binding_patch_text_ref = format!( |
| @@ -739,6 +766,56 @@ pub async fn launch() -> Result<()> { | |||
| 739 | } | 766 | } |
| 740 | } | 767 | } |
| 741 | 768 | ||
| 769 | fn fetch_oid_for_from_servers_for_pr( | ||
| 770 | oid: &str, | ||
| 771 | git_repo: &Repo, | ||
| 772 | repo_ref: &RepoRef, | ||
| 773 | pr_or_pr_update_event: &nostr::Event, | ||
| 774 | ) -> Result<()> { | ||
| 775 | let git_servers = { | ||
| 776 | let mut seen: HashSet<String> = HashSet::new(); | ||
| 777 | let mut out: Vec<String> = vec![]; | ||
| 778 | for tag in pr_or_pr_update_event.tags.as_slice() { | ||
| 779 | if tag.kind().eq(&nostr::event::TagKind::Clone) { | ||
| 780 | for clone_url in tag.as_slice().iter().skip(1) { | ||
| 781 | seen.insert(clone_url.clone()); | ||
| 782 | } | ||
| 783 | } | ||
| 784 | } | ||
| 785 | for server in &repo_ref.git_server { | ||
| 786 | if seen.insert(server.clone()) { | ||
| 787 | out.push(server.clone()); | ||
| 788 | } | ||
| 789 | } | ||
| 790 | out | ||
| 791 | }; | ||
| 792 | |||
| 793 | let mut errors = vec![]; | ||
| 794 | let term = console::Term::stderr(); | ||
| 795 | |||
| 796 | for git_server_url in &git_servers { | ||
| 797 | if let Err(error) = fetch_from_git_server( | ||
| 798 | git_repo, | ||
| 799 | &[oid.to_string()], | ||
| 800 | git_server_url, | ||
| 801 | &repo_ref.to_nostr_git_url(&None), | ||
| 802 | &term, | ||
| 803 | is_grasp_server_in_list(git_server_url, &repo_ref.grasp_servers()), | ||
| 804 | ) { | ||
| 805 | errors.push(error); | ||
| 806 | } else { | ||
| 807 | println!("fetched proposal git data from {git_server_url}"); | ||
| 808 | break; | ||
| 809 | } | ||
| 810 | } | ||
| 811 | if !git_repo.does_commit_exist(oid)? { | ||
| 812 | bail!( | ||
| 813 | "cannot find proposal git data from proposal git server hint or repository git servers" | ||
| 814 | ) | ||
| 815 | } | ||
| 816 | Ok(()) | ||
| 817 | } | ||
| 818 | |||
| 742 | fn launch_git_am_with_patches(mut patches: Vec<nostr::Event>) -> Result<()> { | 819 | fn launch_git_am_with_patches(mut patches: Vec<nostr::Event>) -> Result<()> { |
| 743 | println!("applying to current branch with `git am`"); | 820 | println!("applying to current branch with `git am`"); |
| 744 | // TODO: add PATCH x/n to appended patches | 821 | // TODO: add PATCH x/n to appended patches |