diff options
| -rw-r--r-- | server/common/src/git.rs | 39 | ||||
| -rw-r--r-- | server/common/src/tests.rs | 10 | ||||
| -rw-r--r-- | server/src/git_root.rs | 2 |
3 files changed, 41 insertions, 10 deletions
diff --git a/server/common/src/git.rs b/server/common/src/git.rs index 053ff3f..8fe7863 100644 --- a/server/common/src/git.rs +++ b/server/common/src/git.rs @@ -122,6 +122,22 @@ fn parse_tree_entries(output: String) -> Vec<TreeEntry> { ret } +fn branch_eq(a: impl AsRef<str>, b: impl AsRef<str>) -> bool { + let a = a.as_ref(); + let b = b.as_ref(); + if a.starts_with("refs/heads/") { + if b.starts_with("refs/heads/") { + return a[11..] == b[11..]; + } + return a == format!("refs/heads/{b}"); + } else { + if b.starts_with("refs/heads/") { + return format!("refs/heads/{a}") == b; + } + return a == b; + } +} + impl RepoData { fn new() -> Self { Self { @@ -130,7 +146,7 @@ impl RepoData { } } - async fn fetch(&self, repo: &Repository, branch: String) -> Result<(), Error> { + async fn fetch(&self, repo: &Repository, branch: String) -> Result<String, Error> { if repo.remote.is_none() { return Err(Error::new("No remote set")); } @@ -149,9 +165,24 @@ impl RepoData { // <+ force update><remote branch>:<local branch> cmd.arg(format!("+{branch}:{branch}")); - self.output(&mut cmd).await?; + let output = self.output(&mut cmd).await?; - Ok(()) + // git fetch porcelain format: + // <flag> <old-object-id> <new-object-id> <local-reference> + for line in output.lines() { + let mut parts = line.split(' '); + parts.next(); // flag + parts.next(); // old-object-id + if let Some(new_object_id) = parts.next() { + let local_reference = parts.collect::<Vec<&str>>().join(" "); + if branch_eq(local_reference, &branch) { + return Ok(new_object_id.to_string()); + } + } + } + + assert!(false); + Err(Error::new("Fetch succeeded but branch not found")) } async fn init(&mut self, repo: &Repository) -> Result<(), Error> { @@ -590,7 +621,7 @@ impl Repository { Ok(()) } - pub async fn fetch(&self, branch: impl Into<String>) -> Result<(), Error> { + pub async fn fetch(&self, branch: impl Into<String>) -> Result<String, Error> { let branch = branch.into(); let data = self.lock.read().await; diff --git a/server/common/src/tests.rs b/server/common/src/tests.rs index 34cc315..c8553f7 100644 --- a/server/common/src/tests.rs +++ b/server/common/src/tests.rs @@ -272,15 +272,15 @@ async fn git_fetch(bare: bool) -> git::Repository { repo.fetch("branch"), repo.fetch("other"), ); - main.unwrap(); - branch.unwrap(); - other.unwrap(); + assert_eq!(main.unwrap(), "d7c502b9c6b833060576a0c4da0287933d603011"); + assert_eq!(branch.unwrap(), "2d05d489d42d4f36dd0ebf52502f243991e010eb"); + assert_eq!(other.unwrap(), "2cecdec660a30bf3964cee645d9cee03640ef8dc"); } else { // Not bare repo will complain when you try to fetch into the currently checked // out branch. So just try fetching other branches. let (branch, other) = tokio::join!(repo.fetch("branch"), repo.fetch("other")); - branch.unwrap(); - other.unwrap(); + assert_eq!(branch.unwrap(), "2d05d489d42d4f36dd0ebf52502f243991e010eb"); + assert_eq!(other.unwrap(), "2cecdec660a30bf3964cee645d9cee03640ef8dc"); } repo } diff --git a/server/src/git_root.rs b/server/src/git_root.rs index 01cc2b5..71ad96f 100644 --- a/server/src/git_root.rs +++ b/server/src/git_root.rs @@ -535,7 +535,7 @@ async fn setup_project_root( let bg_project_id = project_id.clone(); tokio::spawn(async move { match bg_repo.fetch(&main_branch).await { - Ok(()) => {} + Ok(_) => {} Err(e) => { error!("{bg_project_id}: fetch {main_branch} returned {e:?}"); } |
