diff --git a/src/run/ci_provider/buildkite/provider.rs b/src/run/ci_provider/buildkite/provider.rs index f719f0f2..b3d3e846 100644 --- a/src/run/ci_provider/buildkite/provider.rs +++ b/src/run/ci_provider/buildkite/provider.rs @@ -1,10 +1,9 @@ use std::env; -use lazy_static::lazy_static; -use regex::Regex; use simplelog::SharedLogger; use crate::prelude::*; +use crate::run::helpers::{parse_git_remote, GitRemote}; use crate::run::{ ci_provider::{ interfaces::{CIProviderMetadata, RepositoryProvider, RunEvent}, @@ -27,16 +26,6 @@ pub struct BuildkiteProvider { repository_root_path: String, } -lazy_static! { - static ref GITHUB_URL_REGEX: Regex = Regex::new( - r"(?x) - (?:https://github.com/|git@github.com:) - (?P[^/]+)/(?P[^/.]+)\.git - " - ) - .expect("Failed to compile GitHub URL regex"); -} - pub fn get_pr_number() -> Result> { Ok(get_env_variable("BUILDKITE_PULL_REQUEST")?.parse().ok()) } @@ -64,24 +53,6 @@ pub fn get_ref() -> Result { } } -pub fn get_owner_and_repository() -> Result<(String, String)> { - let repository_url = get_env_variable("BUILDKITE_REPO")?; - let captures = GITHUB_URL_REGEX - .captures(&repository_url) - .context("Failed to parse the GitHub repository URL")?; - - let owner = captures - .name("owner") - .context("Failed to parse the GitHub repository URL")? - .as_str(); - let repository = captures - .name("repository") - .context("Failed to parse the GitHub repository URL")? - .as_str(); - - Ok((owner.into(), repository.into())) -} - impl TryFrom<&Config> for BuildkiteProvider { type Error = Error; fn try_from(config: &Config) -> Result { @@ -90,7 +61,18 @@ impl TryFrom<&Config> for BuildkiteProvider { } let is_pr = get_pr_number()?.is_some(); - let (owner, repository) = get_owner_and_repository()?; + let repository_url = get_env_variable("BUILDKITE_REPO")?; + let GitRemote { + owner, + repository, + domain, + } = parse_git_remote(&repository_url)?; + + if domain != "github.com" { + bail!( + "Only GitHub repositories are supported by CodSpeed BuildKite integration for now." + ); + } let repository_root_path = match find_repository_root(&std::env::current_dir()?) { Some(mut path) => { @@ -181,29 +163,6 @@ mod tests { }); } - #[test] - fn test_get_owner_and_repository() { - with_var( - "BUILDKITE_REPO", - Some("https://github.com/my-org/adrien-python-test.git"), - || { - let (owner, repository) = get_owner_and_repository().unwrap(); - assert_eq!(owner, "my-org"); - assert_eq!(repository, "adrien-python-test"); - }, - ); - - with_var( - "BUILDKITE_REPO", - Some("git@github.com:my-org/adrien-python-test.git"), - || { - let (owner, repository) = get_owner_and_repository().unwrap(); - assert_eq!(owner, "my-org"); - assert_eq!(repository, "adrien-python-test"); - }, - ); - } - #[test] fn test_try_from_push_main() { with_vars( diff --git a/src/run/ci_provider/local/provider.rs b/src/run/ci_provider/local/provider.rs index f6cb84c8..10ab4760 100644 --- a/src/run/ci_provider/local/provider.rs +++ b/src/run/ci_provider/local/provider.rs @@ -1,9 +1,9 @@ use git2::Repository; -use lazy_static::lazy_static; use simplelog::SharedLogger; use crate::local_logger::get_local_logger; use crate::prelude::*; +use crate::run::helpers::{parse_git_remote, GitRemote}; use crate::run::{ ci_provider::{ interfaces::{CIProviderMetadata, RepositoryProvider, RunEvent}, @@ -27,31 +27,22 @@ pub struct LocalProvider { impl LocalProvider {} -lazy_static! { - static ref REMOTE_REGEX: regex::Regex = regex::Regex::new( - r"(?P[^/@\.]+)\.\w+[:/](?P[^/]+)/(?P[^/]+)\.git" - ) - .unwrap(); -} - fn extract_provider_owner_and_repository_from_remote_url( remote_url: &str, ) -> Result<(RepositoryProvider, String, String)> { - let captures = REMOTE_REGEX.captures(remote_url).ok_or_else(|| { - anyhow!( - "Could not extract owner and repository from remote url: {}", - remote_url - ) - })?; - - let domain = captures.name("domain").unwrap().as_str(); - let repository_provider = serde_json::from_str(&format!("\"{}\"", domain.to_uppercase())) - .context(format!( + let GitRemote { + domain, + owner, + repository, + } = parse_git_remote(remote_url)?; + let repository_provider = match domain.as_str() { + "github.com" => RepositoryProvider::GitHub, + "gitlab.com" => RepositoryProvider::GitLab, + domain => bail!( "Repository provider {} is not supported by CodSpeed", domain - ))?; - let owner = captures.name("owner").unwrap().as_str(); - let repository = captures.name("repository").unwrap().as_str(); + ), + }; Ok(( repository_provider, diff --git a/src/run/helpers/mod.rs b/src/run/helpers/mod.rs index 033ca5ab..868c6b99 100644 --- a/src/run/helpers/mod.rs +++ b/src/run/helpers/mod.rs @@ -1,5 +1,7 @@ mod find_repository_root; mod get_env_var; +mod parse_git_remote; pub use find_repository_root::find_repository_root; pub use get_env_var::get_env_variable; +pub use parse_git_remote::*; diff --git a/src/run/helpers/parse_git_remote.rs b/src/run/helpers/parse_git_remote.rs new file mode 100644 index 00000000..579ecda9 --- /dev/null +++ b/src/run/helpers/parse_git_remote.rs @@ -0,0 +1,93 @@ +use anyhow::{anyhow, Result}; +use lazy_static::lazy_static; + +lazy_static! { + static ref REMOTE_REGEX: regex::Regex = regex::Regex::new( + r"(?P[^/@\.]+\.\w+)[:/](?P[^/]+)/(?P[^/]+?)(\.git)?$" + ) + .unwrap(); +} + +#[derive(Debug)] +pub struct GitRemote { + pub domain: String, + pub owner: String, + pub repository: String, +} + +pub fn parse_git_remote(remote: &str) -> Result { + let captures = REMOTE_REGEX.captures(remote).ok_or_else(|| { + anyhow!( + "Could not extract owner and repository from remote url: {}", + remote + ) + })?; + + let domain = captures.name("domain").unwrap().as_str(); + let owner = captures.name("owner").unwrap().as_str(); + let repository = captures.name("repository").unwrap().as_str(); + + Ok(GitRemote { + domain: domain.to_string(), + owner: owner.to_string(), + repository: repository.to_string(), + }) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_git_remote() { + let remote = "git@github.com:CodSpeedHQ/runner.git"; + let git_remote = parse_git_remote(remote).unwrap(); + insta::assert_debug_snapshot!(git_remote, @r###" + GitRemote { + domain: "github.com", + owner: "CodSpeedHQ", + repository: "runner", + } + "###); + + let remote = "https://github.com/CodSpeedHQ/runner.git"; + let git_remote = parse_git_remote(remote).unwrap(); + insta::assert_debug_snapshot!(git_remote, @r###" + GitRemote { + domain: "github.com", + owner: "CodSpeedHQ", + repository: "runner", + } + "###); + + let remote = "https://github.com/CodSpeedHQ/runner"; + let git_remote = parse_git_remote(remote).unwrap(); + insta::assert_debug_snapshot!(git_remote, @r###" + GitRemote { + domain: "github.com", + owner: "CodSpeedHQ", + repository: "runner", + } + "###); + + let remote = "git@gitlab.com:codspeed/runner.git"; + let git_remote = parse_git_remote(remote).unwrap(); + insta::assert_debug_snapshot!(git_remote, @r###" + GitRemote { + domain: "gitlab.com", + owner: "codspeed", + repository: "runner", + } + "###); + + let remote = "https://gitlab.com/codspeed/runner.git"; + let git_remote = parse_git_remote(remote).unwrap(); + insta::assert_debug_snapshot!(git_remote, @r###" + GitRemote { + domain: "gitlab.com", + owner: "codspeed", + repository: "runner", + } + "###); + } +}