From 843a3c2dfebf661bd47f0a0faf2849cc660b7349 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 7 Aug 2024 10:20:48 +0100 Subject: feat(remote): `fetch` applies proposal commits that have been proposal tips returned by `list` can be found --- src/git_remote_helper.rs | 73 ++++++++++++++++++++++++++------- tests/git_remote_helper.rs | 100 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 14 deletions(-) diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs index d7363cf..4cafba1 100644 --- a/src/git_remote_helper.rs +++ b/src/git_remote_helper.rs @@ -31,6 +31,7 @@ use sub_commands::{ list::{ get_all_proposal_patch_events_from_cache, get_commit_id_from_patch, get_most_recent_patch_with_ancestors, get_proposals_and_revisions_from_cache, status_kinds, + tag_value, }, send::{event_is_revision_root, event_to_cover_letter, send_events}, }; @@ -104,7 +105,7 @@ async fn main() -> Result<()> { println!("unsupported"); } ["fetch", oid, refstr] => { - fetch(&git_repo, &repo_ref, &stdin, oid, refstr)?; + fetch(&git_repo, &repo_ref, &stdin, oid, refstr).await?; } ["push", refspec] => { push( @@ -431,14 +432,14 @@ async fn get_open_proposals( Ok(open_proposals) } -fn fetch( +async fn fetch( git_repo: &Repo, repo_ref: &RepoRef, stdin: &Stdin, oid: &str, refstr: &str, ) -> Result<()> { - let fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; + let mut fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; let oids_from_git_servers = fetch_batch .iter() @@ -465,20 +466,64 @@ fn fetch( )?; errors.insert(short_name.to_string(), e); } else { - term.flush()?; - println!(); - return Ok(()); + break; } } + + if oids_from_git_servers + .iter() + .any(|oid| !git_repo.does_commit_exist(oid).unwrap()) + { + bail!( + "failed to fetch objects in nostr state event from:\r\n{}", + errors + .iter() + .map(|(url, error)| format!("{url}: {error}")) + .collect::>() + .join("\r\n") + ); + } + + let open_proposals = get_open_proposals(git_repo, repo_ref).await?; + + fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/prs/")); + + for (refstr, oid) in fetch_batch { + if let Some((_, (_, patches))) = open_proposals.iter().find(|(_, (proposal, _))| { + if let Ok(cl) = event_to_cover_letter(proposal) { + if let Ok(branch_name) = cl.get_branch_name() { + branch_name.eq(&refstr.replace("refs/heads/", "")) + } else { + false + } + } else { + false + } + }) { + if !git_repo.does_commit_exist(&oid)? { + let mut patches_ancestor_first = patches.clone(); + patches_ancestor_first.reverse(); + if git_repo.does_commit_exist(&tag_value( + patches_ancestor_first.first().unwrap(), + "parent-commit", + )?)? { + for patch in &patches_ancestor_first { + git_repo.create_commit_from_patch(patch)?; + } + } else { + term.write_line( + format!("WARNING: cannot find parent commit for {refstr}").as_str(), + )?; + } + } + } else { + term.write_line(format!("WARNING: cannot find proposal for {refstr}").as_str())?; + } + } + term.flush()?; - bail!( - "failed to fetch objects in nostr state event from:\r\n{}", - errors - .iter() - .map(|(url, error)| format!("{url}: {error}")) - .collect::>() - .join("\r\n") - ); + println!(); + Ok(()) } fn fetch_from_git_server( diff --git a/tests/git_remote_helper.rs b/tests/git_remote_helper.rs index bfe0e25..66a0be5 100644 --- a/tests/git_remote_helper.rs +++ b/tests/git_remote_helper.rs @@ -154,6 +154,50 @@ async fn generate_repo_with_state_event() -> Result<(nostr::Event, GitTestRepo)> Ok((state_event.clone(), source_git_repo)) } +async fn prep_source_repo_and_events_including_proposals() +-> Result<(Vec, GitTestRepo)> { + let (state_event, source_git_repo) = generate_repo_with_state_event().await?; + let source_path = source_git_repo.dir.to_str().unwrap().to_string(); + + let events = vec![ + generate_test_key_1_metadata_event("fred"), + generate_test_key_1_relay_list_event(), + generate_repo_ref_event_with_git_server(vec![source_path.to_string()]), + state_event, + ]; + // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) + let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( + Relay::new(8051, None, None), + Relay::new(8052, None, None), + Relay::new(8053, None, None), + Relay::new(8055, None, None), + Relay::new(8056, None, None), + Relay::new(8057, None, None), + ); + r51.events = events.clone(); + r55.events = events; + + let cli_tester_handle = std::thread::spawn(move || -> Result<()> { + cli_tester_create_proposals()?; + for p in [51, 52, 53, 55, 56, 57] { + relay::shutdown_relay(8000 + p)?; + } + Ok(()) + }); + // launch relays + let _ = join!( + r51.listen_until_close(), + r52.listen_until_close(), + r53.listen_until_close(), + r55.listen_until_close(), + r56.listen_until_close(), + r57.listen_until_close(), + ); + cli_tester_handle.join().unwrap()?; + + Ok((r55.events, source_git_repo)) +} + mod initially_runs_fetch { use super::*; @@ -689,6 +733,62 @@ mod fetch { Ok(()) } } + + #[tokio::test] + #[serial] + async fn creates_commits_from_open_proposal_with_no_warngins_printed() -> Result<()> { + let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; + let source_path = source_git_repo.dir.to_str().unwrap().to_string(); + + let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( + Relay::new(8051, None, None), + Relay::new(8052, None, None), + Relay::new(8053, None, None), + Relay::new(8055, None, None), + Relay::new(8056, None, None), + Relay::new(8057, None, None), + ); + r51.events = events.clone(); + r55.events = events.clone(); + + let git_repo = prep_git_repo()?; + + let cli_tester_handle = std::thread::spawn(move || -> Result<()> { + let branch_name = get_proposal_branch_name_from_events(&events, FEATURE_BRANCH_NAME_1)?; + let proposal_tip = cli_tester_create_proposal_branches_ready_to_send()? + .get_tip_of_local_branch(FEATURE_BRANCH_NAME_1)?; + + assert!(git_repo.git_repo.find_commit(proposal_tip).is_err()); + + let mut p = cli_tester_after_fetch(&git_repo)?; + p.send_line(format!("fetch {proposal_tip} refs/heads/{branch_name}").as_str())?; + p.send_line("")?; + p.expect(format!("fetching from {source_path}...\r\n").as_str())?; + // expect no errors + p.expect_after_whitespace("\r\n")?; + p.exit()?; + for p in [51, 52, 53, 55, 56, 57] { + relay::shutdown_relay(8000 + p)?; + } + + assert!(git_repo.git_repo.find_commit(proposal_tip).is_ok()); + + Ok(()) + }); + // launch relays + let _ = join!( + r51.listen_until_close(), + r52.listen_until_close(), + r53.listen_until_close(), + r55.listen_until_close(), + r56.listen_until_close(), + r57.listen_until_close(), + ); + + cli_tester_handle.join().unwrap()?; + + Ok(()) + } } mod push { -- cgit v1.2.3