From fcdb10a7ffb0c4658db390ecdcc96c4e050525a4 Mon Sep 17 00:00:00 2001 From: "Brian J. Tarricone" Date: Sat, 16 Sep 2023 02:35:56 -0700 Subject: [PATCH] Make messages look better and publish multiple for push events For push events, publish one message per commit pushed, up to a limit of 15. --- src/event.rs | 115 +++++++++++++++++++++++++++++++++++---------------- src/main.rs | 45 +++++++++----------- 2 files changed, 100 insertions(+), 60 deletions(-) diff --git a/src/event.rs b/src/event.rs index 4ffb82b..05cf3c1 100644 --- a/src/event.rs +++ b/src/event.rs @@ -2,8 +2,7 @@ pub trait GitlabEventExt { fn project(&self) -> &Project; fn r#ref(&self) -> &str; fn user(&self) -> &str; - fn url(&self) -> String; - fn title(&self) -> String; + fn titles(&self) -> Vec; } #[derive(Debug, Deserialize)] @@ -70,6 +69,7 @@ impl MergeRequestAction { #[derive(Debug, Deserialize)] pub struct MergeRequestObjectAttributes { + pub iid: u64, pub target_branch: String, pub source_branch: String, pub title: String, @@ -158,7 +158,7 @@ pub enum GitlabEvent { #[serde(rename = "pipeline")] Pipeline { object_attributes: PipelineObjectAttributes, - merge_request: PipelineMergeRequest, + merge_request: Option, user: User, project: Project, }, @@ -192,56 +192,101 @@ impl GitlabEventExt for GitlabEvent { } } - fn url(&self) -> String { - let url = match self { - GitlabEvent::Push { after, project, .. } => format!("{}/-/commits/{}", project.web_url, after), - GitlabEvent::TagPush { - r#ref, - checkout_sha, - project, - .. - } => { - let refname = r#ref.split('/').into_iter().last().unwrap_or(checkout_sha); - 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() - } - - fn title(&self) -> String { + fn titles(&self) -> Vec { fn find_commit<'a>(commits: &'a Vec, sha: &str) -> Option<&'a Commit> { commits.iter().find(|commit| commit.id == sha) } match self { - GitlabEvent::Push { after, commits, .. } => find_commit(commits, &after) - .map(|commit| commit.title.clone()) - .unwrap_or_else(|| "New commit(s) pushed".to_string()), + GitlabEvent::Push { + after, + project, + commits, + .. + } => { + const MAX_COMMITS: usize = 15; // TODO: make configurable + commits.iter().fold(Vec::new(), |mut titles, commit| { + if titles.len() < MAX_COMMITS { + titles.push(format!("[**pushed** {}]({})", commit.title, commit.url)); + + if titles.len() == MAX_COMMITS { + titles.push(format!( + "[**pushed** {} more commits]({}/-/compare/{}...{})", + commits.len() - MAX_COMMITS, + project.web_url, + commit.id, + after + )); + } + } + + titles + }) + } GitlabEvent::TagPush { - checkout_sha, commits, .. - } => find_commit(commits, &checkout_sha) - .iter() - .fold("New tag pushed".to_string(), |accum, commit| { - format!("{} ({})", accum, commit.title) - }), + r#ref, + checkout_sha, + project, + commits, + .. + } => { + let title = format!( + "**tagged** {}", + find_commit(commits, &checkout_sha) + .map(|commit| &commit.title) + .unwrap_or(checkout_sha) + ); + let url = format!("{}/-/tags/{}", project.web_url, parse_ref(r#ref)); + vec![markdown_link(&title, &url)] + } GitlabEvent::MergeRequest { object_attributes, .. } => { - format!("MR {}: {}", object_attributes.action.as_str(), object_attributes.title) + let title = format!( + "MR !{} **{}**: {}", + object_attributes.iid, + object_attributes.action.as_str(), + object_attributes.title + ); + vec![markdown_link(&title, &object_attributes.url)] } 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) + let title = object_attributes + .name + .as_ref() + .map(|n| n.clone()) + .or(merge_request.as_ref().map(|mr| mr.title.clone())) + .iter() + .fold( + format!("Pipeline **{}**", object_attributes.status.as_str()), + |accum, title| format!("{}: {}", accum, title), + ); + vec![markdown_link(&title, &object_attributes.url)] } } } } +#[inline] +fn markdown_link(title: &String, url: &String) -> String { + format!("[{}]({})", title, url) +} + +pub fn parse_ref(r#ref: &str) -> String { + if r#ref.starts_with("refs/") { + let parts = r#ref.split('/').collect::>(); + if parts.len() > 2 { + parts.into_iter().skip(2).collect::>().join("/").to_string() + } else { + r#ref.to_string() + } + } else { + r#ref.to_string() + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/main.rs b/src/main.rs index 0015d61..2a6fa96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -105,28 +105,22 @@ async fn ensure_matrix_room_joined(matrix_client: &Client, room_id: &OwnedRoomOr room.ok_or_else(|| anyhow!("Unable to join room {}", room_id)) } -fn build_gitlab_message(event: &GitlabEvent) -> String { +fn build_gitlab_messages(event: &GitlabEvent) -> Vec { let project = event.project(); - let r = event.r#ref(); - let refname = if r.starts_with("refs/") { - let parts = r.split('/').collect::>(); - if parts.len() > 2 { - parts.into_iter().skip(2).collect::>().join("/").to_string() - } else { - drop(parts); - r.to_string() - } - } else { - r.to_string() - }; - format!( - "*{}* {} **{}** [{}]({})", - project.path_with_namespace, - refname, - event.user(), - event.title(), - event.url() - ) + let refname = event::parse_ref(event.r#ref()); + event + .titles() + .iter() + .map(|title| { + format!( + "\\[{}\\] `{}` *{}* {}", + project.path_with_namespace, + refname, + event.user(), + title, + ) + }) + .collect() } async fn handle_gitlab_event( @@ -145,10 +139,11 @@ async fn handle_gitlab_event( } let room = ensure_matrix_room_joined(matrix_client, room_id).await?; - let msg = build_gitlab_message(&event); - debug!("Sending message to {}: {}", room_id, msg); - let msg_content = RoomMessageEventContent::text_markdown(&msg); - room.send(msg_content, None).await?; + for msg in build_gitlab_messages(&event) { + debug!("Sending message to {}: {}", room_id, msg); + let msg_content = RoomMessageEventContent::text_markdown(&msg); + room.send(msg_content, None).await?; + } Ok(()) }