diff options
| -rw-r--r-- | src/bin/git_remote_nostr/push.rs | 249 | ||||
| -rw-r--r-- | tests/git_remote_nostr/push.rs | 193 |
2 files changed, 369 insertions, 73 deletions
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index dde4ab0..40e9584 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs | |||
| @@ -25,7 +25,7 @@ use ngit::{ | |||
| 25 | nostr_url::{CloneUrl, NostrUrlDecoded}, | 25 | nostr_url::{CloneUrl, NostrUrlDecoded}, |
| 26 | oid_to_shorthand_string, | 26 | oid_to_shorthand_string, |
| 27 | }, | 27 | }, |
| 28 | git_events::{self, get_event_root}, | 28 | git_events::{self, event_to_cover_letter, get_event_root}, |
| 29 | login::{self, get_curent_user}, | 29 | login::{self, get_curent_user}, |
| 30 | repo_ref::{self, get_repo_config_from_yaml}, | 30 | repo_ref::{self, get_repo_config_from_yaml}, |
| 31 | repo_state, | 31 | repo_state, |
| @@ -965,72 +965,181 @@ async fn get_merged_status_events( | |||
| 965 | }; | 965 | }; |
| 966 | let (ahead, _) = | 966 | let (ahead, _) = |
| 967 | git_repo.get_commits_ahead_behind(&tip_of_remote_branch, &tip_of_pushed_branch)?; | 967 | git_repo.get_commits_ahead_behind(&tip_of_remote_branch, &tip_of_pushed_branch)?; |
| 968 | for commit_hash in ahead { | ||
| 969 | let commit = git_repo.git_repo.find_commit(sha1_to_oid(&commit_hash)?)?; | ||
| 970 | if commit.parent_count() > 1 { | ||
| 971 | // merge commit | ||
| 972 | for parent in commit.parents() { | ||
| 973 | // lookup parent id | ||
| 974 | let commit_events = get_events_from_local_cache( | ||
| 975 | git_repo.get_path()?, | ||
| 976 | vec![ | ||
| 977 | nostr::Filter::default() | ||
| 978 | .kind(nostr::Kind::GitPatch) | ||
| 979 | .reference(parent.id().to_string()), | ||
| 980 | ], | ||
| 981 | ) | ||
| 982 | .await?; | ||
| 983 | if let Some(commit_event) = commit_events.iter().find(|e| { | ||
| 984 | e.tags.iter().any(|t| { | ||
| 985 | t.as_slice()[0].eq("commit") | ||
| 986 | && t.as_slice()[1].eq(&parent.id().to_string()) | ||
| 987 | }) | ||
| 988 | }) { | ||
| 989 | let (proposal_id, revision_id) = | ||
| 990 | get_proposal_and_revision_root_from_patch(git_repo, commit_event) | ||
| 991 | .await?; | ||
| 992 | term.write_line( | ||
| 993 | format!( | ||
| 994 | "merge commit {}: create nostr proposal status event", | ||
| 995 | &commit.id().to_string()[..7], | ||
| 996 | ) | ||
| 997 | .as_str(), | ||
| 998 | )?; | ||
| 999 | 968 | ||
| 1000 | events.push( | 969 | let commit_events = get_events_from_local_cache( |
| 1001 | create_merge_status( | 970 | git_repo.get_path()?, |
| 1002 | signer, | 971 | vec![ |
| 1003 | repo_ref, | 972 | nostr::Filter::default().kind(nostr::Kind::GitPatch), |
| 1004 | &get_event_from_cache_by_id(git_repo, &proposal_id).await?, | 973 | // TODO: limit by repo_ref |
| 1005 | &if let Some(revision_id) = revision_id { | 974 | ], |
| 1006 | Some( | 975 | ) |
| 1007 | get_event_from_cache_by_id(git_repo, &revision_id) | 976 | .await?; |
| 1008 | .await?, | 977 | |
| 1009 | ) | 978 | let merged_proposals_info = |
| 1010 | } else { | 979 | get_merged_proposals_info(git_repo, &ahead, &commit_events).await?; |
| 1011 | None | 980 | |
| 1012 | }, | 981 | for event in |
| 1013 | &commit_hash, | 982 | create_merge_events(term, git_repo, repo_ref, signer, &merged_proposals_info) |
| 1014 | commit_event.id, | 983 | .await? |
| 1015 | ) | 984 | { |
| 1016 | .await?, | 985 | events.push(event); |
| 1017 | ); | 986 | } |
| 987 | } | ||
| 988 | } | ||
| 989 | Ok(events) | ||
| 990 | } | ||
| 991 | |||
| 992 | /// (`proposal_id`, `revision_id`) | ||
| 993 | type MergedProposalsInfo = | ||
| 994 | HashMap<EventId, (Option<EventId>, HashMap<Sha1Hash, MergedPRCommitType>)>; | ||
| 995 | |||
| 996 | async fn get_merged_proposals_info( | ||
| 997 | git_repo: &Repo, | ||
| 998 | ahead: &Vec<Sha1Hash>, | ||
| 999 | available_patches: &[Event], | ||
| 1000 | ) -> Result<MergedProposalsInfo> { | ||
| 1001 | let mut proposals: MergedProposalsInfo = HashMap::new(); | ||
| 1002 | |||
| 1003 | for commit_hash in ahead { | ||
| 1004 | let commit = git_repo.git_repo.find_commit(sha1_to_oid(commit_hash)?)?; | ||
| 1005 | // three-way merge - just to set merge commit id as the merged branch commits | ||
| 1006 | // are in ahead | ||
| 1007 | if commit.parent_count() > 1 { | ||
| 1008 | for parent in commit.parents() { | ||
| 1009 | for patch_event in available_patches | ||
| 1010 | .iter() | ||
| 1011 | .filter(|e| { | ||
| 1012 | e.tags.iter().any(|t| { | ||
| 1013 | t.as_slice()[0].eq("commit") | ||
| 1014 | && t.as_slice()[1].eq(&parent.id().to_string()) | ||
| 1015 | }) | ||
| 1016 | }) | ||
| 1017 | .collect::<Vec<&Event>>() | ||
| 1018 | { | ||
| 1019 | if let Ok((proposal_id, revision_id)) = | ||
| 1020 | get_proposal_and_revision_root_from_patch(git_repo, patch_event).await | ||
| 1021 | { | ||
| 1022 | let (entry_revision_id, merged_patches) = | ||
| 1023 | proposals.entry(proposal_id).or_default(); | ||
| 1024 | if entry_revision_id == &revision_id { | ||
| 1025 | merged_patches.insert(*commit_hash, MergedPRCommitType::MergeCommit); | ||
| 1018 | } | 1026 | } |
| 1019 | } | 1027 | } |
| 1020 | } | 1028 | } |
| 1021 | } | 1029 | } |
| 1030 | } else { | ||
| 1031 | // three way merge or fast forward merge commits | ||
| 1032 | // note: ahead included commits of three-way merged branches | ||
| 1033 | for patch_event in available_patches | ||
| 1034 | .iter() | ||
| 1035 | .filter(|e| { | ||
| 1036 | e.tags.iter().any(|t| { | ||
| 1037 | t.as_slice()[0].eq("commit") && t.as_slice()[1].eq(&commit_hash.to_string()) | ||
| 1038 | }) | ||
| 1039 | }) | ||
| 1040 | .collect::<Vec<&Event>>() | ||
| 1041 | { | ||
| 1042 | if let Ok((proposal_id, revision_id)) = | ||
| 1043 | get_proposal_and_revision_root_from_patch(git_repo, patch_event).await | ||
| 1044 | { | ||
| 1045 | let (entry_revision_id, merged_patches) = | ||
| 1046 | proposals.entry(proposal_id).or_default(); | ||
| 1047 | // ignore revisions without all the merged commits | ||
| 1048 | if entry_revision_id == &revision_id { | ||
| 1049 | merged_patches.insert( | ||
| 1050 | *commit_hash, | ||
| 1051 | MergedPRCommitType::PatchCommit { | ||
| 1052 | event_id: patch_event.id, | ||
| 1053 | }, | ||
| 1054 | ); | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | } | ||
| 1058 | } | ||
| 1059 | } | ||
| 1060 | Ok(proposals) | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | async fn create_merge_events( | ||
| 1064 | term: &console::Term, | ||
| 1065 | git_repo: &Repo, | ||
| 1066 | repo_ref: &RepoRef, | ||
| 1067 | signer: &Arc<dyn NostrSigner>, | ||
| 1068 | merged_proposals_info: &MergedProposalsInfo, | ||
| 1069 | ) -> Result<Vec<Event>> { | ||
| 1070 | let mut events = vec![]; | ||
| 1071 | for (proposal_id, (revision_id, merged_patches)) in merged_proposals_info { | ||
| 1072 | let proposal = get_event_from_cache_by_id(git_repo, proposal_id).await?; | ||
| 1073 | |||
| 1074 | if merged_patches | ||
| 1075 | .values() | ||
| 1076 | .any(|m| *m == MergedPRCommitType::MergeCommit) | ||
| 1077 | { | ||
| 1078 | term.write_line( | ||
| 1079 | format!( | ||
| 1080 | "merge commit {}: create nostr proposal status event", | ||
| 1081 | &merged_patches.keys().next().unwrap().to_string()[..7], | ||
| 1082 | ) | ||
| 1083 | .as_str(), | ||
| 1084 | )?; | ||
| 1085 | } else { | ||
| 1086 | term.write_line( | ||
| 1087 | format!( | ||
| 1088 | "fast-forward merge: create nostr proposal status event for {}", | ||
| 1089 | event_to_cover_letter(&proposal)?.get_branch_name()?, | ||
| 1090 | ) | ||
| 1091 | .as_str(), | ||
| 1092 | )?; | ||
| 1022 | } | 1093 | } |
| 1094 | events.push( | ||
| 1095 | create_merge_status( | ||
| 1096 | signer, | ||
| 1097 | repo_ref, | ||
| 1098 | &proposal, | ||
| 1099 | &if let Some(revision_id) = revision_id { | ||
| 1100 | Some(get_event_from_cache_by_id(git_repo, revision_id).await?) | ||
| 1101 | } else { | ||
| 1102 | None | ||
| 1103 | }, | ||
| 1104 | if merged_patches | ||
| 1105 | .values() | ||
| 1106 | .any(|m| m == &MergedPRCommitType::MergeCommit) | ||
| 1107 | { | ||
| 1108 | vec![*merged_patches.keys().next().unwrap()] | ||
| 1109 | } else { | ||
| 1110 | let mut t: Vec<Sha1Hash> = merged_patches.keys().copied().collect(); | ||
| 1111 | t.reverse(); | ||
| 1112 | t | ||
| 1113 | }, | ||
| 1114 | merged_patches | ||
| 1115 | .values() | ||
| 1116 | .filter_map(|m| match m { | ||
| 1117 | MergedPRCommitType::MergeCommit => None, | ||
| 1118 | MergedPRCommitType::PatchApplied { event_id } | ||
| 1119 | | MergedPRCommitType::PatchCommit { event_id } => Some(*event_id), | ||
| 1120 | }) | ||
| 1121 | .collect(), | ||
| 1122 | ) | ||
| 1123 | .await?, | ||
| 1124 | ); | ||
| 1023 | } | 1125 | } |
| 1024 | Ok(events) | 1126 | Ok(events) |
| 1025 | } | 1127 | } |
| 1026 | 1128 | ||
| 1129 | #[derive(PartialEq)] | ||
| 1130 | enum MergedPRCommitType { | ||
| 1131 | MergeCommit, | ||
| 1132 | PatchCommit { event_id: EventId }, | ||
| 1133 | PatchApplied { event_id: EventId }, | ||
| 1134 | } | ||
| 1135 | |||
| 1027 | async fn create_merge_status( | 1136 | async fn create_merge_status( |
| 1028 | signer: &Arc<dyn NostrSigner>, | 1137 | signer: &Arc<dyn NostrSigner>, |
| 1029 | repo_ref: &RepoRef, | 1138 | repo_ref: &RepoRef, |
| 1030 | proposal: &Event, | 1139 | proposal: &Event, |
| 1031 | revision: &Option<Event>, | 1140 | revision: &Option<Event>, |
| 1032 | merge_commit: &Sha1Hash, | 1141 | merge_commits: Vec<Sha1Hash>, |
| 1033 | merged_patch: EventId, | 1142 | merged_patches: Vec<EventId>, |
| 1034 | ) -> Result<Event> { | 1143 | ) -> Result<Event> { |
| 1035 | let mut public_keys = repo_ref | 1144 | let mut public_keys = repo_ref |
| 1036 | .maintainers | 1145 | .maintainers |
| @@ -1056,14 +1165,20 @@ async fn create_merge_status( | |||
| 1056 | public_key: None, | 1165 | public_key: None, |
| 1057 | uppercase: false, | 1166 | uppercase: false, |
| 1058 | }), | 1167 | }), |
| 1059 | Tag::from_standardized(nostr::TagStandard::Event { | ||
| 1060 | event_id: merged_patch, | ||
| 1061 | relay_url: repo_ref.relays.first().cloned(), | ||
| 1062 | marker: Some(Marker::Mention), | ||
| 1063 | public_key: None, | ||
| 1064 | uppercase: false, | ||
| 1065 | }), | ||
| 1066 | ], | 1168 | ], |
| 1169 | // Tags for merged patches | ||
| 1170 | merged_patches | ||
| 1171 | .iter() | ||
| 1172 | .map(|merged_patch| { | ||
| 1173 | Tag::from_standardized(nostr::TagStandard::Event { | ||
| 1174 | event_id: *merged_patch, | ||
| 1175 | relay_url: repo_ref.relays.first().cloned(), | ||
| 1176 | marker: Some(Marker::Mention), | ||
| 1177 | public_key: None, | ||
| 1178 | uppercase: false, | ||
| 1179 | }) | ||
| 1180 | }) | ||
| 1181 | .collect::<Vec<Tag>>(), | ||
| 1067 | if let Some(revision) = revision { | 1182 | if let Some(revision) = revision { |
| 1068 | vec![Tag::from_standardized(nostr::TagStandard::Event { | 1183 | vec![Tag::from_standardized(nostr::TagStandard::Event { |
| 1069 | event_id: revision.id, | 1184 | event_id: revision.id, |
| @@ -1085,14 +1200,22 @@ async fn create_merge_status( | |||
| 1085 | Tag::from_standardized(nostr::TagStandard::Reference( | 1200 | Tag::from_standardized(nostr::TagStandard::Reference( |
| 1086 | repo_ref.root_commit.to_string(), | 1201 | repo_ref.root_commit.to_string(), |
| 1087 | )), | 1202 | )), |
| 1088 | Tag::from_standardized(nostr::TagStandard::Reference(format!( | ||
| 1089 | "{merge_commit}" | ||
| 1090 | ))), | ||
| 1091 | Tag::custom( | 1203 | Tag::custom( |
| 1092 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("merge-commit-id")), | 1204 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("merge-commit-id")), |
| 1093 | vec![format!("{merge_commit}")], | 1205 | merge_commits |
| 1206 | .iter() | ||
| 1207 | .map(|merge_commit| format!("{merge_commit}")) | ||
| 1208 | .collect::<Vec<String>>(), | ||
| 1094 | ), | 1209 | ), |
| 1095 | ], | 1210 | ], |
| 1211 | merge_commits | ||
| 1212 | .iter() | ||
| 1213 | .map(|merge_commit| { | ||
| 1214 | Tag::from_standardized(nostr::TagStandard::Reference(format!( | ||
| 1215 | "{merge_commit}" | ||
| 1216 | ))) | ||
| 1217 | }) | ||
| 1218 | .collect::<Vec<Tag>>(), | ||
| 1096 | ] | 1219 | ] |
| 1097 | .concat(), | 1220 | .concat(), |
| 1098 | ), | 1221 | ), |
diff --git a/tests/git_remote_nostr/push.rs b/tests/git_remote_nostr/push.rs index b93475c..4dc2c1d 100644 --- a/tests/git_remote_nostr/push.rs +++ b/tests/git_remote_nostr/push.rs | |||
| @@ -894,7 +894,8 @@ async fn pushes_to_all_git_servers_listed_and_ok_printed() -> Result<()> { | |||
| 894 | 894 | ||
| 895 | #[tokio::test] | 895 | #[tokio::test] |
| 896 | #[serial] | 896 | #[serial] |
| 897 | async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> Result<()> { | 897 | async fn proposal_three_way_merge_commit_pushed_to_main_leads_to_status_event_issued() -> Result<()> |
| 898 | { | ||
| 898 | // | 899 | // |
| 899 | let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; | 900 | let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; |
| 900 | let source_path = source_git_repo.dir.to_str().unwrap().to_string(); | 901 | let source_path = source_git_repo.dir.to_str().unwrap().to_string(); |
| @@ -958,11 +959,14 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 958 | r57.listen_until_close(), | 959 | r57.listen_until_close(), |
| 959 | ); | 960 | ); |
| 960 | 961 | ||
| 961 | let (output, oid) = cli_tester_handle.join().unwrap()?; | 962 | let (output, merge_oid) = cli_tester_handle.join().unwrap()?; |
| 962 | 963 | ||
| 963 | assert_eq!( | 964 | assert_eq!( |
| 964 | output, | 965 | output, |
| 965 | format!(" 431b84e..{} main -> main\r\n", &oid.to_string()[..7]) | 966 | format!( |
| 967 | " 431b84e..{} main -> main\r\n", | ||
| 968 | &merge_oid.to_string()[..7] | ||
| 969 | ) | ||
| 966 | ); | 970 | ); |
| 967 | 971 | ||
| 968 | let new_events = r55 | 972 | let new_events = r55 |
| @@ -976,7 +980,7 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 976 | 980 | ||
| 977 | assert_eq!(new_events.len(), 2, "{new_events:?}"); | 981 | assert_eq!(new_events.len(), 2, "{new_events:?}"); |
| 978 | 982 | ||
| 979 | let proposal = r55 | 983 | let proposal_cover_letter_event = r55 |
| 980 | .events | 984 | .events |
| 981 | .iter() | 985 | .iter() |
| 982 | .find(|e| { | 986 | .find(|e| { |
| @@ -993,14 +997,15 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 993 | .unwrap(); | 997 | .unwrap(); |
| 994 | 998 | ||
| 995 | assert_eq!( | 999 | assert_eq!( |
| 996 | oid.to_string(), | 1000 | vec!["merge-commit-id".to_string(), merge_oid.to_string()], |
| 997 | merge_status | 1001 | merge_status |
| 998 | .tags | 1002 | .tags |
| 999 | .iter() | 1003 | .iter() |
| 1000 | .find(|t| t.as_slice()[0].eq("merge-commit-id")) | 1004 | .find(|t| t.as_slice()[0].eq("merge-commit-id")) |
| 1001 | .unwrap() | 1005 | .unwrap() |
| 1002 | .as_slice()[1], | 1006 | .clone() |
| 1003 | "status sets correct merge-commit-id tag" | 1007 | .to_vec(), |
| 1008 | "status sets correct merge-commit-id tag {merge_status:?}" | ||
| 1004 | ); | 1009 | ); |
| 1005 | 1010 | ||
| 1006 | let proposal_tip = r55 | 1011 | let proposal_tip = r55 |
| @@ -1009,7 +1014,7 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 1009 | .filter(|e| { | 1014 | .filter(|e| { |
| 1010 | e.tags | 1015 | e.tags |
| 1011 | .iter() | 1016 | .iter() |
| 1012 | .any(|t| t.as_slice()[1].eq(&proposal.id.to_string())) | 1017 | .any(|t| t.as_slice()[1].eq(&proposal_cover_letter_event.id.to_string())) |
| 1013 | && e.kind.eq(&Kind::GitPatch) | 1018 | && e.kind.eq(&Kind::GitPatch) |
| 1014 | }) | 1019 | }) |
| 1015 | .last() | 1020 | .last() |
| @@ -1029,7 +1034,175 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 1029 | ); | 1034 | ); |
| 1030 | 1035 | ||
| 1031 | assert_eq!( | 1036 | assert_eq!( |
| 1032 | proposal.id.to_string(), | 1037 | proposal_cover_letter_event.id.to_string(), |
| 1038 | merge_status | ||
| 1039 | .tags | ||
| 1040 | .iter() | ||
| 1041 | .find(|t| t.is_root()) | ||
| 1042 | .unwrap() | ||
| 1043 | .as_slice()[1], | ||
| 1044 | "status tags proposal id as root \r\nmerge status:\r\n{}\r\nproposal:\r\n{}", | ||
| 1045 | merge_status.as_json(), | ||
| 1046 | proposal_cover_letter_event.as_json(), | ||
| 1047 | ); | ||
| 1048 | |||
| 1049 | Ok(()) | ||
| 1050 | } | ||
| 1051 | |||
| 1052 | #[tokio::test] | ||
| 1053 | #[serial] | ||
| 1054 | async fn proposal_fast_forward_merge_commits_pushed_to_main_leads_to_status_event_issued() | ||
| 1055 | -> Result<()> { | ||
| 1056 | // | ||
| 1057 | let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?; | ||
| 1058 | let source_path = source_git_repo.dir.to_str().unwrap().to_string(); | ||
| 1059 | |||
| 1060 | let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = ( | ||
| 1061 | Relay::new(8051, None, None), | ||
| 1062 | Relay::new(8052, None, None), | ||
| 1063 | Relay::new(8053, None, None), | ||
| 1064 | Relay::new(8055, None, None), | ||
| 1065 | Relay::new(8056, None, None), | ||
| 1066 | Relay::new(8057, None, None), | ||
| 1067 | ); | ||
| 1068 | r51.events = events.clone(); | ||
| 1069 | r55.events = events.clone(); | ||
| 1070 | |||
| 1071 | #[allow(clippy::mutable_key_type)] | ||
| 1072 | let before = r55.events.iter().cloned().collect::<HashSet<Event>>(); | ||
| 1073 | |||
| 1074 | let cli_tester_handle = std::thread::spawn(move || -> Result<(String, Oid)> { | ||
| 1075 | let branch_name = get_proposal_branch_name_from_events(&events, FEATURE_BRANCH_NAME_1)?; | ||
| 1076 | |||
| 1077 | let git_repo = clone_git_repo_with_nostr_url()?; | ||
| 1078 | git_repo.checkout_remote_branch(&branch_name)?; | ||
| 1079 | git_repo.checkout("refs/heads/main")?; | ||
| 1080 | |||
| 1081 | CliTester::new_git_with_remote_helper_from_dir( | ||
| 1082 | &git_repo.dir, | ||
| 1083 | ["merge", &branch_name, "-m", "proposal merge commit message"], | ||
| 1084 | ) | ||
| 1085 | .expect_end_eventually_and_print()?; | ||
| 1086 | |||
| 1087 | let oid = git_repo.get_tip_of_local_branch("main")?; | ||
| 1088 | |||
| 1089 | let mut p = CliTester::new_git_with_remote_helper_from_dir(&git_repo.dir, ["push"]); | ||
| 1090 | cli_expect_nostr_fetch(&mut p)?; | ||
| 1091 | p.expect(format!("fetching {} ref list over filesystem...\r\n", source_path).as_str())?; | ||
| 1092 | p.expect("list: connecting...\r\n")?; | ||
| 1093 | p.expect_eventually(format!( | ||
| 1094 | "fast-forward merge: create nostr proposal status event for {branch_name}\r\n" | ||
| 1095 | ))?; | ||
| 1096 | // status updates printed here | ||
| 1097 | p.expect_eventually(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?; | ||
| 1098 | let output = p.expect_end_eventually()?; | ||
| 1099 | |||
| 1100 | for p in [51, 52, 53, 55, 56, 57] { | ||
| 1101 | relay::shutdown_relay(8000 + p)?; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | Ok((output, oid)) | ||
| 1105 | }); | ||
| 1106 | // launch relays | ||
| 1107 | let _ = join!( | ||
| 1108 | r51.listen_until_close(), | ||
| 1109 | r52.listen_until_close(), | ||
| 1110 | r53.listen_until_close(), | ||
| 1111 | r55.listen_until_close(), | ||
| 1112 | r56.listen_until_close(), | ||
| 1113 | r57.listen_until_close(), | ||
| 1114 | ); | ||
| 1115 | |||
| 1116 | let (output, tip_oid) = cli_tester_handle.join().unwrap()?; | ||
| 1117 | |||
| 1118 | assert_eq!( | ||
| 1119 | output, | ||
| 1120 | format!( | ||
| 1121 | " 431b84e..{} main -> main\r\n", | ||
| 1122 | &tip_oid.to_string()[..7] | ||
| 1123 | ) | ||
| 1124 | ); | ||
| 1125 | |||
| 1126 | let new_events = r55 | ||
| 1127 | .events | ||
| 1128 | .iter() | ||
| 1129 | .cloned() | ||
| 1130 | .collect::<HashSet<Event>>() | ||
| 1131 | .difference(&before) | ||
| 1132 | .cloned() | ||
| 1133 | .collect::<Vec<Event>>(); | ||
| 1134 | |||
| 1135 | assert_eq!(new_events.len(), 2, "{new_events:?}"); | ||
| 1136 | |||
| 1137 | let proposal_cover_letter_event = r55 | ||
| 1138 | .events | ||
| 1139 | .iter() | ||
| 1140 | .find(|e| { | ||
| 1141 | e.tags | ||
| 1142 | .iter() | ||
| 1143 | .find(|t| t.as_slice()[0].eq("branch-name")) | ||
| 1144 | .is_some_and(|t| t.as_slice()[1].eq(FEATURE_BRANCH_NAME_1)) | ||
| 1145 | }) | ||
| 1146 | .unwrap(); | ||
| 1147 | |||
| 1148 | let proposal_patches: Vec<&Event> = r55 | ||
| 1149 | .events | ||
| 1150 | .iter() | ||
| 1151 | .filter(|e| { | ||
| 1152 | e.kind == Kind::GitPatch | ||
| 1153 | && e.tags | ||
| 1154 | .iter() | ||
| 1155 | .any(|t| t.as_slice()[1].eq(&proposal_cover_letter_event.id.to_string())) | ||
| 1156 | }) | ||
| 1157 | .collect(); | ||
| 1158 | |||
| 1159 | let merge_status = new_events | ||
| 1160 | .iter() | ||
| 1161 | .find(|e| e.kind.eq(&Kind::GitStatusApplied)) | ||
| 1162 | .unwrap(); | ||
| 1163 | // println!("{:?}", proposal_cover_letter_event); | ||
| 1164 | // println!("merge status"); | ||
| 1165 | // println!("{:?}", merge_status); | ||
| 1166 | |||
| 1167 | let patch_commit_ids = proposal_patches | ||
| 1168 | .iter() | ||
| 1169 | .map(|e| { | ||
| 1170 | e.tags | ||
| 1171 | .iter() | ||
| 1172 | .find(|t| t.as_slice()[0].eq("commit")) | ||
| 1173 | .unwrap() | ||
| 1174 | .as_slice()[1] | ||
| 1175 | .to_string() | ||
| 1176 | }) | ||
| 1177 | .collect::<Vec<String>>(); | ||
| 1178 | assert_eq!( | ||
| 1179 | [vec!["merge-commit-id".to_string()], patch_commit_ids].concat(), | ||
| 1180 | merge_status | ||
| 1181 | .tags | ||
| 1182 | .iter() | ||
| 1183 | .find(|t| t.as_slice()[0].eq("merge-commit-id")) | ||
| 1184 | .unwrap() | ||
| 1185 | .clone() | ||
| 1186 | .to_vec(), | ||
| 1187 | "status sets correct merge-commit-id tag {merge_status:?}" | ||
| 1188 | ); | ||
| 1189 | |||
| 1190 | for patch_id in proposal_patches | ||
| 1191 | .iter() | ||
| 1192 | .map(|e| e.id.to_string()) | ||
| 1193 | .collect::<Vec<String>>() | ||
| 1194 | { | ||
| 1195 | assert!( | ||
| 1196 | merge_status.tags.iter().any(|t| t.as_slice().len().eq(&4) | ||
| 1197 | && t.as_slice()[1] == patch_id | ||
| 1198 | && t.as_slice()[3].eq("mention")), | ||
| 1199 | "merge status doesnt mention proposal patch {patch_id} \r\nmerge status:\r\n{}", | ||
| 1200 | merge_status.as_json(), | ||
| 1201 | ); | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | assert_eq!( | ||
| 1205 | proposal_cover_letter_event.id.to_string(), | ||
| 1033 | merge_status | 1206 | merge_status |
| 1034 | .tags | 1207 | .tags |
| 1035 | .iter() | 1208 | .iter() |
| @@ -1038,7 +1211,7 @@ async fn proposal_merge_commit_pushed_to_main_leads_to_status_event_issued() -> | |||
| 1038 | .as_slice()[1], | 1211 | .as_slice()[1], |
| 1039 | "status tags proposal id as root \r\nmerge status:\r\n{}\r\nproposal:\r\n{}", | 1212 | "status tags proposal id as root \r\nmerge status:\r\n{}\r\nproposal:\r\n{}", |
| 1040 | merge_status.as_json(), | 1213 | merge_status.as_json(), |
| 1041 | proposal.as_json(), | 1214 | proposal_cover_letter_event.as_json(), |
| 1042 | ); | 1215 | ); |
| 1043 | 1216 | ||
| 1044 | Ok(()) | 1217 | Ok(()) |