From 985593513b4f1c804e52f88df186e157ddb15725 Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Fri, 15 Sep 2023 12:51:33 -0700 Subject: [PATCH] Add support for pipeline events --- src/event.rs | 81 ++++++++++- src/main.rs | 8 +- test-data/pipeline-event.json | 262 ++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+), 9 deletions(-) create mode 100644 test-data/pipeline-event.json diff --git a/src/event.rs b/src/event.rs index 667844e..cd0d3ad 100644 --- a/src/event.rs +++ b/src/event.rs @@ -20,10 +20,6 @@ pub struct Project { pub namespace: String, pub path_with_namespace: String, pub default_branch: String, - pub homepage: String, - pub url: String, - pub ssh_url: String, - pub http_url: String, } #[derive(Debug, Deserialize)] @@ -31,7 +27,6 @@ pub struct Repository { pub name: String, pub url: String, pub description: String, - pub homepage: String, } #[derive(Debug, Deserialize)] @@ -74,7 +69,7 @@ impl MergeRequestAction { } #[derive(Debug, Deserialize)] -pub struct ObjectAttributes { +pub struct MergeRequestObjectAttributes { pub target_branch: String, pub source_branch: String, pub title: String, @@ -84,6 +79,36 @@ pub struct ObjectAttributes { pub action: MergeRequestAction, } +#[derive(PartialEq, Debug, Deserialize)] +pub enum PipelineStatus { + #[serde(rename = "failed")] + Failed, + #[serde(other)] + Other, +} + +impl PipelineStatus { + pub fn as_str(&self) -> &str { + match self { + PipelineStatus::Failed => "failed", + PipelineStatus::Other => "other", + } + } +} + +#[derive(Debug, Deserialize)] +pub struct PipelineObjectAttributes { + pub name: Option, + pub r#ref: String, + pub status: PipelineStatus, + pub url: String, +} + +#[derive(Debug, Deserialize)] +pub struct PipelineMergeRequest { + pub title: String, +} + #[derive(Debug, Deserialize)] #[serde(tag = "object_kind")] pub enum GitlabEvent { @@ -128,7 +153,14 @@ pub enum GitlabEvent { user: User, project: Project, repository: Repository, - object_attributes: ObjectAttributes, + object_attributes: MergeRequestObjectAttributes, + }, + #[serde(rename = "pipeline")] + Pipeline { + object_attributes: PipelineObjectAttributes, + merge_request: PipelineMergeRequest, + user: User, + project: Project, }, } @@ -138,6 +170,7 @@ impl GitlabEventExt for GitlabEvent { GitlabEvent::Push { project, .. } => &project, GitlabEvent::TagPush { project, .. } => &project, GitlabEvent::MergeRequest { project, .. } => &project, + GitlabEvent::Pipeline { project, .. } => &project, } } @@ -146,6 +179,7 @@ impl GitlabEventExt for GitlabEvent { GitlabEvent::Push { r#ref, .. } => &r#ref, GitlabEvent::TagPush { r#ref, .. } => &r#ref, GitlabEvent::MergeRequest { object_attributes, .. } => &object_attributes.target_branch, + GitlabEvent::Pipeline { object_attributes, .. } => &object_attributes.r#ref, } } @@ -154,6 +188,7 @@ impl GitlabEventExt for GitlabEvent { GitlabEvent::Push { user_name, .. } => &user_name, GitlabEvent::TagPush { user_name, .. } => &user_name, GitlabEvent::MergeRequest { user, .. } => &user.name, + GitlabEvent::Pipeline { user, .. } => &user.name, } } @@ -170,6 +205,7 @@ impl GitlabEventExt for GitlabEvent { format!("{}/-/tags/{}", project.web_url, refname) } GitlabEvent::MergeRequest { object_attributes, .. } => object_attributes.url.clone(), + GitlabEvent::Pipeline { object_attributes, .. } => object_attributes.url.clone(), }; url.replace("http://", "https://").to_string() @@ -192,6 +228,14 @@ impl GitlabEventExt for GitlabEvent { GitlabEvent::MergeRequest { object_attributes, .. } => { format!("MR {}: {}", object_attributes.action.as_str(), object_attributes.title) } + GitlabEvent::Pipeline { + object_attributes, + merge_request, + .. + } => { + let title = object_attributes.name.as_ref().unwrap_or(&merge_request.title); + format!("Pipeline {}: {}", object_attributes.status.as_str(), title) + } } } } @@ -296,4 +340,27 @@ mod test { Ok(()) } + + #[test] + pub fn parse_pipeline_event() -> anyhow::Result<()> { + let event = load_test_data("pipeline-event")?; + + match event { + GitlabEvent::Pipeline { + object_attributes, + merge_request, + user, + .. + } => { + assert_eq!(object_attributes.name, Some("Pipeline for branch: master".to_string())); + assert_eq!(object_attributes.r#ref, "master"); + assert_eq!(object_attributes.status, PipelineStatus::Failed); + assert_eq!(merge_request.title, "Test"); + assert_eq!(user.name, "Administrator"); + } + _ => panic!("not a pipeline event"), + }; + + Ok(()) + } } diff --git a/src/main.rs b/src/main.rs index 0b0afca..7fd4c1d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,7 +22,7 @@ use matrix_sdk::{ }; use warp::Filter; -use crate::event::MergeRequestAction; +use crate::event::{MergeRequestAction, PipelineStatus}; async fn build_sync_settings(matrix_client: &Client) -> SyncSettings { let mut settings = SyncSettings::default().timeout(Duration::from_secs(30)); @@ -131,6 +131,10 @@ async fn handle_gitlab_event( if object_attributes.action == MergeRequestAction::Other { return Ok(()); } + } else if let GitlabEvent::Pipeline { object_attributes, .. } = &event { + if object_attributes.status == PipelineStatus::Other { + return Ok(()); + } } let room = ensure_matrix_room_joined(matrix_client, room_id).await?; @@ -168,7 +172,7 @@ async fn run() -> anyhow::Result<()> { async move { let project = event.project(); - let config_key = project.homepage.replace("http://", "").replace("https://", ""); + let config_key = project.web_url.replace("http://", "").replace("https://", ""); if let Some(repo_config) = config.repo_configs.get(&config_key) { if !constant_time_eq(token.as_bytes(), repo_config.token.as_bytes()) { warn!("Invalid token for repo '{}'", config_key); diff --git a/test-data/pipeline-event.json b/test-data/pipeline-event.json new file mode 100644 index 0000000..a8ba32c --- /dev/null +++ b/test-data/pipeline-event.json @@ -0,0 +1,262 @@ +{ + "object_kind": "pipeline", + "object_attributes":{ + "id": 31, + "iid": 3, + "name": "Pipeline for branch: master", + "ref": "master", + "tag": false, + "sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "before_sha": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "source": "merge_request_event", + "status": "failed", + "stages":[ + "build", + "test", + "deploy" + ], + "created_at": "2016-08-12 15:23:28 UTC", + "finished_at": "2016-08-12 15:26:29 UTC", + "duration": 63, + "variables": [ + { + "key": "NESTOR_PROD_ENVIRONMENT", + "value": "us-west-1" + } + ], + "url": "http://example.com/gitlab-org/gitlab-test/-/pipelines/31" + }, + "merge_request": { + "id": 1, + "iid": 1, + "title": "Test", + "source_branch": "test", + "source_project_id": 1, + "target_branch": "master", + "target_project_id": 1, + "state": "opened", + "merge_status": "can_be_merged", + "detailed_merge_status": "mergeable", + "url": "http://192.168.64.1:3005/gitlab-org/gitlab-test/merge_requests/1" + }, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "user_email@gitlab.com" + }, + "project":{ + "id": 1, + "name": "Gitlab Test", + "description": "Atque in sunt eos similique dolores voluptatem.", + "web_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test", + "avatar_url": null, + "git_ssh_url": "git@192.168.64.1:gitlab-org/gitlab-test.git", + "git_http_url": "http://192.168.64.1:3005/gitlab-org/gitlab-test.git", + "namespace": "Gitlab Org", + "visibility_level": 20, + "path_with_namespace": "gitlab-org/gitlab-test", + "default_branch": "master" + }, + "commit":{ + "id": "bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "message": "test\n", + "timestamp": "2016-08-12T17:23:21+02:00", + "url": "http://example.com/gitlab-org/gitlab-test/commit/bcbb5ec396a2c0f828686f14fac9b80b780504f2", + "author":{ + "name": "User", + "email": "user@gitlab.com" + } + }, + "source_pipeline":{ + "project":{ + "id": 41, + "web_url": "https://gitlab.example.com/gitlab-org/upstream-project", + "path_with_namespace": "gitlab-org/upstream-project" + }, + "pipeline_id": 30, + "job_id": 3401 + }, + "builds":[ + { + "id": 380, + "stage": "deploy", + "name": "production", + "status": "skipped", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": null, + "finished_at": null, + "duration": null, + "queued_duration": null, + "failure_reason": null, + "when": "manual", + "manual": true, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": null, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": { + "name": "production", + "action": "start", + "deployment_tier": "production" + } + }, + { + "id": 377, + "stage": "test", + "name": "test-image", + "status": "success", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": "2016-08-12 15:26:12 UTC", + "finished_at": "2016-08-12 15:26:29 UTC", + "duration": 17.0, + "queued_duration": 196.0, + "failure_reason": null, + "when": "on_success", + "manual": false, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": { + "id": 380987, + "description": "shared-runners-manager-6.gitlab.com", + "active": true, + "runner_type": "instance_type", + "is_shared": true, + "tags": [ + "linux", + "docker", + "shared-runner" + ] + }, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": null + }, + { + "id": 378, + "stage": "test", + "name": "test-build", + "status": "failed", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": "2016-08-12 15:26:12 UTC", + "finished_at": "2016-08-12 15:26:29 UTC", + "duration": 17.0, + "queued_duration": 196.0, + "failure_reason": "script_failure", + "when": "on_success", + "manual": false, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": { + "id":380987, + "description":"shared-runners-manager-6.gitlab.com", + "active":true, + "runner_type": "instance_type", + "is_shared": true, + "tags": [ + "linux", + "docker" + ] + }, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": null + }, + { + "id": 376, + "stage": "build", + "name": "build-image", + "status": "success", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": "2016-08-12 15:24:56 UTC", + "finished_at": "2016-08-12 15:25:26 UTC", + "duration": 17.0, + "queued_duration": 196.0, + "failure_reason": null, + "when": "on_success", + "manual": false, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": { + "id": 380987, + "description": "shared-runners-manager-6.gitlab.com", + "active": true, + "runner_type": "instance_type", + "is_shared": true, + "tags": [ + "linux", + "docker" + ] + }, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": null + }, + { + "id": 379, + "stage": "deploy", + "name": "staging", + "status": "created", + "created_at": "2016-08-12 15:23:28 UTC", + "started_at": null, + "finished_at": null, + "duration": null, + "queued_duration": null, + "failure_reason": null, + "when": "on_success", + "manual": false, + "allow_failure": false, + "user":{ + "id": 1, + "name": "Administrator", + "username": "root", + "avatar_url": "http://www.gravatar.com/avatar/e32bd13e2add097461cb96824b7a829c?s=80\u0026d=identicon", + "email": "admin@example.com" + }, + "runner": null, + "artifacts_file":{ + "filename": null, + "size": null + }, + "environment": { + "name": "staging", + "action": "start", + "deployment_tier": "staging" + } + } + ] +}