diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-08 00:50:54 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-08 00:50:54 +0000 |
| commit | f75e1c59aacf5ce668fd327e4e3d827511661c2a (patch) | |
| tree | 867926c7503e7c587e86c67896a9e7347600447b /src/git | |
| parent | 3f14f998d64b5fa15bdddd7570b4f72874eb9f29 (diff) | |
chore: cargo fmt
Diffstat (limited to 'src/git')
| -rw-r--r-- | src/git/authorization.rs | 4 | ||||
| -rw-r--r-- | src/git/process.rs | 66 | ||||
| -rw-r--r-- | src/git/sync.rs | 40 |
3 files changed, 61 insertions, 49 deletions
diff --git a/src/git/authorization.rs b/src/git/authorization.rs index fbddb98..7502a52 100644 --- a/src/git/authorization.rs +++ b/src/git/authorization.rs | |||
| @@ -134,11 +134,11 @@ pub async fn authorize_push( | |||
| 134 | e | 134 | e |
| 135 | ))); | 135 | ))); |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | // Create placeholder for git-data-first scenario | 138 | // Create placeholder for git-data-first scenario |
| 139 | // This allows cleanup if the PR event never arrives | 139 | // This allows cleanup if the PR event never arrives |
| 140 | purgatory.add_pr_placeholder(event_id_hex.to_string(), new_oid.clone()); | 140 | purgatory.add_pr_placeholder(event_id_hex.to_string(), new_oid.clone()); |
| 141 | 141 | ||
| 142 | debug!( | 142 | debug!( |
| 143 | "Created placeholder for {} - awaiting PR event (will expire in 30min if event doesn't arrive)", | 143 | "Created placeholder for {} - awaiting PR event (will expire in 30min if event doesn't arrive)", |
| 144 | event_id_hex | 144 | event_id_hex |
diff --git a/src/git/process.rs b/src/git/process.rs index d052c04..215b423 100644 --- a/src/git/process.rs +++ b/src/git/process.rs | |||
| @@ -6,12 +6,15 @@ | |||
| 6 | //! - When events are released from purgatory (purgatory sync) | 6 | //! - When events are released from purgatory (purgatory sync) |
| 7 | //! - When git pushes trigger purgatory releases (receive-pack handler) | 7 | //! - When git pushes trigger purgatory releases (receive-pack handler) |
| 8 | 8 | ||
| 9 | use std::path::Path; | ||
| 10 | use nostr_sdk::Event; | ||
| 11 | use crate::git::authorization::{collect_authorized_maintainers, RepositoryData}; | ||
| 12 | use crate::git::sync::{align_repository_with_state, sync_pr_refs_to_tagged_owner_repos, copy_missing_oids_between_repos}; | ||
| 13 | use crate::git; | 9 | use crate::git; |
| 10 | use crate::git::authorization::{collect_authorized_maintainers, RepositoryData}; | ||
| 11 | use crate::git::sync::{ | ||
| 12 | align_repository_with_state, copy_missing_oids_between_repos, | ||
| 13 | sync_pr_refs_to_tagged_owner_repos, | ||
| 14 | }; | ||
| 14 | use crate::nostr::events::RepositoryState; | 15 | use crate::nostr::events::RepositoryState; |
| 16 | use nostr_sdk::Event; | ||
| 17 | use std::path::Path; | ||
| 15 | 18 | ||
| 16 | /// Result of processing a state event with git data | 19 | /// Result of processing a state event with git data |
| 17 | #[derive(Debug, Default, Clone)] | 20 | #[derive(Debug, Default, Clone)] |
| @@ -68,19 +71,19 @@ pub fn process_state_with_git_data( | |||
| 68 | git_data_path: &Path, | 71 | git_data_path: &Path, |
| 69 | ) -> ProcessStateResult { | 72 | ) -> ProcessStateResult { |
| 70 | let mut result = ProcessStateResult::default(); | 73 | let mut result = ProcessStateResult::default(); |
| 71 | 74 | ||
| 72 | let state_author = state.event.pubkey.to_hex(); | 75 | let state_author = state.event.pubkey.to_hex(); |
| 73 | 76 | ||
| 74 | // Collect authorized maintainers per owner | 77 | // Collect authorized maintainers per owner |
| 75 | let by_owner = collect_authorized_maintainers(&db_repo_data.announcements); | 78 | let by_owner = collect_authorized_maintainers(&db_repo_data.announcements); |
| 76 | 79 | ||
| 77 | // Step 1: Identify owner repos that the state event author is maintainer for | 80 | // Step 1: Identify owner repos that the state event author is maintainer for |
| 78 | let authorized_owners: Vec<&String> = by_owner | 81 | let authorized_owners: Vec<&String> = by_owner |
| 79 | .iter() | 82 | .iter() |
| 80 | .filter(|(_, maintainers)| maintainers.contains(&state_author)) | 83 | .filter(|(_, maintainers)| maintainers.contains(&state_author)) |
| 81 | .map(|(owner, _)| owner) | 84 | .map(|(owner, _)| owner) |
| 82 | .collect(); | 85 | .collect(); |
| 83 | 86 | ||
| 84 | if authorized_owners.is_empty() { | 87 | if authorized_owners.is_empty() { |
| 85 | tracing::debug!( | 88 | tracing::debug!( |
| 86 | identifier = %state.identifier, | 89 | identifier = %state.identifier, |
| @@ -89,18 +92,18 @@ pub fn process_state_with_git_data( | |||
| 89 | ); | 92 | ); |
| 90 | return result; | 93 | return result; |
| 91 | } | 94 | } |
| 92 | 95 | ||
| 93 | // Process each owner repo that authorizes this state event author | 96 | // Process each owner repo that authorizes this state event author |
| 94 | for owner in &authorized_owners { | 97 | for owner in &authorized_owners { |
| 95 | let maintainers = by_owner.get(*owner).unwrap(); | 98 | let maintainers = by_owner.get(*owner).unwrap(); |
| 96 | 99 | ||
| 97 | // Step 2: Check if this state event is the latest authorized for this owner | 100 | // Step 2: Check if this state event is the latest authorized for this owner |
| 98 | let is_latest = crate::git::sync::is_latest_authorized_state_public( | 101 | let is_latest = crate::git::sync::is_latest_authorized_state_public( |
| 99 | state, | 102 | state, |
| 100 | maintainers, | 103 | maintainers, |
| 101 | &db_repo_data.states, | 104 | &db_repo_data.states, |
| 102 | ); | 105 | ); |
| 103 | 106 | ||
| 104 | if !is_latest { | 107 | if !is_latest { |
| 105 | tracing::debug!( | 108 | tracing::debug!( |
| 106 | identifier = %state.identifier, | 109 | identifier = %state.identifier, |
| @@ -109,7 +112,7 @@ pub fn process_state_with_git_data( | |||
| 109 | ); | 112 | ); |
| 110 | continue; | 113 | continue; |
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | // Find the announcement for this owner | 116 | // Find the announcement for this owner |
| 114 | let Some(announcement) = db_repo_data | 117 | let Some(announcement) = db_repo_data |
| 115 | .announcements | 118 | .announcements |
| @@ -118,9 +121,9 @@ pub fn process_state_with_git_data( | |||
| 118 | else { | 121 | else { |
| 119 | continue; | 122 | continue; |
| 120 | }; | 123 | }; |
| 121 | 124 | ||
| 122 | let target_repo_path = git_data_path.join(announcement.repo_path()); | 125 | let target_repo_path = git_data_path.join(announcement.repo_path()); |
| 123 | 126 | ||
| 124 | // Step 3: Check git repo exists for that owner | 127 | // Step 3: Check git repo exists for that owner |
| 125 | if !target_repo_path.exists() { | 128 | if !target_repo_path.exists() { |
| 126 | tracing::debug!( | 129 | tracing::debug!( |
| @@ -131,14 +134,12 @@ pub fn process_state_with_git_data( | |||
| 131 | ); | 134 | ); |
| 132 | continue; | 135 | continue; |
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | // Step 4: Copy all required OIDs to that repo (unless it's source_repo_path) | 138 | // Step 4: Copy all required OIDs to that repo (unless it's source_repo_path) |
| 136 | if target_repo_path != source_repo_path { | 139 | if target_repo_path != source_repo_path { |
| 137 | if let Err(e) = copy_missing_oids_between_repos( | 140 | if let Err(e) = |
| 138 | source_repo_path, | 141 | copy_missing_oids_between_repos(source_repo_path, &target_repo_path, state) |
| 139 | &target_repo_path, | 142 | { |
| 140 | state, | ||
| 141 | ) { | ||
| 142 | tracing::warn!( | 143 | tracing::warn!( |
| 143 | identifier = %state.identifier, | 144 | identifier = %state.identifier, |
| 144 | source = %source_repo_path.display(), | 145 | source = %source_repo_path.display(), |
| @@ -150,14 +151,14 @@ pub fn process_state_with_git_data( | |||
| 150 | continue; // Skip this owner repo | 151 | continue; // Skip this owner repo |
| 151 | } | 152 | } |
| 152 | } | 153 | } |
| 153 | 154 | ||
| 154 | // Step 5: Reset the git state in that repo to match the state event | 155 | // Step 5: Reset the git state in that repo to match the state event |
| 155 | let align_result = align_repository_with_state(&target_repo_path, state); | 156 | let align_result = align_repository_with_state(&target_repo_path, state); |
| 156 | result.repos_synced += 1; | 157 | result.repos_synced += 1; |
| 157 | result.refs_created += align_result.refs_created; | 158 | result.refs_created += align_result.refs_created; |
| 158 | result.refs_updated += align_result.refs_updated; | 159 | result.refs_updated += align_result.refs_updated; |
| 159 | result.refs_deleted += align_result.refs_deleted; | 160 | result.refs_deleted += align_result.refs_deleted; |
| 160 | 161 | ||
| 161 | tracing::info!( | 162 | tracing::info!( |
| 162 | identifier = %state.identifier, | 163 | identifier = %state.identifier, |
| 163 | owner = %owner, | 164 | owner = %owner, |
| @@ -169,7 +170,7 @@ pub fn process_state_with_git_data( | |||
| 169 | "Aligned repository with state" | 170 | "Aligned repository with state" |
| 170 | ); | 171 | ); |
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | result | 174 | result |
| 174 | } | 175 | } |
| 175 | 176 | ||
| @@ -205,13 +206,13 @@ pub fn process_pr_with_git_data( | |||
| 205 | source_owner_pubkey: &str, | 206 | source_owner_pubkey: &str, |
| 206 | ) -> ProcessPrResult { | 207 | ) -> ProcessPrResult { |
| 207 | let mut result = ProcessPrResult::default(); | 208 | let mut result = ProcessPrResult::default(); |
| 208 | 209 | ||
| 209 | let event_id = event.id.to_hex(); | 210 | let event_id = event.id.to_hex(); |
| 210 | 211 | ||
| 211 | // Sync PR ref to owner repos using tagged maintainer logic | 212 | // Sync PR ref to owner repos using tagged maintainer logic |
| 212 | let pr_refs = vec![(event_id.clone(), commit.to_string())]; | 213 | let pr_refs = vec![(event_id.clone(), commit.to_string())]; |
| 213 | let pr_events = vec![event.clone()]; | 214 | let pr_events = vec![event.clone()]; |
| 214 | 215 | ||
| 215 | let sync_result = sync_pr_refs_to_tagged_owner_repos( | 216 | let sync_result = sync_pr_refs_to_tagged_owner_repos( |
| 216 | source_repo_path, | 217 | source_repo_path, |
| 217 | &pr_refs, | 218 | &pr_refs, |
| @@ -222,13 +223,10 @@ pub fn process_pr_with_git_data( | |||
| 222 | ); | 223 | ); |
| 223 | result.repos_synced += sync_result.repos_synced; | 224 | result.repos_synced += sync_result.repos_synced; |
| 224 | result.refs_created += sync_result.refs_created; | 225 | result.refs_created += sync_result.refs_created; |
| 225 | result.errors.extend( | 226 | result |
| 226 | sync_result | 227 | .errors |
| 227 | .errors | 228 | .extend(sync_result.errors.into_iter().map(|(_, e)| e)); |
| 228 | .into_iter() | 229 | |
| 229 | .map(|(_, e)| e), | ||
| 230 | ); | ||
| 231 | |||
| 232 | // Create the ref in the source repo if it doesn't exist | 230 | // Create the ref in the source repo if it doesn't exist |
| 233 | let ref_name = format!("refs/nostr/{}", event_id); | 231 | let ref_name = format!("refs/nostr/{}", event_id); |
| 234 | if git::get_ref_commit(source_repo_path, &ref_name).is_none() { | 232 | if git::get_ref_commit(source_repo_path, &ref_name).is_none() { |
| @@ -250,6 +248,6 @@ pub fn process_pr_with_git_data( | |||
| 250 | ); | 248 | ); |
| 251 | } | 249 | } |
| 252 | } | 250 | } |
| 253 | 251 | ||
| 254 | result | 252 | result |
| 255 | } | 253 | } |
diff --git a/src/git/sync.rs b/src/git/sync.rs index 5e2d3f2..06013a5 100644 --- a/src/git/sync.rs +++ b/src/git/sync.rs | |||
| @@ -837,13 +837,27 @@ pub async fn process_newly_available_git_data( | |||
| 837 | ); | 837 | ); |
| 838 | 838 | ||
| 839 | // Process state events from purgatory | 839 | // Process state events from purgatory |
| 840 | let state_result = | 840 | let state_result = process_purgatory_state_events( |
| 841 | process_purgatory_state_events(&identifier, source_repo_path, database, local_relay, purgatory, git_data_path).await; | 841 | &identifier, |
| 842 | source_repo_path, | ||
| 843 | database, | ||
| 844 | local_relay, | ||
| 845 | purgatory, | ||
| 846 | git_data_path, | ||
| 847 | ) | ||
| 848 | .await; | ||
| 842 | result.merge(state_result); | 849 | result.merge(state_result); |
| 843 | 850 | ||
| 844 | // Process PR events from purgatory | 851 | // Process PR events from purgatory |
| 845 | let pr_result = | 852 | let pr_result = process_purgatory_pr_events( |
| 846 | process_purgatory_pr_events(&identifier, source_repo_path, database, local_relay, purgatory, git_data_path).await; | 853 | &identifier, |
| 854 | source_repo_path, | ||
| 855 | database, | ||
| 856 | local_relay, | ||
| 857 | purgatory, | ||
| 858 | git_data_path, | ||
| 859 | ) | ||
| 860 | .await; | ||
| 847 | result.merge(pr_result); | 861 | result.merge(pr_result); |
| 848 | 862 | ||
| 849 | if result.released_any() { | 863 | if result.released_any() { |
| @@ -1113,7 +1127,9 @@ async fn process_purgatory_pr_events( | |||
| 1113 | error = %e, | 1127 | error = %e, |
| 1114 | "Failed to fetch repository data for PR events" | 1128 | "Failed to fetch repository data for PR events" |
| 1115 | ); | 1129 | ); |
| 1116 | result.errors.push(format!("Failed to fetch repo data: {}", e)); | 1130 | result |
| 1131 | .errors | ||
| 1132 | .push(format!("Failed to fetch repo data: {}", e)); | ||
| 1117 | return result; | 1133 | return result; |
| 1118 | } | 1134 | } |
| 1119 | }; | 1135 | }; |
| @@ -1137,8 +1153,8 @@ async fn process_purgatory_pr_events( | |||
| 1137 | } | 1153 | } |
| 1138 | 1154 | ||
| 1139 | // Extract owner pubkey | 1155 | // Extract owner pubkey |
| 1140 | let owner_pubkey = extract_owner_from_repo_path(source_repo_path, git_data_path) | 1156 | let owner_pubkey = |
| 1141 | .unwrap_or_default(); | 1157 | extract_owner_from_repo_path(source_repo_path, git_data_path).unwrap_or_default(); |
| 1142 | 1158 | ||
| 1143 | // Use unified processing function | 1159 | // Use unified processing function |
| 1144 | let process_result = crate::git::process::process_pr_with_git_data( | 1160 | let process_result = crate::git::process::process_pr_with_git_data( |
| @@ -1192,7 +1208,9 @@ async fn process_purgatory_pr_events( | |||
| 1192 | error = %e, | 1208 | error = %e, |
| 1193 | "Failed to save PR event to database" | 1209 | "Failed to save PR event to database" |
| 1194 | ); | 1210 | ); |
| 1195 | result.errors.push(format!("Failed to save PR event: {}", e)); | 1211 | result |
| 1212 | .errors | ||
| 1213 | .push(format!("Failed to save PR event: {}", e)); | ||
| 1196 | } | 1214 | } |
| 1197 | } | 1215 | } |
| 1198 | } | 1216 | } |
| @@ -1527,11 +1545,7 @@ mod tests { | |||
| 1527 | } | 1545 | } |
| 1528 | 1546 | ||
| 1529 | // Helper function to create a test state event with specific timestamp | 1547 | // Helper function to create a test state event with specific timestamp |
| 1530 | fn create_test_state_event( | 1548 | fn create_test_state_event(keys: &Keys, identifier: &str, created_at: u64) -> RepositoryState { |
| 1531 | keys: &Keys, | ||
| 1532 | identifier: &str, | ||
| 1533 | created_at: u64, | ||
| 1534 | ) -> RepositoryState { | ||
| 1535 | create_test_state_event_with_nonce(keys, identifier, created_at, "") | 1549 | create_test_state_event_with_nonce(keys, identifier, created_at, "") |
| 1536 | } | 1550 | } |
| 1537 | 1551 | ||