Skip to content

Commit

Permalink
Add webhook event deserialization (#427)
Browse files Browse the repository at this point in the history
Implement deserialization of payloads as described in
https://docs.github.com/en/webhooks-and-events/webhooks/webhook-events-and-payloads

The payloads themselves do not implement `Deserialize`, since the event
type information is located in headers, not in the payload itself.
  • Loading branch information
gagbo authored Jul 30, 2023
1 parent 02b96b1 commit d46de1f
Show file tree
Hide file tree
Showing 89 changed files with 5,747 additions and 16 deletions.
4 changes: 2 additions & 2 deletions src/api/orgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,11 @@ impl<'octo> OrgHandler<'octo> {
/// ```no_run
/// # async fn run() -> octocrab::Result<()> {
/// # let octocrab = octocrab::Octocrab::default();
/// use octocrab::models::hooks::{Hook, Config as HookConfig};
/// use octocrab::models::hooks::{Hook, Config as HookConfig, ContentType as HookContentType};
///
/// let config = HookConfig {
/// url: "https://example.com".to_string(),
/// content_type: Some("json".to_string()),
/// content_type: Some(HookContentType::Json),
/// insecure_ssl: None,
/// secret: None
/// };
Expand Down
19 changes: 19 additions & 0 deletions src/models.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub mod reactions;
pub mod repos;
pub mod teams;
pub mod timelines;
pub mod webhook_events;
pub mod workflows;

pub use apps::App;
Expand Down Expand Up @@ -97,6 +98,7 @@ id_type!(
AppId,
ArtifactId,
AssetId,
BranchProtectionRuleId,
CardId,
CheckSuiteId,
CheckRunId,
Expand All @@ -105,6 +107,7 @@ id_type!(
IssueEventId,
IssueId,
JobId,
HookId,
LabelId,
MilestoneId,
NotificationId,
Expand Down Expand Up @@ -403,6 +406,22 @@ pub struct Author {
pub site_admin: bool,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[non_exhaustive]
pub enum AuthorAssociation {
Collaborator,
Contributor,
FirstTimer,
FirstTimeContributor,
Mannequin,
Member,
None,
Owner,
#[serde(untagged)]
Other(String),
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Collaborator {
Expand Down
4 changes: 0 additions & 4 deletions src/models/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@ use serde::{de::Error, Deserialize, Serialize};
use url::Url;

/// A GitHub event.
///
/// If you want to deserialize a webhook payload received in a Github Application, you
/// must directly deserialize the body into a [`WrappedEventPayload`](WrappedEventPayload).
/// For webhooks, the event type is stored in the `X-GitHub-Event` header.
#[derive(Debug, Clone, PartialEq, Serialize)]
#[non_exhaustive]
pub struct Event {
Expand Down
40 changes: 37 additions & 3 deletions src/models/hooks.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
use super::*;
use super::{webhook_events::WebhookEventType, *};

#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct Hook {
pub r#type: String,
pub active: bool,
/// Only included in webhook payload received by GitHub Apps. When you
/// register a new GitHub App, GitHub sends a ping event to the webhook URL
/// you specified during registration. The GitHub App ID sent in this field
/// is required for authenticating an app.
#[serde(skip_serializing_if = "Option::is_none")]
pub app_id: Option<AppId>,
pub id: u64,
/// The type of webhook. At the time of writing, the only valid value is
/// 'web'
pub name: String,
pub events: Vec<String>,
pub events: Vec<WebhookEventType>,
pub config: Config,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_response: Option<LastResponse>,
#[serde(skip_serializing_if = "Option::is_none")]
pub url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ping_url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub deliveries_url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_url: Option<Url>,
#[serde(skip_serializing_if = "Option::is_none")]
pub updated_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<DateTime<Utc>>,
Expand All @@ -22,10 +37,29 @@ pub struct Hook {
#[serde(rename_all = "snake_case")]
pub struct Config {
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
pub content_type: Option<ContentType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub insecure_ssl: Option<String>,
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub secret: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct LastResponse {
pub code: Option<i64>,
pub status: Option<String>,
pub message: Option<String>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
#[serde(rename_all = "snake_case")]
pub enum ContentType {
Json,
#[default]
Form,
#[serde(untagged)]
Other(String),
}
14 changes: 11 additions & 3 deletions src/models/pulls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ pub struct PullRequest {
#[serde(skip_serializing_if = "Option::is_none")]
pub links: Option<Box<Links>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub author_association: Option<String>,
pub author_association: Option<AuthorAssociation>,
#[serde(skip_serializing_if = "Option::is_none")]
pub draft: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -255,13 +255,13 @@ pub struct Comment {
pub commit_id: String,
pub original_commit_id: String,
#[serde(default)]
pub in_reply_to_id: Option<u64>,
pub in_reply_to_id: Option<CommentId>,
pub user: Option<Author>,
pub body: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub updated_at: chrono::DateTime<chrono::Utc>,
pub html_url: String,
pub author_association: String,
pub author_association: AuthorAssociation,
#[serde(rename = "_links")]
pub links: Links,
pub start_line: Option<u64>,
Expand All @@ -272,6 +272,14 @@ pub struct Comment {
pub side: Option<String>,
}

/// A Thread in a pull request review
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct Thread {
pub comments: Vec<Comment>,
pub node_id: String,
}

// This is rather annoying, but Github uses both SCREAMING_SNAKE_CASE and snake_case
// for the review state, it's uppercase when coming from an API request, but
// lowercase when coming from a webhook payload, so we need to deserialize both,
Expand Down
2 changes: 1 addition & 1 deletion src/models/reactions.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub enum ReactionContent {
#[serde(rename = "heart")]
Heart,
Expand Down
5 changes: 4 additions & 1 deletion src/models/repos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,17 @@ pub struct Commit {
pub committer: Option<CommitAuthor>,
}

/// The author of a commit, identified by its name and email, as well as (optionally) a time
/// The author of a commit, identified by its name and email, as well as (optionally) a time and a github username
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct GitUserTime {
#[serde(flatten)]
pub user: CommitAuthor,

#[serde(skip_serializing_if = "Option::is_none")]
pub date: Option<DateTime<Utc>>,

#[serde(skip_serializing_if = "Option::is_none")]
pub username: Option<String>,
}

/// The author of a commit, identified by its name and email.
Expand Down
13 changes: 11 additions & 2 deletions src/models/teams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Team {
pub name: String,
pub slug: String,
pub description: Option<String>,
pub privacy: String,
pub privacy: TeamPrivacy,
pub permission: String,
pub members_url: Url,
pub repositories_url: Url,
Expand Down Expand Up @@ -49,7 +49,7 @@ pub struct RequestedTeam {
pub slug: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
pub privacy: String,
pub privacy: TeamPrivacy,
pub permission: String,
pub members_url: Url,
pub repositories_url: Url,
Expand All @@ -76,3 +76,12 @@ pub struct TeamInvitation {
pub node_id: String,
pub invitation_teams_url: String,
}

#[derive(PartialEq, Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum TeamPrivacy {
Open,
Closed,
Secret,
}
Loading

0 comments on commit d46de1f

Please sign in to comment.