diff options
| -rw-r--r-- | src/git_remote_helper.rs | 73 | ||||
| -rw-r--r-- | 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::{ | |||
| 31 | list::{ | 31 | list::{ |
| 32 | get_all_proposal_patch_events_from_cache, get_commit_id_from_patch, | 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, | 33 | get_most_recent_patch_with_ancestors, get_proposals_and_revisions_from_cache, status_kinds, |
| 34 | tag_value, | ||
| 34 | }, | 35 | }, |
| 35 | send::{event_is_revision_root, event_to_cover_letter, send_events}, | 36 | send::{event_is_revision_root, event_to_cover_letter, send_events}, |
| 36 | }; | 37 | }; |
| @@ -104,7 +105,7 @@ async fn main() -> Result<()> { | |||
| 104 | println!("unsupported"); | 105 | println!("unsupported"); |
| 105 | } | 106 | } |
| 106 | ["fetch", oid, refstr] => { | 107 | ["fetch", oid, refstr] => { |
| 107 | fetch(&git_repo, &repo_ref, &stdin, oid, refstr)?; | 108 | fetch(&git_repo, &repo_ref, &stdin, oid, refstr).await?; |
| 108 | } | 109 | } |
| 109 | ["push", refspec] => { | 110 | ["push", refspec] => { |
| 110 | push( | 111 | push( |
| @@ -431,14 +432,14 @@ async fn get_open_proposals( | |||
| 431 | Ok(open_proposals) | 432 | Ok(open_proposals) |
| 432 | } | 433 | } |
| 433 | 434 | ||
| 434 | fn fetch( | 435 | async fn fetch( |
| 435 | git_repo: &Repo, | 436 | git_repo: &Repo, |
| 436 | repo_ref: &RepoRef, | 437 | repo_ref: &RepoRef, |
| 437 | stdin: &Stdin, | 438 | stdin: &Stdin, |
| 438 | oid: &str, | 439 | oid: &str, |
| 439 | refstr: &str, | 440 | refstr: &str, |
| 440 | ) -> Result<()> { | 441 | ) -> Result<()> { |
| 441 | let fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; | 442 | let mut fetch_batch = get_oids_from_fetch_batch(stdin, oid, refstr)?; |
| 442 | 443 | ||
| 443 | let oids_from_git_servers = fetch_batch | 444 | let oids_from_git_servers = fetch_batch |
| 444 | .iter() | 445 | .iter() |
| @@ -465,20 +466,64 @@ fn fetch( | |||
| 465 | )?; | 466 | )?; |
| 466 | errors.insert(short_name.to_string(), e); | 467 | errors.insert(short_name.to_string(), e); |
| 467 | } else { | 468 | } else { |
| 468 | term.flush()?; | 469 | break; |
| 469 | println!(); | ||
| 470 | return Ok(()); | ||
| 471 | } | 470 | } |
| 472 | } | 471 | } |
| 472 | |||
| 473 | if oids_from_git_servers | ||
| 474 | .iter() | ||
| 475 | .any(|oid| !git_repo.does_commit_exist(oid).unwrap()) | ||
| 476 | { | ||
| 477 | bail!( | ||
| 478 | "failed to fetch objects in nostr state event from:\r\n{}", | ||
| 479 | errors | ||
| 480 | .iter() | ||
| 481 | .map(|(url, error)| format!("{url}: {error}")) | ||
| 482 | .collect::<Vec<String>>() | ||
| 483 | .join("\r\n") | ||
| 484 | ); | ||
| 485 | } | ||
| 486 | |||
| 487 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | ||
| 488 | |||
| 489 | fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/prs/")); | ||
| 490 | |||
| 491 | for (refstr, oid) in fetch_batch { | ||
| 492 | if let Some((_, (_, patches))) = open_proposals.iter().find(|(_, (proposal, _))| { | ||
| 493 | if let Ok(cl) = event_to_cover_letter(proposal) { | ||
| 494 | if let Ok(branch_name) = cl.get_branch_name() { | ||
| 495 | branch_name.eq(&refstr.replace("refs/heads/", "")) | ||
| 496 | } else { | ||
| 497 | false | ||
| 498 | } | ||
| 499 | } else { | ||
| 500 | false | ||
| 501 | } | ||
| 502 | }) { | ||
| 503 | if !git_repo.does_commit_exist(&oid)? { | ||
| 504 | let mut patches_ancestor_first = patches.clone(); | ||
| 505 | patches_ancestor_first.reverse(); | ||
| 506 | if git_repo.does_commit_exist(&tag_value( | ||
| 507 | patches_ancestor_first.first().unwrap(), | ||
| 508 | "parent-commit", | ||
| 509 | )?)? { | ||
| 510 | for patch in &patches_ancestor_first { | ||
| 511 | git_repo.create_commit_from_patch(patch)?; | ||
| 512 | } | ||
| 513 | } else { | ||
| 514 | term.write_line( | ||
| 515 | format!("WARNING: cannot find parent commit for {refstr}").as_str(), | ||
| 516 | )?; | ||
| 517 | } | ||
| 518 | } | ||
| 519 | } else { | ||
| 520 | term.write_line(format!("WARNING: cannot find proposal for {refstr}").as_str())?; | ||
| 521 | } | ||
| 522 | } | ||
| 523 | |||
| 473 | term.flush()?; | 524 | term.flush()?; |
| 474 | bail!( | 525 | println!(); |
| 475 | "failed to fetch objects in nostr state event from:\r\n{}", | 526 | Ok(()) |
| 476 | errors | ||
| 477 | .iter() | ||
| 478 | .map(|(url, error)| format!("{url}: {error}")) | ||
| 479 | .collect::<Vec<String>>() | ||
| 480 | .join("\r\n") | ||
| 481 | ); | ||
| 482 | } | 527 | } |
| 483 | 528 | ||
| 484 | fn fetch_from_git_server( | 529 | 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)> | |||
| 154 | Ok((state_event.clone(), source_git_repo)) | 154 | Ok((state_event.clone(), source_git_repo)) |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | async fn prep_source_repo_and_events_including_proposals() | ||
| 158 | -> Result<(Vec<nostr::Event>, GitTestRepo)> { | ||
| 159 | let (state_event, source_git_repo) = generate_repo_with_state_event().await?; | ||
| 160 | let source_path = source_git_repo.dir.to_str().unwrap().to_string(); | ||
| 161 | |||
| 162 | let events = vec![ | ||
| 163 | generate_test_key_1_metadata_event("fred"), | ||
| 164 | generate_test_key_1_relay_list_event(), | ||
| 165 | generate_repo_ref_event_with_git_server(vec![source_path.to_string()]), | ||
| 166 | state_event, | ||
| 167 | ]; | ||
| 168 | // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57) | ||
| 169 | let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( | ||
| 170 | Relay::new(8051, None, None), | ||
| 171 | Relay::new(8052, None, None), | ||
| 172 | Relay::new(8053, None, None), | ||
| 173 | Relay::new(8055, None, None), | ||
| 174 | Relay::new(8056, None, None), | ||
| 175 | Relay::new(8057, None, None), | ||
| 176 | ); | ||
| 177 | r51.events = events.clone(); | ||
| 178 | r55.events = events; | ||
| 179 | |||
| 180 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 181 | cli_tester_create_proposals()?; | ||
| 182 | for p in [51, 52, 53, 55, 56, 57] { | ||
| 183 | relay::shutdown_relay(8000 + p)?; | ||
| 184 | } | ||
| 185 | Ok(()) | ||
| 186 | }); | ||
| 187 | // launch relays | ||
| 188 | let _ = join!( | ||
| 189 | r51.listen_until_close(), | ||
| 190 | r52.listen_until_close(), | ||
| 191 | r53.listen_until_close(), | ||
| 192 | r55.listen_until_close(), | ||
| 193 | r56.listen_until_close(), | ||
| 194 | r57.listen_until_close(), | ||
| 195 | ); | ||
| 196 | cli_tester_handle.join().unwrap()?; | ||
| 197 | |||
| 198 | Ok((r55.events, source_git_repo)) | ||
| 199 | } | ||
| 200 | |||
| 157 | mod initially_runs_fetch { | 201 | mod initially_runs_fetch { |
| 158 | 202 | ||
| 159 | use super::*; | 203 | use super::*; |
| @@ -689,6 +733,62 @@ mod fetch { | |||
| 689 | Ok(()) | 733 | Ok(()) |
| 690 | } | 734 | } |
| 691 | } | 735 | } |
| 736 | |||
| 737 | #[tokio::test] | ||
| 738 | #[serial] | ||
| 739 | async fn creates_commits_from_open_proposal_with_no_warngins_printed() -> Result<()> { | ||
| 740 | let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; | ||
| 741 | let source_path = source_git_repo.dir.to_str().unwrap().to_string(); | ||
| 742 | |||
| 743 | let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( | ||
| 744 | Relay::new(8051, None, None), | ||
| 745 | Relay::new(8052, None, None), | ||
| 746 | Relay::new(8053, None, None), | ||
| 747 | Relay::new(8055, None, None), | ||
| 748 | Relay::new(8056, None, None), | ||
| 749 | Relay::new(8057, None, None), | ||
| 750 | ); | ||
| 751 | r51.events = events.clone(); | ||
| 752 | r55.events = events.clone(); | ||
| 753 | |||
| 754 | let git_repo = prep_git_repo()?; | ||
| 755 | |||
| 756 | let cli_tester_handle = std::thread::spawn(move || -> Result<()> { | ||
| 757 | let branch_name = get_proposal_branch_name_from_events(&events, FEATURE_BRANCH_NAME_1)?; | ||
| 758 | let proposal_tip = cli_tester_create_proposal_branches_ready_to_send()? | ||
| 759 | .get_tip_of_local_branch(FEATURE_BRANCH_NAME_1)?; | ||
| 760 | |||
| 761 | assert!(git_repo.git_repo.find_commit(proposal_tip).is_err()); | ||
| 762 | |||
| 763 | let mut p = cli_tester_after_fetch(&git_repo)?; | ||
| 764 | p.send_line(format!("fetch {proposal_tip} refs/heads/{branch_name}").as_str())?; | ||
| 765 | p.send_line("")?; | ||
| 766 | p.expect(format!("fetching from {source_path}...\r\n").as_str())?; | ||
| 767 | // expect no errors | ||
| 768 | p.expect_after_whitespace("\r\n")?; | ||
| 769 | p.exit()?; | ||
| 770 | for p in [51, 52, 53, 55, 56, 57] { | ||
| 771 | relay::shutdown_relay(8000 + p)?; | ||
| 772 | } | ||
| 773 | |||
| 774 | assert!(git_repo.git_repo.find_commit(proposal_tip).is_ok()); | ||
| 775 | |||
| 776 | Ok(()) | ||
| 777 | }); | ||
| 778 | // launch relays | ||
| 779 | let _ = join!( | ||
| 780 | r51.listen_until_close(), | ||
| 781 | r52.listen_until_close(), | ||
| 782 | r53.listen_until_close(), | ||
| 783 | r55.listen_until_close(), | ||
| 784 | r56.listen_until_close(), | ||
| 785 | r57.listen_until_close(), | ||
| 786 | ); | ||
| 787 | |||
| 788 | cli_tester_handle.join().unwrap()?; | ||
| 789 | |||
| 790 | Ok(()) | ||
| 791 | } | ||
| 692 | } | 792 | } |
| 693 | 793 | ||
| 694 | mod push { | 794 | mod push { |