upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bin/ngit
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/ngit')
-rw-r--r--src/bin/ngit/sub_commands/list.rs129
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 @@
1use std::{io::Write, ops::Add}; 1use std::{collections::HashSet, io::Write, ops::Add};
2 2
3use anyhow::{Context, Result, bail}; 3use anyhow::{Context, Result, bail};
4use ngit::{ 4use 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};
14use nostr_sdk::Kind; 16use 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
769fn 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
742fn launch_git_am_with_patches(mut patches: Vec<nostr::Event>) -> Result<()> { 819fn 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