Skip to content

Commit

Permalink
feat(gitlab): implement gitlab ci provider
Browse files Browse the repository at this point in the history
  • Loading branch information
fargito committed Oct 31, 2024
1 parent 9522c80 commit e9ba710
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 6 deletions.
1 change: 1 addition & 0 deletions src/run/ci_provider/buildkite/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ impl CIProvider for BuildkiteProvider {
ref_: self.ref_.clone(),
repository_root_path: self.repository_root_path.clone(),
gh_data: None,
gl_data: None,
sender: None,
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ expression: provider_metadata
"event": "pull_request",
"sender": null,
"ghData": null,
"glData": null,
"repositoryRootPath": "/buildkite/builds/7b10eca7600b-1/my-org/buildkite-test/"
}
1 change: 1 addition & 0 deletions src/run/ci_provider/github_actions/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ impl CIProvider for GitHubActionsProvider {
head_ref: self.head_ref.clone(),
event: self.event.clone(),
gh_data: Some(self.gh_data.clone()),
gl_data: None,
sender: self.sender.clone(),
owner: self.owner.clone(),
repository: self.repository.clone(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ expression: provider_metadata
"runId": "6957110437",
"job": "log-env"
},
"glData": null,
"repositoryRootPath": "/home/runner/work/adrien-python-test/adrien-python-test/"
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ expression: provider_metadata
"runId": "6957110437",
"job": "log-env"
},
"glData": null,
"repositoryRootPath": "/home/runner/work/adrien-python-test/adrien-python-test/"
}
260 changes: 255 additions & 5 deletions src/run/ci_provider/gitlab_ci/provider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,117 @@ use simplelog::SharedLogger;
use std::env;

use crate::prelude::*;
use crate::run::ci_provider::interfaces::ProviderMetadata;
use crate::run::ci_provider::interfaces::{
CIProviderMetadata, GlData, RepositoryProvider, RunEvent, Sender,
};
use crate::run::ci_provider::provider::CIProviderDetector;
use crate::run::ci_provider::CIProvider;
use crate::run::config::Config;
use crate::run::helpers::get_env_variable;

use super::logger::GitLabCILogger;

#[derive(Debug)]
pub struct GitLabCIProvider {}
pub struct GitLabCIProvider {
owner: String,
repository: String,
ref_: String,
head_ref: Option<String>,
base_ref: Option<String>,
gl_data: GlData,
sender: Sender,
event: RunEvent,
repository_root_path: String,
}

impl TryFrom<&Config> for GitLabCIProvider {
type Error = Error;
fn try_from(_config: &Config) -> Result<Self> {
Ok(Self {})
let owner = get_env_variable("CI_PROJECT_NAMESPACE")?;
let repository = get_env_variable("CI_PROJECT_NAME")?;

let ci_pipeline_source = get_env_variable("CI_PIPELINE_SOURCE")?;
let branch_name = get_env_variable("CI_COMMIT_REF_NAME")?;
let branch_ref = format!("refs/heads/{branch_name}");

// https://docs.gitlab.com/ee/ci/jobs/job_rules.html#ci_pipeline_source-predefined-variable
let (event, ref_, base_ref, head_ref) = match ci_pipeline_source.as_str() {
// For pipelines created when a merge request is created or updated. Required to enable merge request pipelines, merged results pipelines, and merge trains.
// https://docs.gitlab.com/ee/ci/variables/predefined_variables.html#predefined-variables-for-merge-request-pipelines
"merge_request_event" => {
let merge_request_id = get_env_variable("CI_MERGE_REQUEST_IID")?;
let target_branch_name = get_env_variable("CI_MERGE_REQUEST_TARGET_BRANCH_NAME")?;
let source_branch_name = get_env_variable("CI_MERGE_REQUEST_SOURCE_BRANCH_NAME")?;

// check if the merge request is from a fork
let ci_project_path = get_env_variable("CI_PROJECT_PATH")?;
let ci_merge_request_source_project_path =
get_env_variable("CI_MERGE_REQUEST_SOURCE_PROJECT_PATH")?;

if ci_project_path != ci_merge_request_source_project_path {
let fork_owner = ci_merge_request_source_project_path
.split('/')
.next()
.expect("Malformed Source Project Path");

(
RunEvent::PullRequest,
format!("refs/pull/{merge_request_id}/merge"),
Some(target_branch_name),
Some(format!("{fork_owner}:{source_branch_name}")),
)
} else {
(
RunEvent::PullRequest,
format!("refs/pull/{merge_request_id}/merge"),
Some(target_branch_name),
Some(source_branch_name),
)
}
}

// For pipelines triggered by a Git push event, including for branches and tags.
"push" => (RunEvent::Push, branch_ref, Some(branch_name), None),

// For scheduled pipelines.
"schedule" => (RunEvent::Schedule, branch_ref, Some(branch_name), None),

// For pipelines created by using a trigger token or created via the GitLab UI.
"trigger" | "web" => (
RunEvent::WorkflowDispatch,
branch_ref,
Some(branch_name),
None,
),

_ => bail!("Event {} is not supported by CodSpeed", ci_pipeline_source),
};

let run_id = get_env_variable("CI_JOB_ID")?;
let job = get_env_variable("CI_JOB_NAME")?;

let gitlab_user_id = get_env_variable("GITLAB_USER_ID")?;
let gitlab_user_login = get_env_variable("GITLAB_USER_LOGIN")?;

let gl_data = GlData { run_id, job };
let sender = Sender {
id: gitlab_user_id,
login: gitlab_user_login,
};

let repository_root_path = get_env_variable("CI_PROJECT_DIR")?;

Ok(Self {
owner,
repository,
ref_,
head_ref,
base_ref,
gl_data,
sender,
event,
repository_root_path,
})
}
}

