diff --git a/src/heroku/webhook.rs b/src/heroku/webhook.rs index 43233c0..2338d7a 100644 --- a/src/heroku/webhook.rs +++ b/src/heroku/webhook.rs @@ -27,9 +27,9 @@ use serde::Deserialize; #[derive(Debug, PartialEq, Eq)] pub enum HookEvent { /// From the entity `api:release`. - Rollback { version: String }, + Rollback { author: String, version: String }, /// From the entity `api:release`. - EnvVarsChange { raw_change: String }, + EnvVarsChange { author: String, raw_change: String }, /// From the entity `dyno` (NB *not* `api:dyno`). DynoCrash { name: String, status_code: u8 }, } @@ -96,9 +96,9 @@ async fn send( }; let desc = match event { - HookEvent::Rollback { version } => format!("Rollback to {}", version), - HookEvent::EnvVarsChange { raw_change } => { - format!("Environment variables changed: {}", raw_change) + HookEvent::Rollback { version, author } => format!("Rollback to {} ({})", version, author), + HookEvent::EnvVarsChange { raw_change, author } => { + format!("Environment variables changed: {} ({})", raw_change, author) } HookEvent::DynoCrash { name, status_code } => { format!("Dyno {} crashed with status code {}", name, status_code) @@ -149,6 +149,7 @@ fn decode_rollback(payload: &ReleaseHookPayload) -> Option { .and_then(|re| re.captures(&payload.data.description)) .and_then(|cs| cs.name("version")) .map(|m| HookEvent::Rollback { + author: payload.data.user.email.to_owned(), version: m.as_str().to_owned(), }) } @@ -161,6 +162,7 @@ fn decode_env_vars_change(payload: &ReleaseHookPayload) -> Option { .and_then(|re| re.captures(&payload.data.description)) .and_then(|cs| cs.name("change")) .map(|m| HookEvent::EnvVarsChange { + author: payload.data.user.email.to_owned(), raw_change: m.as_str().to_owned(), }) } @@ -226,14 +228,15 @@ pub enum ReleaseHookAction { Other, } -/// General information about an `api:release` webhook event. +/// General information about an `api:release` entity type. #[derive(Debug, PartialEq, Deserialize)] struct ReleaseHookData { app: AppData, description: String, + user: UserData, } -/// General information about an `api:release` webhook event. +/// General information about an `dyno` entity type. #[derive(Debug, PartialEq, Deserialize)] struct DynoHookData { app: AppData, @@ -253,6 +256,12 @@ struct AppData { name: String, } +/// Information about the user who enacted the change. +#[derive(Debug, PartialEq, Deserialize)] +struct UserData { + email: String, +} + fn get_app_data(payload: &HookPayload) -> &AppData { match payload { HookPayload::Release(x) => &x.data.app, @@ -285,7 +294,7 @@ mod tests { }, "user": { "id": "71def50e-da83-453a-bba3-46b4e26911b0", - "email": "hello@example.com" + "email": "hodor@unsplash.com" }, "stack": "heroku-20", "status": "succeeded", @@ -340,6 +349,9 @@ mod tests { name: "my-app".to_string(), }, description: "Deploy 69eec518".to_string(), + user: UserData { + email: "hodor@unsplash.com".to_string(), + }, }, action: ReleaseHookAction::Update, }); @@ -551,6 +563,9 @@ mod tests { name: "any".to_string(), }, description: desc.to_string(), + user: UserData { + email: "hodor@unsplash.com".to_string(), + }, }, action: ReleaseHookAction::Update, } @@ -561,6 +576,7 @@ mod tests { assert_eq!( decode_release_payload(&payload_from_desc("Rollback to v1234")), Ok(HookEvent::Rollback { + author: "hodor@unsplash.com".to_string(), version: "v1234".to_string() }), ); @@ -568,6 +584,7 @@ mod tests { assert_eq!( decode_release_payload(&payload_from_desc("Rollback to some new format")), Ok(HookEvent::Rollback { + author: "hodor@unsplash.com".to_string(), version: "some new format".to_string() }), ); @@ -583,6 +600,7 @@ mod tests { assert_eq!( decode_release_payload(&payload_from_desc("Set FOO, BAR config vars")), Ok(HookEvent::EnvVarsChange { + author: "hodor@unsplash.com".to_string(), raw_change: "Set FOO, BAR".to_string() }), ); @@ -590,6 +608,7 @@ mod tests { assert_eq!( decode_release_payload(&payload_from_desc("Some new format config vars")), Ok(HookEvent::EnvVarsChange { + author: "hodor@unsplash.com".to_string(), raw_change: "Some new format".to_string() }), ); diff --git a/src/router.rs b/src/router.rs index 9260bde..94ea568 100644 --- a/src/router.rs +++ b/src/router.rs @@ -833,11 +833,14 @@ mod tests { "app": { "name": "any" }, - "description": "any" + "description": "any", + "user": { + "email": "hodor@unsplash.com" + } }, "action": "update" }"#; - let sig = "IsNt6nWoGu9tBYt1fKKi3SjiLhMp6Fk/TYsFCehd6LM="; + let sig = "0+jCzQsgvzi0SL0haDhB18ttbTNEYYlrwhtpL0FEVGw="; let req = Request::builder() .method("POST") @@ -861,11 +864,14 @@ mod tests { "app": { "name": "any" }, - "description": "any" + "description": "any", + "user": { + "email": "hodor@unsplash.com" + } }, "action": "create" }"#; - let sig = "WKv86Cw9YFrEpu8vkCw21QfsQ7FT0f8502q1F9EEQ6c="; + let sig = "F5ArFnV9sfXsDmk9ubM24fu6gVVxEXl1TOdt1XTVokg="; let req = Request::builder() .method("POST") @@ -889,11 +895,14 @@ mod tests { "app": { "name": "any" }, - "description": "Rollback to v1234" + "description": "Rollback to v1234", + "user": { + "email": "hodor@unsplash.com" + } }, "action": "update" }"#; - let sig = "mMGRnv4/Wjm2kyEbI0vqR//Kmt8NaV3Rj9xiMBdvlUU="; + let sig = "GxMZ9dos5w6r9V0JTDyeWprKmd3JW+i4otfkkDV463M="; let req = Request::builder() .method("POST") @@ -943,11 +952,14 @@ mod tests { "app": { "name": "any" }, - "description": "Rollback to v1234" + "description": "Rollback to v1234", + "user": { + "email": "hodor@unsplash.com" + } }, "action": "update" }"#; - let sig = "mMGRnv4/Wjm2kyEbI0vqR//Kmt8NaV3Rj9xiMBdvlUU="; + let sig = "GxMZ9dos5w6r9V0JTDyeWprKmd3JW+i4otfkkDV463M="; let req = Request::builder() .method("POST") @@ -997,11 +1009,14 @@ mod tests { "app": { "name": "any" }, - "description": "Rollback to v1234" + "description": "Rollback to v1234", + "user": { + "email": "hodor@unsplash.com" + } }, "action": "update" }"#; - let sig = "mMGRnv4/Wjm2kyEbI0vqR//Kmt8NaV3Rj9xiMBdvlUU="; + let sig = "GxMZ9dos5w6r9V0JTDyeWprKmd3JW+i4otfkkDV463M="; let req = Request::builder() .method("POST")