upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-07 13:56:46 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-07 13:56:46 +0000
commit871ab773cd1d2fea89fdfe584d637c64694f9991 (patch)
treedeaa35584c236c01f90d98f1b9627c81b0480ca0 /src
parent41487476bfbe842df61d821df1e3eae06b1c31e2 (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.rs5
-rw-r--r--src/nostr/policy/state.rs193
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;
13pub use announcement::{AnnouncementPolicy, AnnouncementResult}; 13pub use announcement::{AnnouncementPolicy, AnnouncementResult};
14pub use pr_event::PrEventPolicy; 14pub use pr_event::PrEventPolicy;
15pub use related::{ReferenceResult, RelatedEventPolicy}; 15pub use related::{ReferenceResult, RelatedEventPolicy};
16pub use state::{AlignmentResult, StatePolicy, StateResult}; 16pub use state::{StatePolicy, StateResult};
17
18// Re-export AlignmentResult from git::sync (canonical location)
19pub use crate::git::sync::AlignmentResult;
17 20
18use super::SharedDatabase; 21use super::SharedDatabase;
19use crate::purgatory::Purgatory; 22use 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
11use super::PolicyContext; 11use super::PolicyContext;
12use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data}; 12use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data};
13use crate::git::sync::align_repository_with_state;
13use crate::git::{self}; 14use crate::git::{self};
14use crate::nostr::events::{validate_state, RepositoryAnnouncement, RepositoryState}; 15use crate::nostr::events::{validate_state, RepositoryAnnouncement, RepositoryState};
15 16
16/// Result of aligning a repository with authorized state
17#[derive(Debug, Default)]
18pub 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
29impl 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)]
37pub enum StateResult { 19pub 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 &current_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