Expand All @@ -27,6 +124,10 @@ impl CIProviderDetector for GitLabCIProvider {
}

impl CIProvider for GitLabCIProvider {
fn get_repository_provider(&self) -> RepositoryProvider {
RepositoryProvider::Gitlab
}

fn get_logger(&self) -> Box<dyn SharedLogger> {
Box::new(GitLabCILogger::new())
}
Expand All @@ -39,7 +140,156 @@ impl CIProvider for GitLabCIProvider {
"gitlab-ci"
}

fn get_provider_metadata(&self) -> Result<ProviderMetadata> {
unimplemented!()
fn get_ci_provider_metadata(&self) -> Result<CIProviderMetadata> {
Ok(CIProviderMetadata {
base_ref: self.base_ref.clone(),
head_ref: self.head_ref.clone(),
event: self.event.clone(),
gh_data: None,
gl_data: Some(self.gl_data.clone()),
sender: Some(self.sender.clone()),
owner: self.owner.clone(),
repository: self.repository.clone(),
ref_: self.ref_.clone(),
repository_root_path: self.repository_root_path.clone(),
})
}
}

#[cfg(test)]
mod tests {
use insta::assert_json_snapshot;
use temp_env::{with_var, with_vars};

use crate::VERSION;

use super::*;

#[test]
fn test_detect() {
with_var("GITLAB_CI", Some("true"), || {
assert!(GitLabCIProvider::detect());
});
}

#[test]
fn test_push_main_provider_metadata() {
with_vars(
[
("GITLAB_CI", Some("true")),
("CI_PROJECT_DIR", Some("/builds/owner/repository")),
("GITLAB_USER_ID", Some("1234567890")),
("GITLAB_USER_LOGIN", Some("actor")),
("CI_PROJECT_NAME", Some("repository")),
("CI_PROJECT_NAMESPACE", Some("owner")),
("CI_JOB_NAME", Some("job")),
("CI_JOB_ID", Some("1234567890")),
("CI_PIPELINE_SOURCE", Some("push")),
("CI_COMMIT_REF_NAME", Some("main")),
],
|| {
let config = Config {
token: Some("token".into()),
..Config::test()
};
let gitlab_ci_provider = GitLabCIProvider::try_from(&config).unwrap();
let provider_metadata = gitlab_ci_provider.get_ci_provider_metadata().unwrap();

assert_json_snapshot!(provider_metadata, {
".runner.version" => insta::dynamic_redaction(|value,_path| {
assert_eq!(value.as_str().unwrap(), VERSION.to_string());
"[version]"
}),
});
},
)
}

#[test]
fn test_merge_request_provider_metadata() {
with_vars(
[
("GITLAB_CI", Some("true")),
("CI_PROJECT_DIR", Some("/builds/owner/repository")),
("GITLAB_USER_ID", Some("19605940")),
("GITLAB_USER_LOGIN", Some("actor")),
("CI_PROJECT_NAME", Some("repository")),
("CI_PROJECT_NAMESPACE", Some("owner")),
("CI_JOB_NAME", Some("build-job")),
("CI_JOB_ID", Some("6957110437")),
("CI_PIPELINE_SOURCE", Some("merge_request_event")),
("CI_COMMIT_REF_NAME", Some("main")),
("CI_MERGE_REQUEST_IID", Some("5")),
("CI_MERGE_REQUEST_TARGET_BRANCH_NAME", Some("main")),
(
"CI_MERGE_REQUEST_SOURCE_BRANCH_NAME",
Some("feat/awesome-feature"),
),
("CI_PROJECT_PATH", Some("owner/repository")),
(
"CI_MERGE_REQUEST_SOURCE_PROJECT_PATH",
Some("owner/repository"),
),
],
|| {
let config = Config {
token: Some("token".into()),
..Config::test()
};
let gitlab_ci_provider = GitLabCIProvider::try_from(&config).unwrap();
let provider_metadata = gitlab_ci_provider.get_ci_provider_metadata().unwrap();

assert_json_snapshot!(provider_metadata, {
".runner.version" => insta::dynamic_redaction(|value,_path| {
assert_eq!(value.as_str().unwrap(), VERSION.to_string());
"[version]"
}),
});
},
);
}

#[test]
fn test_fork_merge_request_provider_metadata() {
with_vars(
[
("GITLAB_CI", Some("true")),
("CI_PROJECT_DIR", Some("/builds/owner/repository")),
("GITLAB_USER_ID", Some("19605940")),
("GITLAB_USER_LOGIN", Some("actor")),
("CI_PROJECT_NAME", Some("repository")),
("CI_PROJECT_NAMESPACE", Some("owner")),
("CI_JOB_NAME", Some("build-job")),
("CI_JOB_ID", Some("6957110437")),
("CI_PIPELINE_SOURCE", Some("merge_request_event")),
("CI_COMMIT_REF_NAME", Some("main")),
("CI_MERGE_REQUEST_IID", Some("5")),
("CI_MERGE_REQUEST_TARGET_BRANCH_NAME", Some("main")),
(
"CI_MERGE_REQUEST_SOURCE_BRANCH_NAME",
Some("feat/awesome-feature"),
),
("CI_PROJECT_PATH", Some("owner/repository")),
(
"CI_MERGE_REQUEST_SOURCE_PROJECT_PATH",
Some("fork-owner/fork-repository"),
),
],
|| {
let config = Config {
token: Some("token".into()),
..Config::test()
};
let gitlab_ci_provider = GitLabCIProvider::try_from(&config).unwrap();
let provider_metadata = gitlab_ci_provider.get_ci_provider_metadata().unwrap();

assert_json_snapshot!(provider_metadata, {
".runner.version" => insta::dynamic_redaction(|value,_path| {
assert_eq!(value.as_str().unwrap(), VERSION.to_string());
"[version]"
}),
});
},
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: src/run/ci_provider/gitlab_ci/provider.rs
expression: provider_metadata
---
{
"ref": "refs/pull/5/merge",
"headRef": "fork-owner:feat/awesome-feature",
"baseRef": "main",
"owner": "owner",
"repository": "repository",
"event": "pull_request",
"sender": {
"id": "19605940",
"login": "actor"
},
"ghData": null,
"glData": {
"runId": "6957110437",
"job": "build-job"
},
"repositoryRootPath": "/builds/owner/repository"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: src/run/ci_provider/gitlab_ci/provider.rs
expression: provider_metadata
---
{
"ref": "refs/pull/5/merge",
"headRef": "feat/awesome-feature",
"baseRef": "main",
"owner": "owner",
"repository": "repository",
"event": "pull_request",
"sender": {
"id": "19605940",
"login": "actor"
},
"ghData": null,
"glData": {
"runId": "6957110437",
"job": "build-job"
},
"repositoryRootPath": "/builds/owner/repository"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: src/run/ci_provider/gitlab_ci/provider.rs
expression: provider_metadata
---
{
"ref": "refs/heads/main",
"headRef": null,
"baseRef": "main",
"owner": "owner",
"repository": "repository",
"event": "push",
"sender": {
"id": "1234567890",
"login": "actor"
},
"ghData": null,
"glData": {
"runId": "1234567890",
"job": "job"
},
"repositoryRootPath": "/builds/owner/repository"
}
Loading

0 comments on commit e9ba710

Please sign in to comment.