diff options
Diffstat (limited to 'src/git_remote_helper.rs')
| -rw-r--r-- | src/git_remote_helper.rs | 102 |
1 files changed, 72 insertions, 30 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs index f36b23b..be230b1 100644 --- a/src/git_remote_helper.rs +++ b/src/git_remote_helper.rs | |||
| @@ -33,7 +33,10 @@ use sub_commands::{ | |||
| 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 | tag_value, |
| 35 | }, | 35 | }, |
| 36 | send::{event_is_revision_root, event_to_cover_letter, generate_patch_event, send_events}, | 36 | send::{ |
| 37 | event_is_revision_root, event_to_cover_letter, generate_cover_letter_and_patch_events, | ||
| 38 | generate_patch_event, send_events, | ||
| 39 | }, | ||
| 37 | }; | 40 | }; |
| 38 | 41 | ||
| 39 | #[cfg(not(test))] | 42 | #[cfg(not(test))] |
| @@ -656,21 +659,42 @@ async fn push( | |||
| 656 | if let Some((_, (proposal, patches))) = | 659 | if let Some((_, (proposal, patches))) = |
| 657 | find_proposal_and_patches_by_branch_name(to, &open_proposals) | 660 | find_proposal_and_patches_by_branch_name(to, &open_proposals) |
| 658 | { | 661 | { |
| 659 | if to.starts_with('+') { | 662 | if [repo_ref.maintainers.clone(), vec![proposal.author()]] |
| 660 | // TODO do force push - issue as revision | 663 | .concat() |
| 661 | } else { | 664 | .contains(&user_ref.public_key) |
| 662 | let tip_patch = patches.first().unwrap(); | 665 | { |
| 663 | let tip_of_proposal = get_commit_id_from_patch(tip_patch)?; | ||
| 664 | let tip_of_proposal_commit = | ||
| 665 | git_repo.get_commit_or_tip_of_reference(&tip_of_proposal)?; | ||
| 666 | let tip_of_pushed_branch = git_repo.get_commit_or_tip_of_reference(from)?; | 666 | let tip_of_pushed_branch = git_repo.get_commit_or_tip_of_reference(from)?; |
| 667 | let (mut ahead, behind) = git_repo | 667 | if refspec.starts_with('+') { |
| 668 | .get_commits_ahead_behind(&tip_of_proposal_commit, &tip_of_pushed_branch)?; | 668 | // force push |
| 669 | if behind.is_empty() { | 669 | let (_, main_tip) = git_repo.get_main_or_master_branch()?; |
| 670 | if [repo_ref.maintainers.clone(), vec![proposal.author()]] | 670 | let (mut ahead, _) = |
| 671 | .concat() | 671 | git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; |
| 672 | .contains(&user_ref.public_key) | 672 | ahead.reverse(); |
| 673 | for patch in generate_cover_letter_and_patch_events( | ||
| 674 | None, | ||
| 675 | git_repo, | ||
| 676 | &ahead, | ||
| 677 | &signer, | ||
| 678 | repo_ref, | ||
| 679 | &Some(proposal.id().to_string()), | ||
| 680 | &[], | ||
| 681 | ) | ||
| 682 | .await? | ||
| 673 | { | 683 | { |
| 684 | events.push(patch); | ||
| 685 | } | ||
| 686 | } else { | ||
| 687 | // fast forward push | ||
| 688 | let tip_patch = patches.first().unwrap(); | ||
| 689 | let tip_of_proposal = get_commit_id_from_patch(tip_patch)?; | ||
| 690 | let tip_of_proposal_commit = | ||
| 691 | git_repo.get_commit_or_tip_of_reference(&tip_of_proposal)?; | ||
| 692 | |||
| 693 | let (mut ahead, behind) = git_repo.get_commits_ahead_behind( | ||
| 694 | &tip_of_proposal_commit, | ||
| 695 | &tip_of_pushed_branch, | ||
| 696 | )?; | ||
| 697 | if behind.is_empty() { | ||
| 674 | let thread_id = if let Ok(root_event_id) = get_event_root(tip_patch) { | 698 | let thread_id = if let Ok(root_event_id) = get_event_root(tip_patch) { |
| 675 | root_event_id | 699 | root_event_id |
| 676 | } else { | 700 | } else { |
| @@ -702,25 +726,25 @@ async fn push( | |||
| 702 | parent_patch = new_patch; | 726 | parent_patch = new_patch; |
| 703 | } | 727 | } |
| 704 | } else { | 728 | } else { |
| 729 | // we shouldn't get here | ||
| 730 | term.write_line( | ||
| 731 | format!( | ||
| 732 | "WARNING: failed to push {from} as nostr proposal. Try and force push ", | ||
| 733 | ) | ||
| 734 | .as_str(), | ||
| 735 | ) | ||
| 736 | .unwrap(); | ||
| 705 | println!( | 737 | println!( |
| 706 | "error {to} permission denied. you are not the proposal author or a repo maintainer" | 738 | "error {to} cannot fastforward as newer patches found on proposal" |
| 707 | ); | 739 | ); |
| 708 | rejected_proposal_refspecs.push(refspec.to_string()); | 740 | rejected_proposal_refspecs.push(refspec.to_string()); |
| 709 | } | 741 | } |
| 710 | } else { | ||
| 711 | // we shouldn't get here | ||
| 712 | term.write_line( | ||
| 713 | format!( | ||
| 714 | "WARNING: failed to push {from} as nostr proposal. Try and force push ", | ||
| 715 | ) | ||
| 716 | .as_str(), | ||
| 717 | ) | ||
| 718 | .unwrap(); | ||
| 719 | println!( | ||
| 720 | "error {to} cannot fastforward as newer patches found on proposal" | ||
| 721 | ); | ||
| 722 | rejected_proposal_refspecs.push(refspec.to_string()); | ||
| 723 | } | 742 | } |
| 743 | } else { | ||
| 744 | println!( | ||
| 745 | "error {to} permission denied. you are not the proposal author or a repo maintainer" | ||
| 746 | ); | ||
| 747 | rejected_proposal_refspecs.push(refspec.to_string()); | ||
| 724 | } | 748 | } |
| 725 | } else { | 749 | } else { |
| 726 | // TODO new proposal / proposal no longer open | 750 | // TODO new proposal / proposal no longer open |
| @@ -1046,7 +1070,14 @@ fn refspec_to_from_to(refspec: &str) -> Result<(&str, &str)> { | |||
| 1046 | ); | 1070 | ); |
| 1047 | } | 1071 | } |
| 1048 | let parts = refspec.split(':').collect::<Vec<&str>>(); | 1072 | let parts = refspec.split(':').collect::<Vec<&str>>(); |
| 1049 | Ok((parts.first().unwrap(), parts.get(1).unwrap())) | 1073 | Ok(( |
| 1074 | if parts.first().unwrap().starts_with('+') { | ||
| 1075 | &parts.first().unwrap()[1..] | ||
| 1076 | } else { | ||
| 1077 | parts.first().unwrap() | ||
| 1078 | }, | ||
| 1079 | parts.get(1).unwrap(), | ||
| 1080 | )) | ||
| 1050 | } | 1081 | } |
| 1051 | 1082 | ||
| 1052 | fn refspec_remote_ref_name( | 1083 | fn refspec_remote_ref_name( |
| @@ -1061,7 +1092,8 @@ fn refspec_remote_ref_name( | |||
| 1061 | Ok(format!( | 1092 | Ok(format!( |
| 1062 | "refs/remotes/{}/{}", | 1093 | "refs/remotes/{}/{}", |
| 1063 | nostr_remote.name().context("remote should have a name")?, | 1094 | nostr_remote.name().context("remote should have a name")?, |
| 1064 | to.replace("refs/heads/", ""), // TODO only replace if it begins with this | 1095 | to.replace("refs/heads/", ""), /* TODO only replace if it begins with this |
| 1096 | * TODO what about tags? */ | ||
| 1065 | )) | 1097 | )) |
| 1066 | } | 1098 | } |
| 1067 | 1099 | ||
| @@ -1289,4 +1321,14 @@ mod tests { | |||
| 1289 | } | 1321 | } |
| 1290 | } | 1322 | } |
| 1291 | } | 1323 | } |
| 1324 | |||
| 1325 | mod refspec_to_from_to { | ||
| 1326 | use super::*; | ||
| 1327 | |||
| 1328 | #[test] | ||
| 1329 | fn trailing_plus_stripped() { | ||
| 1330 | let (from, _) = refspec_to_from_to("+testing:testingb").unwrap(); | ||
| 1331 | assert_eq!(from, "testing"); | ||
| 1332 | } | ||
| 1333 | } | ||
| 1292 | } | 1334 | } |