bebot/src/event.rs

225 lines
6.6 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 Project {
pub id: u64,
pub name: String,
pub description: String,
pub web_url: String,
pub avatar_url: Option<String>,
pub git_ssh_url: String,
pub git_http_url: String,
pub namespace: String,
pub visibility_level: u32,
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)]
pub struct Repository {
pub name: String,
pub url: String,
pub description: String,
pub homepage: String,
pub git_http_url: String,
pub git_ssh_url: String,
pub visibility_level: u32,
}
#[derive(Debug, Deserialize)]
pub struct Commit {
pub id: String,
pub title: String,
pub url: 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,
},
}
impl GitlabEventExt for GitlabEvent {
fn project(&self) -> &Project {
match self {
GitlabEvent::Push { project, .. } => &project,
GitlabEvent::TagPush { project, .. } => &project,
}
}
fn r#ref(&self) -> &str {
match self {
GitlabEvent::Push { r#ref, .. } => &r#ref,
GitlabEvent::TagPush { r#ref, .. } => &r#ref,
}
}
fn user(&self) -> &str {
match self {
GitlabEvent::Push { user_name, .. } => &user_name,
GitlabEvent::TagPush { user_name, .. } => &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)
}
};
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()),
}
}
}
#[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(())
}
}