From f68cbd1f69ce41ca323f603069d48e8c559eb5d4 Mon Sep 17 00:00:00 2001 From: Adrien Cacciaguerra Date: Mon, 29 Apr 2024 10:32:35 -0400 Subject: [PATCH] fix: retrieve root_repository_path from git dir --- src/ci_provider/buildkite/provider.rs | 23 +++++--- src/ci_provider/github_actions/provider.rs | 12 +++- src/helpers/find_repository_root.rs | 66 ++++++++++++++++++++++ src/helpers/mod.rs | 2 + 4 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 src/helpers/find_repository_root.rs diff --git a/src/ci_provider/buildkite/provider.rs b/src/ci_provider/buildkite/provider.rs index 56a3343..322e464 100644 --- a/src/ci_provider/buildkite/provider.rs +++ b/src/ci_provider/buildkite/provider.rs @@ -10,7 +10,7 @@ use crate::{ provider::{CIProvider, CIProviderDetector}, }, config::Config, - helpers::get_env_variable, + helpers::{find_repository_root, get_env_variable}, prelude::*, }; @@ -93,6 +93,20 @@ impl TryFrom<&Config> for BuildkiteProvider { let is_pr = get_pr_number()?.is_some(); let (owner, repository) = get_owner_and_repository()?; + let repository_root_path = match find_repository_root(&std::env::current_dir()?) { + Some(mut path) => { + // Add a trailing slash to the path + path.push(""); + path.to_string_lossy().to_string() + } + None => format!( + "/buildkite/builds/{}/{}/{}/", + get_env_variable("BUILDKITE_AGENT_NAME")?, + get_env_variable("BUILDKITE_ORGANIZATION_SLUG")?, + get_env_variable("BUILDKITE_PIPELINE_SLUG")?, + ), + }; + Ok(Self { owner: owner.clone(), repository: repository.clone(), @@ -109,12 +123,7 @@ impl TryFrom<&Config> for BuildkiteProvider { }, commit_hash: get_env_variable("BUILDKITE_COMMIT")?, event: get_run_event()?, - repository_root_path: format!( - "/buildkite/builds/{}/{}/{}/", - get_env_variable("BUILDKITE_AGENT_NAME")?, - get_env_variable("BUILDKITE_ORGANIZATION_SLUG")?, - get_env_variable("BUILDKITE_PIPELINE_SLUG")?, - ), + repository_root_path, }) } } diff --git a/src/ci_provider/github_actions/provider.rs b/src/ci_provider/github_actions/provider.rs index a405f36..727e32e 100644 --- a/src/ci_provider/github_actions/provider.rs +++ b/src/ci_provider/github_actions/provider.rs @@ -10,7 +10,7 @@ use crate::{ provider::{CIProvider, CIProviderDetector}, }, config::Config, - helpers::get_env_variable, + helpers::{find_repository_root, get_env_variable}, prelude::*, }; @@ -82,6 +82,14 @@ impl TryFrom<&Config> for GitHubActionsProvider { let event = serde_json::from_str(&format!("\"{}\"", github_event_name)).context( format!("Event {} is not supported by CodSpeed", github_event_name), )?; + let repository_root_path = match find_repository_root(&std::env::current_dir()?) { + Some(mut path) => { + // Add a trailing slash to the path + path.push(""); + path.to_string_lossy().to_string() + } + None => format!("/home/runner/work/{}/{}/", repository, repository), + }; Ok(Self { owner, @@ -103,7 +111,7 @@ impl TryFrom<&Config> for GitHubActionsProvider { }), }, base_ref: get_env_variable("GITHUB_BASE_REF").ok(), - repository_root_path: format!("/home/runner/work/{}/{}/", repository, repository), + repository_root_path, }) } } diff --git a/src/helpers/find_repository_root.rs b/src/helpers/find_repository_root.rs new file mode 100644 index 0000000..0de143b --- /dev/null +++ b/src/helpers/find_repository_root.rs @@ -0,0 +1,66 @@ +use std::path::{Path, PathBuf}; + +// during normal execution, we want to find the repository root by looking for a .git directory +// during tests, we want `find_repository_root` to always return `None`, so that we don't have to +// create a git repository for each test + +#[cfg(not(test))] +pub fn find_repository_root(base_dir: &Path) -> Option { + _find_repository_root(base_dir) +} + +#[cfg(test)] +pub fn find_repository_root(_base_dir: &Path) -> Option { + None +} + +// the core logic is extracted into a separate function so that it can be tested +fn _find_repository_root(base_dir: &Path) -> Option { + let current_dir = base_dir.canonicalize().ok()?; + + for ancestor in current_dir.ancestors() { + let git_dir = ancestor.join(".git"); + if git_dir.exists() { + return Some(ancestor.to_path_buf()); + } + } + + log::warn!("Could not find repository root"); + + None +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_find_repository_root() { + // create an empty directory in a tmp directory, add a nested .git directory + // and check if the repository root is found when calling _find_repository_root from a nested directory + let tmp_dir = tempfile::tempdir().unwrap(); + let base_dir = tmp_dir.path().join("base-dir"); + let git_dir = base_dir.join(".git"); + std::fs::create_dir_all(git_dir).unwrap(); + let nested_current_dir = base_dir.join("nested").join("deeply"); + std::fs::create_dir_all(&nested_current_dir).unwrap(); + + let repository_root = _find_repository_root(&nested_current_dir).unwrap(); + assert_eq!(repository_root, base_dir.canonicalize().unwrap()); + + tmp_dir.close().unwrap(); + } + + #[test] + fn test_find_repository_root_no_git_dir() { + // create an empty directory in a tmp directory and check if the repository root is not found + let tmp_dir = tempfile::tempdir().unwrap(); + let base_dir = tmp_dir.path().join("base-dir"); + std::fs::create_dir_all(&base_dir).unwrap(); + + let repository_root = _find_repository_root(&base_dir); + assert_eq!(repository_root, None); + + tmp_dir.close().unwrap(); + } +} diff --git a/src/helpers/mod.rs b/src/helpers/mod.rs index b48b7ee..033ca5a 100644 --- a/src/helpers/mod.rs +++ b/src/helpers/mod.rs @@ -1,3 +1,5 @@ +mod find_repository_root; mod get_env_var; +pub use find_repository_root::find_repository_root; pub use get_env_var::get_env_variable;