Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 19 additions & 22 deletions ast/src/lang/graphs/neo4j/operations/migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::lang::graphs::{
queries::*,
Edge, EdgeType, Neo4jGraph, NodeData, NodeKeys, NodeRef, NodeType,
};
use git_url_parse::GitUrl;
use neo4rs::{query, BoltMap};
use shared::{Error, Result};
use tracing::{info, warn};
Expand Down Expand Up @@ -297,20 +298,24 @@ impl Neo4jGraph {
}
}

fn repo_full_name(repo_url: &str) -> String {
match GitUrl::parse(repo_url) {
Ok(gurl) => format!("{}/{}", gurl.owner.unwrap_or_default(), gurl.name),
Err(_) => repo_url
.trim_end_matches(".git")
.rsplit('/')
.next()
.unwrap_or(repo_url)
.to_string(),
}
}

pub fn get_repository_hash_query(repo_url: &str) -> (String, BoltMap) {
let mut params = BoltMap::new();

let repo_name = if repo_url.contains('/') {
let parts: Vec<&str> = repo_url.split('/').collect();
let name = parts.last().unwrap_or(&repo_url);
name.trim_end_matches(".git")
} else {
repo_url
};

boltmap_insert_str(&mut params, "repo_name", repo_name);
let query = "MATCH (r:Repository)
WHERE r.name CONTAINS $repo_name
boltmap_insert_str(&mut params, "repo_name", &repo_full_name(repo_url));
let query = "MATCH (r:Repository)
WHERE r.name = $repo_name
RETURN r.hash as hash";

(query.to_string(), params)
Expand Down Expand Up @@ -392,19 +397,11 @@ pub fn remove_nodes_by_files_chunked_query(
pub fn update_repository_hash_query(repo_url: &str, new_hash: &str) -> (String, BoltMap) {
let mut params = BoltMap::new();

let name = if repo_url.contains('/') {
let parts: Vec<&str> = repo_url.split('/').collect();
let n = parts.last().unwrap_or(&repo_url);
n.trim_end_matches(".git")
} else {
repo_url
};

boltmap_insert_str(&mut params, "repo_name", name);
boltmap_insert_str(&mut params, "repo_name", &repo_full_name(repo_url));
boltmap_insert_str(&mut params, "new_hash", new_hash);

let query = "MATCH (r:Repository)
WHERE r.name CONTAINS $repo_name
let query = "MATCH (r:Repository)
WHERE r.name = $repo_name
SET r.hash = $new_hash";

(query.to_string(), params)
Expand Down
36 changes: 35 additions & 1 deletion standalone/tests/cross_repo_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use ast::lang::graphs::graph_ops::GraphOps;
use ast::lang::graphs::EdgeType;
use ast::lang::linker::normalize_frontend_path;
use ast::lang::{Graph, NodeType};
use ast::lang::{Graph, NodeData, NodeType};
use ast::repo::Repo;
use axum::{extract::State, Json};
use standalone::{ingest, sync, AppState, ProcessBody};
Expand Down Expand Up @@ -235,6 +235,40 @@ async fn test_cross_repo_muted_preservation() {
);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_sync_hash_scoped_to_exact_repo() {
let state = test_state();
let g = fresh_graph().await;

reset_clones();
let _ = ingest(State(state.clone()), Json(body(BE, Some("before"))))
.await
.expect("backend ingest failed");

let sibling = NodeData {
name: "fayekelmith/graph-update-backend-extra".to_string(),
file: "fayekelmith/graph-update-backend-extra".to_string(),
hash: Some("sentinel".to_string()),
..Default::default()
};
g.graph
.add_node_async(NodeType::Repository, sibling)
.await
.expect("failed to seed sibling repository node");

sync_repo(&state, BE, "after").await;

let hash = g
.graph
.get_repository_hash("https://github.com/fayekelmith/graph-update-backend-extra")
.await
.expect("sibling repository node lost after syncing another repo");
assert_eq!(
hash, "sentinel",
"sibling repository hash must not change when syncing another repo"
);
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_backward_sync_preserves_mute() {
let state = test_state();
Expand Down
Loading