370 lines
11 KiB
Rust
370 lines
11 KiB
Rust
pub trait GitlabEventExt {
|
|
fn project(&self) -> &Project;
|
|
fn r#ref(&self) -> &str;
|
|
fn user(&self) -> &str;
|
|
fn url(&self) -> String;
|
|
fn title(&self) -> String;
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct User {
|
|
name: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Project {
|
|
pub name: String,
|
|
pub description: String,
|
|
pub web_url: String,
|
|
pub avatar_url: Option<String>,
|
|
pub namespace: String,
|
|
pub path_with_namespace: String,
|
|
pub default_branch: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Repository {
|
|
pub name: String,
|
|
pub url: String,
|
|
pub description: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct Commit {
|
|
pub id: String,
|
|
pub title: String,
|
|
pub url: String,
|
|
}
|
|
|
|
#[derive(PartialEq, Debug, Deserialize)]
|
|
pub enum MergeRequestAction {
|
|
#[serde(rename = "open")]
|
|
Opened,
|
|
#[serde(rename = "close")]
|
|
Closed,
|
|
#[serde(rename = "reopen")]
|
|
Reopened,
|
|
#[serde(rename = "update")]
|
|
Updated,
|
|
#[serde(rename = "approved")]
|
|
Approved,
|
|
#[serde(rename = "unapproved")]
|
|
Unapproved,
|
|
#[serde(rename = "merge")]
|
|
Merged,
|
|
#[serde(other)]
|
|
Other,
|
|
}
|
|
|
|
impl MergeRequestAction {
|
|
pub fn as_str(&self) -> &str {
|
|
match self {
|
|
MergeRequestAction::Opened => "opened",
|
|
MergeRequestAction::Closed => "closed",
|
|
MergeRequestAction::Reopened => "reopened",
|
|
MergeRequestAction::Updated => "updated",
|
|
MergeRequestAction::Approved => "approved",
|
|
MergeRequestAction::Unapproved => "unapproved",
|
|
MergeRequestAction::Merged => "merged",
|
|
MergeRequestAction::Other => "other",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct MergeRequestObjectAttributes {
|
|
pub target_branch: String,
|
|
pub source_branch: String,
|
|
pub title: String,
|
|
pub url: String,
|
|
pub source: Project,
|
|
pub target: Project,
|
|
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<String>,
|
|
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 {
|
|
#[serde(rename = "push")]
|
|
Push {
|
|
event_name: String,
|
|
before: String,
|
|
after: String,
|
|
r#ref: String,
|
|
ref_protected: bool,
|
|
checkout_sha: String,
|
|
user_id: u64,
|
|
user_name: String,
|
|
user_username: String,
|
|
user_email: String,
|
|
user_avatar: Option<String>,
|
|
project_id: u64,
|
|
project: Project,
|
|
repository: Repository,
|
|
commits: Vec<Commit>,
|
|
total_commits_count: u64,
|
|
},
|
|
#[serde(rename = "tag_push")]
|
|
TagPush {
|
|
event_name: String,
|
|
before: String,
|
|
after: String,
|
|
r#ref: String,
|
|
ref_protected: bool,
|
|
checkout_sha: String,
|
|
user_id: u64,
|
|
user_name: String,
|
|
user_avatar: Option<String>,
|
|
project_id: u64,
|
|
project: Project,
|
|
repository: Repository,
|
|
commits: Vec<Commit>,
|
|
total_commits_count: u64,
|
|
},
|
|
#[serde(rename = "merge_request")]
|
|
MergeRequest {
|
|
user: User,
|
|
project: Project,
|
|
repository: Repository,
|
|
object_attributes: MergeRequestObjectAttributes,
|
|
},
|
|
#[serde(rename = "pipeline")]
|
|
Pipeline {
|
|
object_attributes: PipelineObjectAttributes,
|
|
merge_request: PipelineMergeRequest,
|
|
user: User,
|
|
project: Project,
|
|
},
|
|
}
|
|
|
|
impl GitlabEventExt for GitlabEvent {
|
|
fn project(&self) -> &Project {
|
|
match self {
|
|
GitlabEvent::Push { project, .. } => &project,
|
|
GitlabEvent::TagPush { project, .. } => &project,
|
|
GitlabEvent::MergeRequest { project, .. } => &project,
|
|
GitlabEvent::Pipeline { project, .. } => &project,
|
|
}
|
|
}
|
|
|
|
fn r#ref(&self) -> &str {
|
|
match self {
|
|
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,
|
|
}
|
|
}
|
|
|
|
fn user(&self) -> &str {
|
|
match self {
|
|
GitlabEvent::Push { user_name, .. } => &user_name,
|
|
GitlabEvent::TagPush { user_name, .. } => &user_name,
|
|
GitlabEvent::MergeRequest { user, .. } => &user.name,
|
|
GitlabEvent::Pipeline { user, .. } => &user.name,
|
|
}
|
|
}
|
|
|
|
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 find_commit<'a>(commits: &'a Vec<Commit>, 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::TagPush {
|
|
checkout_sha, commits, ..
|
|
} => find_commit(commits, &checkout_sha)
|
|
.map(|commit| commit.title.clone())
|
|
.unwrap_or_else(|| "New tag pushed".to_string()),
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
use std::{fs::File, io::BufReader};
|
|
|
|
fn load_test_data(name: &str) -> anyhow::Result<GitlabEvent> {
|
|
let f = File::open(&format!("{}/test-data/{}.json", env!("CARGO_MANIFEST_DIR"), name))?;
|
|
let r = BufReader::new(f);
|
|
let event: GitlabEvent = serde_json::from_reader(r)?;
|
|
Ok(event)
|
|
}
|
|
|
|
#[test]
|
|
pub fn parse_push_event() -> anyhow::Result<()> {
|
|
let event = load_test_data("push-event")?;
|
|
|
|
match event {
|
|
GitlabEvent::Push {
|
|
event_name,
|
|
before,
|
|
after,
|
|
r#ref,
|
|
checkout_sha,
|
|
user_username,
|
|
project,
|
|
repository,
|
|
total_commits_count,
|
|
..
|
|
} => {
|
|
assert_eq!(event_name, "push");
|
|
assert_eq!(before, "95790bf891e76fee5e1747ab589903a6a1f80f22");
|
|
assert_eq!(after, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7");
|
|
assert_eq!(r#ref, "refs/heads/master");
|
|
assert_eq!(checkout_sha, "da1560886d4f094c3e6c9ef40349f7d38b5d27d7");
|
|
assert_eq!(user_username, "jsmith");
|
|
assert_eq!(project.name, "Diaspora");
|
|
assert_eq!(project.namespace, "Mike");
|
|
assert_eq!(repository.name, "Diaspora");
|
|
assert_eq!(repository.url, "git@example.com:mike/diaspora.git");
|
|
assert_eq!(total_commits_count, 4);
|
|
}
|
|
_ => panic!("not a push event"),
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
pub fn parse_tag_push_event() -> anyhow::Result<()> {
|
|
let event = load_test_data("tag-push-event")?;
|
|
|
|
match event {
|
|
GitlabEvent::TagPush {
|
|
event_name,
|
|
before,
|
|
after,
|
|
r#ref,
|
|
checkout_sha,
|
|
user_name,
|
|
project,
|
|
repository,
|
|
total_commits_count,
|
|
..
|
|
} => {
|
|
assert_eq!(event_name, "tag_push");
|
|
assert_eq!(before, "0000000000000000000000000000000000000000");
|
|
assert_eq!(after, "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7");
|
|
assert_eq!(r#ref, "refs/tags/v1.0.0");
|
|
assert_eq!(checkout_sha, "82b3d5ae55f7080f1e6022629cdb57bfae7cccc7");
|
|
assert_eq!(user_name, "John Smith");
|
|
assert_eq!(project.name, "Example");
|
|
assert_eq!(project.namespace, "Jsmith");
|
|
assert_eq!(repository.name, "Example");
|
|
assert_eq!(total_commits_count, 0);
|
|
}
|
|
_ => panic!("not a tag push event"),
|
|
};
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
pub fn parse_merge_request_event() -> anyhow::Result<()> {
|
|
let event = load_test_data("merge-request-event")?;
|
|
|
|
match event {
|
|
GitlabEvent::MergeRequest {
|
|
user,
|
|
object_attributes,
|
|
..
|
|
} => {
|
|
assert_eq!(user.name, "Administrator");
|
|
assert_eq!(object_attributes.action, MergeRequestAction::Opened);
|
|
assert_eq!(object_attributes.title, "MS-Viewport");
|
|
}
|
|
_ => panic!("not a merge request event"),
|
|
};
|
|
|
|
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(())
|
|
}
|
|
}
|