diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-09 08:25:43 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2024-08-09 08:25:43 +0100 |
| commit | d1f1963a34ec66356e1b66c1fce937391dd126c3 (patch) | |
| tree | a3552831489013e5b3d31f5dce6b51403e62659f | |
| parent | a556464452789dc72cb9b0bff8e9ba6addc6639a (diff) | |
feat(remote): remove pr id postfix for authors
remove the (<short id>) post fix for remote proposal branches when
the current user is the author
this enables pushing new proposals without having to change the
upstream branch in a way that remote helpers weren't designed to do
| -rw-r--r-- | src/git_remote_helper.rs | 90 | ||||
| -rw-r--r-- | tests/git_remote_helper.rs | 29 |
2 files changed, 76 insertions, 43 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs index be230b1..ff053f6 100644 --- a/src/git_remote_helper.rs +++ b/src/git_remote_helper.rs | |||
| @@ -287,10 +287,19 @@ async fn list( | |||
| 287 | state.retain(|k, _| !k.starts_with("refs/heads/prs/")); | 287 | state.retain(|k, _| !k.starts_with("refs/heads/prs/")); |
| 288 | 288 | ||
| 289 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | 289 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; |
| 290 | 290 | let current_user = get_curent_user(git_repo)?; | |
| 291 | for (_, (proposal, patches)) in open_proposals { | 291 | for (_, (proposal, patches)) in open_proposals { |
| 292 | if let Ok(cl) = event_to_cover_letter(&proposal) { | 292 | if let Ok(cl) = event_to_cover_letter(&proposal) { |
| 293 | if let Ok(branch_name) = cl.get_branch_name() { | 293 | if let Ok(mut branch_name) = cl.get_branch_name() { |
| 294 | branch_name = if let Some(public_key) = current_user { | ||
| 295 | if proposal.author().eq(&public_key) { | ||
| 296 | cl.branch_name.to_string() | ||
| 297 | } else { | ||
| 298 | branch_name | ||
| 299 | } | ||
| 300 | } else { | ||
| 301 | branch_name | ||
| 302 | }; | ||
| 294 | if let Some(patch) = patches.first() { | 303 | if let Some(patch) = patches.first() { |
| 295 | // TODO this isn't resilient because the commit id stated may not be correct | 304 | // TODO this isn't resilient because the commit id stated may not be correct |
| 296 | // we will need to check whether the commit id exists in the repo or apply the | 305 | // we will need to check whether the commit id exists in the repo or apply the |
| @@ -435,6 +444,20 @@ async fn get_open_proposals( | |||
| 435 | Ok(open_proposals) | 444 | Ok(open_proposals) |
| 436 | } | 445 | } |
| 437 | 446 | ||
| 447 | fn get_curent_user(git_repo: &Repo) -> Result<Option<PublicKey>> { | ||
| 448 | Ok( | ||
| 449 | if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { | ||
| 450 | if let Ok(public_key) = PublicKey::parse(npub) { | ||
| 451 | Some(public_key) | ||
| 452 | } else { | ||
| 453 | None | ||
| 454 | } | ||
| 455 | } else { | ||
| 456 | None | ||
| 457 | }, | ||
| 458 | ) | ||
| 459 | } | ||
| 460 | |||
| 438 | async fn fetch( | 461 | async fn fetch( |
| 439 | git_repo: &Repo, | 462 | git_repo: &Repo, |
| 440 | repo_ref: &RepoRef, | 463 | repo_ref: &RepoRef, |
| @@ -487,32 +510,36 @@ async fn fetch( | |||
| 487 | ); | 510 | ); |
| 488 | } | 511 | } |
| 489 | 512 | ||
| 490 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | ||
| 491 | |||
| 492 | fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/prs/")); | 513 | fetch_batch.retain(|refstr, _| refstr.contains("refs/heads/prs/")); |
| 493 | 514 | ||
| 494 | for (refstr, oid) in fetch_batch { | 515 | if !fetch_batch.is_empty() { |
| 495 | if let Some((_, (_, patches))) = | 516 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; |
| 496 | find_proposal_and_patches_by_branch_name(&refstr, &open_proposals) | 517 | |
| 497 | { | 518 | let current_user = get_curent_user(git_repo)?; |
| 498 | if !git_repo.does_commit_exist(&oid)? { | 519 | |
| 499 | let mut patches_ancestor_first = patches.clone(); | 520 | for (refstr, oid) in fetch_batch { |
| 500 | patches_ancestor_first.reverse(); | 521 | if let Some((_, (_, patches))) = |
| 501 | if git_repo.does_commit_exist(&tag_value( | 522 | find_proposal_and_patches_by_branch_name(&refstr, &open_proposals, ¤t_user) |
| 502 | patches_ancestor_first.first().unwrap(), | 523 | { |
| 503 | "parent-commit", | 524 | if !git_repo.does_commit_exist(&oid)? { |
| 504 | )?)? { | 525 | let mut patches_ancestor_first = patches.clone(); |
| 505 | for patch in &patches_ancestor_first { | 526 | patches_ancestor_first.reverse(); |
| 506 | git_repo.create_commit_from_patch(patch)?; | 527 | if git_repo.does_commit_exist(&tag_value( |
| 528 | patches_ancestor_first.first().unwrap(), | ||
| 529 | "parent-commit", | ||
| 530 | )?)? { | ||
| 531 | for patch in &patches_ancestor_first { | ||
| 532 | git_repo.create_commit_from_patch(patch)?; | ||
| 533 | } | ||
| 534 | } else { | ||
| 535 | term.write_line( | ||
| 536 | format!("WARNING: cannot find parent commit for {refstr}").as_str(), | ||
| 537 | )?; | ||
| 507 | } | 538 | } |
| 508 | } else { | ||
| 509 | term.write_line( | ||
| 510 | format!("WARNING: cannot find parent commit for {refstr}").as_str(), | ||
| 511 | )?; | ||
| 512 | } | 539 | } |
| 540 | } else { | ||
| 541 | term.write_line(format!("WARNING: cannot find proposal for {refstr}").as_str())?; | ||
| 513 | } | 542 | } |
| 514 | } else { | ||
| 515 | term.write_line(format!("WARNING: cannot find proposal for {refstr}").as_str())?; | ||
| 516 | } | 543 | } |
| 517 | } | 544 | } |
| 518 | 545 | ||
| @@ -524,10 +551,20 @@ async fn fetch( | |||
| 524 | fn find_proposal_and_patches_by_branch_name<'a>( | 551 | fn find_proposal_and_patches_by_branch_name<'a>( |
| 525 | refstr: &'a str, | 552 | refstr: &'a str, |
| 526 | open_proposals: &'a HashMap<EventId, (Event, Vec<Event>)>, | 553 | open_proposals: &'a HashMap<EventId, (Event, Vec<Event>)>, |
| 554 | current_user: &Option<PublicKey>, | ||
| 527 | ) -> Option<(&'a EventId, &'a (Event, Vec<Event>))> { | 555 | ) -> Option<(&'a EventId, &'a (Event, Vec<Event>))> { |
| 528 | open_proposals.iter().find(|(_, (proposal, _))| { | 556 | open_proposals.iter().find(|(_, (proposal, _))| { |
| 529 | if let Ok(cl) = event_to_cover_letter(proposal) { | 557 | if let Ok(cl) = event_to_cover_letter(proposal) { |
| 530 | if let Ok(branch_name) = cl.get_branch_name() { | 558 | if let Ok(mut branch_name) = cl.get_branch_name() { |
| 559 | branch_name = if let Some(public_key) = current_user { | ||
| 560 | if proposal.author().eq(public_key) { | ||
| 561 | cl.branch_name.to_string() | ||
| 562 | } else { | ||
| 563 | branch_name | ||
| 564 | } | ||
| 565 | } else { | ||
| 566 | branch_name | ||
| 567 | }; | ||
| 531 | branch_name.eq(&refstr.replace("refs/heads/", "")) | 568 | branch_name.eq(&refstr.replace("refs/heads/", "")) |
| 532 | } else { | 569 | } else { |
| 533 | false | 570 | false |
| @@ -652,18 +689,19 @@ async fn push( | |||
| 652 | let mut rejected_proposal_refspecs = vec![]; | 689 | let mut rejected_proposal_refspecs = vec![]; |
| 653 | if !proposal_refspecs.is_empty() { | 690 | if !proposal_refspecs.is_empty() { |
| 654 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; | 691 | let open_proposals = get_open_proposals(git_repo, repo_ref).await?; |
| 692 | let current_user = get_curent_user(git_repo)?; | ||
| 655 | 693 | ||
| 656 | for refspec in &proposal_refspecs { | 694 | for refspec in &proposal_refspecs { |
| 657 | let (from, to) = refspec_to_from_to(refspec).unwrap(); | 695 | let (from, to) = refspec_to_from_to(refspec).unwrap(); |
| 696 | let tip_of_pushed_branch = git_repo.get_commit_or_tip_of_reference(from)?; | ||
| 658 | 697 | ||
| 659 | if let Some((_, (proposal, patches))) = | 698 | if let Some((_, (proposal, patches))) = |
| 660 | find_proposal_and_patches_by_branch_name(to, &open_proposals) | 699 | find_proposal_and_patches_by_branch_name(to, &open_proposals, ¤t_user) |
| 661 | { | 700 | { |
| 662 | if [repo_ref.maintainers.clone(), vec![proposal.author()]] | 701 | if [repo_ref.maintainers.clone(), vec![proposal.author()]] |
| 663 | .concat() | 702 | .concat() |
| 664 | .contains(&user_ref.public_key) | 703 | .contains(&user_ref.public_key) |
| 665 | { | 704 | { |
| 666 | let tip_of_pushed_branch = git_repo.get_commit_or_tip_of_reference(from)?; | ||
| 667 | if refspec.starts_with('+') { | 705 | if refspec.starts_with('+') { |
| 668 | // force push | 706 | // force push |
| 669 | let (_, main_tip) = git_repo.get_main_or_master_branch()?; | 707 | let (_, main_tip) = git_repo.get_main_or_master_branch()?; |
diff --git a/tests/git_remote_helper.rs b/tests/git_remote_helper.rs index f768806..7cf6799 100644 --- a/tests/git_remote_helper.rs +++ b/tests/git_remote_helper.rs | |||
| @@ -28,15 +28,20 @@ fn get_nostr_remote_url() -> Result<String> { | |||
| 28 | 28 | ||
| 29 | fn prep_git_repo() -> Result<GitTestRepo> { | 29 | fn prep_git_repo() -> Result<GitTestRepo> { |
| 30 | let test_repo = GitTestRepo::without_repo_in_git_config(); | 30 | let test_repo = GitTestRepo::without_repo_in_git_config(); |
| 31 | set_git_nostr_login_config(&test_repo)?; | ||
| 32 | test_repo.add_remote(NOSTR_REMOTE_NAME, &get_nostr_remote_url()?)?; | ||
| 33 | test_repo.populate()?; | ||
| 34 | Ok(test_repo) | ||
| 35 | } | ||
| 36 | |||
| 37 | fn set_git_nostr_login_config(test_repo: &GitTestRepo) -> Result<()> { | ||
| 31 | let mut config = test_repo | 38 | let mut config = test_repo |
| 32 | .git_repo | 39 | .git_repo |
| 33 | .config() | 40 | .config() |
| 34 | .context("cannot open git config")?; | 41 | .context("cannot open git config")?; |
| 35 | config.set_str("nostr.nsec", TEST_KEY_1_NSEC)?; | 42 | config.set_str("nostr.nsec", TEST_KEY_2_NSEC)?; |
| 36 | config.set_str("nostr.npub", TEST_KEY_1_NPUB)?; | 43 | config.set_str("nostr.npub", TEST_KEY_2_NPUB)?; |
| 37 | test_repo.add_remote(NOSTR_REMOTE_NAME, &get_nostr_remote_url()?)?; | 44 | Ok(()) |
| 38 | test_repo.populate()?; | ||
| 39 | Ok(test_repo) | ||
| 40 | } | 45 | } |
| 41 | 46 | ||
| 42 | fn clone_git_repo_with_nostr_url() -> Result<GitTestRepo> { | 47 | fn clone_git_repo_with_nostr_url() -> Result<GitTestRepo> { |
| @@ -45,23 +50,13 @@ fn clone_git_repo_with_nostr_url() -> Result<GitTestRepo> { | |||
| 45 | CliTester::new_git_with_remote_helper_from_dir(&path, ["clone", &get_nostr_remote_url()?, "."]) | 50 | CliTester::new_git_with_remote_helper_from_dir(&path, ["clone", &get_nostr_remote_url()?, "."]) |
| 46 | .expect_end_eventually_and_print()?; | 51 | .expect_end_eventually_and_print()?; |
| 47 | let test_repo = GitTestRepo::open(&path)?; | 52 | let test_repo = GitTestRepo::open(&path)?; |
| 48 | let mut config = test_repo | 53 | set_git_nostr_login_config(&test_repo)?; |
| 49 | .git_repo | ||
| 50 | .config() | ||
| 51 | .context("cannot open git config")?; | ||
| 52 | config.set_str("nostr.nsec", TEST_KEY_1_NSEC)?; | ||
| 53 | config.set_str("nostr.npub", TEST_KEY_1_NPUB)?; | ||
| 54 | Ok(test_repo) | 54 | Ok(test_repo) |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | fn prep_git_repo_minus_1_commit() -> Result<GitTestRepo> { | 57 | fn prep_git_repo_minus_1_commit() -> Result<GitTestRepo> { |
| 58 | let test_repo = GitTestRepo::without_repo_in_git_config(); | 58 | let test_repo = GitTestRepo::without_repo_in_git_config(); |
| 59 | let mut config = test_repo | 59 | set_git_nostr_login_config(&test_repo)?; |
| 60 | .git_repo | ||
| 61 | .config() | ||
| 62 | .context("cannot open git config")?; | ||
| 63 | config.set_str("nostr.nsec", TEST_KEY_1_NSEC)?; | ||
| 64 | config.set_str("nostr.npub", TEST_KEY_1_NPUB)?; | ||
| 65 | test_repo.add_remote(NOSTR_REMOTE_NAME, &get_nostr_remote_url()?)?; | 60 | test_repo.add_remote(NOSTR_REMOTE_NAME, &get_nostr_remote_url()?)?; |
| 66 | test_repo.populate_minus_1()?; | 61 | test_repo.populate_minus_1()?; |
| 67 | Ok(test_repo) | 62 | Ok(test_repo) |