diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-07 13:56:46 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-01-07 13:56:46 +0000 |
| commit | 871ab773cd1d2fea89fdfe584d637c64694f9991 (patch) | |
| tree | deaa35584c236c01f90d98f1b9627c81b0480ca0 /src | |
| parent | 41487476bfbe842df61d821df1e3eae06b1c31e2 (diff) | |
refactor: remove align_repository_with_state duplication
- Remove duplicate AlignmentResult struct from nostr/policy/state.rs
- Remove duplicate align_repository_with_state method from StatePolicy
- Import and use the canonical implementation from git::sync
- Re-export AlignmentResult from git::sync in policy/mod.rs
The git::sync version is preferred as it:
- Handles symbolic refs (ref:) properly by skipping them
- Uses git::oid_exists which is more general than git::commit_exists
- Has a cleaner iteration pattern (delete first, then update/create)
Diffstat (limited to 'src')
| -rw-r--r-- | src/nostr/policy/mod.rs | 5 | ||||
| -rw-r--r-- | src/nostr/policy/state.rs | 193 |
2 files changed, 6 insertions, 192 deletions
diff --git a/src/nostr/policy/mod.rs b/src/nostr/policy/mod.rs index c3c5829..dc023a9 100644 --- a/src/nostr/policy/mod.rs +++ b/src/nostr/policy/mod.rs | |||
| @@ -13,7 +13,10 @@ mod state; | |||
| 13 | pub use announcement::{AnnouncementPolicy, AnnouncementResult}; | 13 | pub use announcement::{AnnouncementPolicy, AnnouncementResult}; |
| 14 | pub use pr_event::PrEventPolicy; | 14 | pub use pr_event::PrEventPolicy; |
| 15 | pub use related::{ReferenceResult, RelatedEventPolicy}; | 15 | pub use related::{ReferenceResult, RelatedEventPolicy}; |
| 16 | pub use state::{AlignmentResult, StatePolicy, StateResult}; | 16 | pub use state::{StatePolicy, StateResult}; |
| 17 | |||
| 18 | // Re-export AlignmentResult from git::sync (canonical location) | ||
| 19 | pub use crate::git::sync::AlignmentResult; | ||
| 17 | 20 | ||
| 18 | use super::SharedDatabase; | 21 | use super::SharedDatabase; |
| 19 | use crate::purgatory::Purgatory; | 22 | use crate::purgatory::Purgatory; |
diff --git a/src/nostr/policy/state.rs b/src/nostr/policy/state.rs index 7521ef1..a85e351 100644 --- a/src/nostr/policy/state.rs +++ b/src/nostr/policy/state.rs | |||
| @@ -10,28 +10,10 @@ use nostr_relay_builder::prelude::Event; | |||
| 10 | 10 | ||
| 11 | use super::PolicyContext; | 11 | use super::PolicyContext; |
| 12 | use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data}; | 12 | use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data}; |
| 13 | use crate::git::sync::align_repository_with_state; | ||
| 13 | use crate::git::{self}; | 14 | use crate::git::{self}; |
| 14 | use crate::nostr::events::{validate_state, RepositoryAnnouncement, RepositoryState}; | 15 | use crate::nostr::events::{validate_state, RepositoryAnnouncement, RepositoryState}; |
| 15 | 16 | ||
| 16 | /// Result of aligning a repository with authorized state | ||
| 17 | #[derive(Debug, Default)] | ||
| 18 | pub struct AlignmentResult { | ||
| 19 | /// Number of refs created | ||
| 20 | pub refs_created: usize, | ||
| 21 | /// Number of refs updated | ||
| 22 | pub refs_updated: usize, | ||
| 23 | /// Number of refs deleted | ||
| 24 | pub refs_deleted: usize, | ||
| 25 | /// Whether HEAD was set | ||
| 26 | pub head_set: bool, | ||
| 27 | } | ||
| 28 | |||
| 29 | impl AlignmentResult { | ||
| 30 | pub fn has_changes(&self) -> bool { | ||
| 31 | self.refs_created > 0 || self.refs_updated > 0 || self.refs_deleted > 0 || self.head_set | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | /// Result of state policy evaluation | 17 | /// Result of state policy evaluation |
| 36 | #[derive(Debug)] | 18 | #[derive(Debug)] |
| 37 | pub enum StateResult { | 19 | pub enum StateResult { |
| @@ -146,7 +128,7 @@ impl StatePolicy { | |||
| 146 | } | 128 | } |
| 147 | } | 129 | } |
| 148 | 130 | ||
| 149 | let result = self.align_repository_with_state(&repo_path, &state); | 131 | let result = align_repository_with_state(&repo_path, &state); |
| 150 | repo_count += 1; | 132 | repo_count += 1; |
| 151 | tracing::info!( | 133 | tracing::info!( |
| 152 | "Aligned {} with state: created={}, updated={}, deleted={}, head_set={}", | 134 | "Aligned {} with state: created={}, updated={}, deleted={}, head_set={}", |
| @@ -194,177 +176,6 @@ impl StatePolicy { | |||
| 194 | } | 176 | } |
| 195 | } | 177 | } |
| 196 | 178 | ||
| 197 | /// Align a repository's refs with the authorized state | ||
| 198 | /// | ||
| 199 | /// This function: | ||
| 200 | /// 1. Deletes refs that are in the repo but not in the state (for refs/heads/ and refs/tags/) | ||
| 201 | /// 2. Updates refs that exist in state if we have the commit | ||
| 202 | /// 3. Sets HEAD if the HEAD branch's commit is available | ||
| 203 | pub fn align_repository_with_state( | ||
| 204 | &self, | ||
| 205 | repo_path: &std::path::Path, | ||
| 206 | state: &RepositoryState, | ||
| 207 | ) -> AlignmentResult { | ||
| 208 | let mut result = AlignmentResult::default(); | ||
| 209 | |||
| 210 | // Check if repository exists | ||
| 211 | if !repo_path.exists() { | ||
| 212 | tracing::debug!( | ||
| 213 | "Repository not found at {}, cannot align with state", | ||
| 214 | repo_path.display() | ||
| 215 | ); | ||
| 216 | return result; | ||
| 217 | } | ||
| 218 | |||
| 219 | // Get current refs from the repository | ||
| 220 | let current_refs = match git::list_refs(repo_path) { | ||
| 221 | Ok(refs) => refs, | ||
| 222 | Err(e) => { | ||
| 223 | tracing::warn!("Failed to list refs in {}: {}", repo_path.display(), e); | ||
| 224 | return result; | ||
| 225 | } | ||
| 226 | }; | ||
| 227 | |||
| 228 | // Build expected refs from state | ||
| 229 | let mut expected_refs: std::collections::HashMap<String, String> = | ||
| 230 | std::collections::HashMap::new(); | ||
| 231 | |||
| 232 | for branch in &state.branches { | ||
| 233 | let ref_name = format!("refs/heads/{}", branch.name); | ||
| 234 | expected_refs.insert(ref_name, branch.commit.clone()); | ||
| 235 | } | ||
| 236 | |||
| 237 | for tag in &state.tags { | ||
| 238 | let ref_name = format!("refs/tags/{}", tag.name); | ||
| 239 | expected_refs.insert(ref_name, tag.commit.clone()); | ||
| 240 | } | ||
| 241 | |||
| 242 | // Process current refs: update or delete as needed | ||
| 243 | for (ref_name, current_commit) in ¤t_refs { | ||
| 244 | // Only process refs/heads/ and refs/tags/ | ||
| 245 | if !ref_name.starts_with("refs/heads/") && !ref_name.starts_with("refs/tags/") { | ||
| 246 | continue; | ||
| 247 | } | ||
| 248 | |||
| 249 | match expected_refs.get(ref_name) { | ||
| 250 | Some(expected_commit) => { | ||
| 251 | // Ref should exist - check if commit matches | ||
| 252 | if current_commit != expected_commit { | ||
| 253 | // Check if we have the expected commit | ||
| 254 | if git::commit_exists(repo_path, expected_commit) { | ||
| 255 | // Update the ref | ||
| 256 | match git::update_ref(repo_path, ref_name, expected_commit) { | ||
| 257 | Ok(()) => { | ||
| 258 | tracing::info!( | ||
| 259 | "Updated {} from {} to {} in {}", | ||
| 260 | ref_name, | ||
| 261 | current_commit, | ||
| 262 | expected_commit, | ||
| 263 | repo_path.display() | ||
| 264 | ); | ||
| 265 | result.refs_updated += 1; | ||
| 266 | } | ||
| 267 | Err(e) => { | ||
| 268 | tracing::warn!( | ||
| 269 | "Failed to update {} in {}: {}", | ||
| 270 | ref_name, | ||
| 271 | repo_path.display(), | ||
| 272 | e | ||
| 273 | ); | ||
| 274 | } | ||
| 275 | } | ||
| 276 | } else { | ||
| 277 | tracing::debug!( | ||
| 278 | "Commit {} not available for {} in {}", | ||
| 279 | expected_commit, | ||
| 280 | ref_name, | ||
| 281 | repo_path.display() | ||
| 282 | ); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | } | ||
| 286 | None => { | ||
| 287 | // Ref should not exist - delete it | ||
| 288 | match git::delete_ref(repo_path, ref_name) { | ||
| 289 | Ok(()) => { | ||
| 290 | tracing::info!( | ||
| 291 | "Deleted {} (not in state) from {}", | ||
| 292 | ref_name, | ||
| 293 | repo_path.display() | ||
| 294 | ); | ||
| 295 | result.refs_deleted += 1; | ||
| 296 | } | ||
| 297 | Err(e) => { | ||
| 298 | tracing::warn!( | ||
| 299 | "Failed to delete {} from {}: {}", | ||
| 300 | ref_name, | ||
| 301 | repo_path.display(), | ||
| 302 | e | ||
| 303 | ); | ||
| 304 | } | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | // Add refs that exist in state but not in repo (if we have the commit) | ||
| 311 | for (ref_name, expected_commit) in &expected_refs { | ||
| 312 | let exists = current_refs.iter().any(|(r, _)| r == ref_name); | ||
| 313 | if !exists && git::commit_exists(repo_path, expected_commit) { | ||
| 314 | match git::update_ref(repo_path, ref_name, expected_commit) { | ||
| 315 | Ok(()) => { | ||
| 316 | tracing::info!( | ||
| 317 | "Created {} at {} in {}", | ||
| 318 | ref_name, | ||
| 319 | expected_commit, | ||
| 320 | repo_path.display() | ||
| 321 | ); | ||
| 322 | result.refs_created += 1; | ||
| 323 | } | ||
| 324 | Err(e) => { | ||
| 325 | tracing::warn!( | ||
| 326 | "Failed to create {} in {}: {}", | ||
| 327 | ref_name, | ||
| 328 | repo_path.display(), | ||
| 329 | e | ||
| 330 | ); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | // Set HEAD if specified in state | ||
| 337 | if let Some(head_ref) = &state.head { | ||
| 338 | if let Some(branch_name) = state.get_head_branch() { | ||
| 339 | if let Some(head_commit) = state.get_branch_commit(branch_name) { | ||
| 340 | match git::try_set_head_if_available(repo_path, head_ref, head_commit) { | ||
| 341 | Ok(true) => { | ||
| 342 | tracing::info!( | ||
| 343 | "Set HEAD to {} in {} (from state by {})", | ||
| 344 | head_ref, | ||
| 345 | repo_path.display(), | ||
| 346 | state.event.pubkey.to_hex() | ||
| 347 | ); | ||
| 348 | result.head_set = true; | ||
| 349 | } | ||
| 350 | Ok(false) => { | ||
| 351 | tracing::debug!( | ||
| 352 | "HEAD commit {} not available yet in {}", | ||
| 353 | head_commit, | ||
| 354 | repo_path.display() | ||
| 355 | ); | ||
| 356 | } | ||
| 357 | Err(e) => { | ||
| 358 | tracing::warn!("Failed to set HEAD in {}: {}", repo_path.display(), e); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | } | ||
| 362 | } | ||
| 363 | } | ||
| 364 | |||
| 365 | result | ||
| 366 | } | ||
| 367 | |||
| 368 | /// Copy missing OIDs from a source repository to a target repository | 179 | /// Copy missing OIDs from a source repository to a target repository |
| 369 | /// | 180 | /// |
| 370 | /// Identifies commits referenced in the state that are missing from the target | 181 | /// Identifies commits referenced in the state that are missing from the target |