From ee17078f55602a8743acae21d565c787e75bead0 Mon Sep 17 00:00:00 2001 From: Gerry Agbobada Date: Tue, 25 Jul 2023 17:54:23 +0200 Subject: [PATCH] Add webhook event deserialization 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. --- src/api/orgs.rs | 4 +- src/models.rs | 19 + src/models/events.rs | 4 - src/models/hooks.rs | 40 +- src/models/pulls.rs | 14 +- src/models/reactions.rs | 2 +- src/models/repos.rs | 5 +- src/models/teams.rs | 13 +- src/models/webhook_events.rs | 930 ++++++++++++++++++ src/models/webhook_events/payload.rs | 193 ++++ .../payload/branch_protection_rule.rs | 76 ++ .../webhook_events/payload/check_run.rs | 18 + .../webhook_events/payload/check_suite.rs | 18 + .../payload/code_scanning_alert.rs | 25 + .../webhook_events/payload/commit_comment.rs | 40 + src/models/webhook_events/payload/create.rs | 14 + src/models/webhook_events/payload/delete.rs | 21 + .../payload/dependabot_alert.rs | 22 + .../webhook_events/payload/deploy_key.rs | 17 + .../webhook_events/payload/deployment.rs | 18 + .../payload/deployment_protection_rule.rs | 19 + .../payload/deployment_status.rs | 20 + .../webhook_events/payload/discussion.rs | 33 + .../payload/discussion_comment.rs | 20 + src/models/webhook_events/payload/fork.rs | 11 + .../payload/github_app_authorization.rs | 15 + src/models/webhook_events/payload/gollum.rs | 9 + .../webhook_events/payload/installation.rs | 23 + .../payload/installation_repositories.rs | 30 + .../payload/installation_target.rs | 11 + .../webhook_events/payload/issue_comment.rs | 30 + src/models/webhook_events/payload/issues.rs | 46 + src/models/webhook_events/payload/label.rs | 19 + .../payload/marketplace_purchase.rs | 21 + src/models/webhook_events/payload/member.rs | 19 + .../webhook_events/payload/membership.rs | 21 + .../webhook_events/payload/merge_group.rs | 26 + src/models/webhook_events/payload/meta.rs | 19 + .../webhook_events/payload/milestone.rs | 21 + .../webhook_events/payload/org_block.rs | 17 + .../webhook_events/payload/organization.rs | 21 + src/models/webhook_events/payload/package.rs | 17 + .../webhook_events/payload/page_build.rs | 9 + .../payload/personal_access_token_request.rs | 18 + src/models/webhook_events/payload/ping.rs | 11 + src/models/webhook_events/payload/project.rs | 21 + .../webhook_events/payload/project_card.rs | 21 + .../webhook_events/payload/project_column.rs | 20 + .../webhook_events/payload/projects_v2.rs | 20 + .../payload/projects_v2_item.rs | 22 + src/models/webhook_events/payload/public.rs | 7 + .../webhook_events/payload/pull_request.rs | 47 + .../payload/pull_request_review.rs | 29 + .../payload/pull_request_review_comment.rs | 30 + .../payload/pull_request_review_thread.rs | 19 + src/models/webhook_events/payload/push.rs | 41 + .../payload/registry_package.rs | 17 + src/models/webhook_events/payload/release.rs | 23 + .../webhook_events/payload/repository.rs | 35 + .../payload/repository_advisory.rs | 18 + .../payload/repository_dispatch.rs | 10 + .../payload/repository_import.rs | 17 + .../payload/repository_vulnerability_alert.rs | 19 + .../payload/secret_scanning_alert.rs | 19 + .../payload/secret_scanning_alert_location.rs | 16 + .../payload/security_advisory.rs | 18 + .../payload/security_and_analysis.rs | 8 + .../webhook_events/payload/sponsorship.rs | 23 + src/models/webhook_events/payload/star.rs | 18 + src/models/webhook_events/payload/status.rs | 32 + src/models/webhook_events/payload/team.rs | 21 + src/models/webhook_events/payload/team_add.rs | 8 + src/models/webhook_events/payload/watch.rs | 15 + .../payload/workflow_dispatch.rs | 10 + .../webhook_events/payload/workflow_job.rs | 20 + .../webhook_events/payload/workflow_run.rs | 19 + .../installation_created_webhook_event.json | 102 ++ .../installation_deleted_webhook_event.json | 101 ++ ...on_repositories_removed_webhook_event.json | 92 ++ .../issue_comment_created_webhook_event.json | 237 +++++ .../issue_comment_deleted_webhook_event.json | 245 +++++ .../issue_comment_edited_webhook_event.json | 250 +++++ .../issues_labeled_webhook_event.json | 213 ++++ .../issues_opened_webhook_event.json | 196 ++++ tests/resources/ping_webhook_event.json | 30 + .../pull_request_closed_webhook_event.json | 506 ++++++++++ .../pull_request_opened_webhook_event.json | 506 ++++++++++ ...ull_request_synchronize_webhook_event.json | 508 ++++++++++ .../repository_deleted_webhook_event.json | 135 +++ 89 files changed, 5747 insertions(+), 16 deletions(-) create mode 100644 src/models/webhook_events.rs create mode 100644 src/models/webhook_events/payload.rs create mode 100644 src/models/webhook_events/payload/branch_protection_rule.rs create mode 100644 src/models/webhook_events/payload/check_run.rs create mode 100644 src/models/webhook_events/payload/check_suite.rs create mode 100644 src/models/webhook_events/payload/code_scanning_alert.rs create mode 100644 src/models/webhook_events/payload/commit_comment.rs create mode 100644 src/models/webhook_events/payload/create.rs create mode 100644 src/models/webhook_events/payload/delete.rs create mode 100644 src/models/webhook_events/payload/dependabot_alert.rs create mode 100644 src/models/webhook_events/payload/deploy_key.rs create mode 100644 src/models/webhook_events/payload/deployment.rs create mode 100644 src/models/webhook_events/payload/deployment_protection_rule.rs create mode 100644 src/models/webhook_events/payload/deployment_status.rs create mode 100644 src/models/webhook_events/payload/discussion.rs create mode 100644 src/models/webhook_events/payload/discussion_comment.rs create mode 100644 src/models/webhook_events/payload/fork.rs create mode 100644 src/models/webhook_events/payload/github_app_authorization.rs create mode 100644 src/models/webhook_events/payload/gollum.rs create mode 100644 src/models/webhook_events/payload/installation.rs create mode 100644 src/models/webhook_events/payload/installation_repositories.rs create mode 100644 src/models/webhook_events/payload/installation_target.rs create mode 100644 src/models/webhook_events/payload/issue_comment.rs create mode 100644 src/models/webhook_events/payload/issues.rs create mode 100644 src/models/webhook_events/payload/label.rs create mode 100644 src/models/webhook_events/payload/marketplace_purchase.rs create mode 100644 src/models/webhook_events/payload/member.rs create mode 100644 src/models/webhook_events/payload/membership.rs create mode 100644 src/models/webhook_events/payload/merge_group.rs create mode 100644 src/models/webhook_events/payload/meta.rs create mode 100644 src/models/webhook_events/payload/milestone.rs create mode 100644 src/models/webhook_events/payload/org_block.rs create mode 100644 src/models/webhook_events/payload/organization.rs create mode 100644 src/models/webhook_events/payload/package.rs create mode 100644 src/models/webhook_events/payload/page_build.rs create mode 100644 src/models/webhook_events/payload/personal_access_token_request.rs create mode 100644 src/models/webhook_events/payload/ping.rs create mode 100644 src/models/webhook_events/payload/project.rs create mode 100644 src/models/webhook_events/payload/project_card.rs create mode 100644 src/models/webhook_events/payload/project_column.rs create mode 100644 src/models/webhook_events/payload/projects_v2.rs create mode 100644 src/models/webhook_events/payload/projects_v2_item.rs create mode 100644 src/models/webhook_events/payload/public.rs create mode 100644 src/models/webhook_events/payload/pull_request.rs create mode 100644 src/models/webhook_events/payload/pull_request_review.rs create mode 100644 src/models/webhook_events/payload/pull_request_review_comment.rs create mode 100644 src/models/webhook_events/payload/pull_request_review_thread.rs create mode 100644 src/models/webhook_events/payload/push.rs create mode 100644 src/models/webhook_events/payload/registry_package.rs create mode 100644 src/models/webhook_events/payload/release.rs create mode 100644 src/models/webhook_events/payload/repository.rs create mode 100644 src/models/webhook_events/payload/repository_advisory.rs create mode 100644 src/models/webhook_events/payload/repository_dispatch.rs create mode 100644 src/models/webhook_events/payload/repository_import.rs create mode 100644 src/models/webhook_events/payload/repository_vulnerability_alert.rs create mode 100644 src/models/webhook_events/payload/secret_scanning_alert.rs create mode 100644 src/models/webhook_events/payload/secret_scanning_alert_location.rs create mode 100644 src/models/webhook_events/payload/security_advisory.rs create mode 100644 src/models/webhook_events/payload/security_and_analysis.rs create mode 100644 src/models/webhook_events/payload/sponsorship.rs create mode 100644 src/models/webhook_events/payload/star.rs create mode 100644 src/models/webhook_events/payload/status.rs create mode 100644 src/models/webhook_events/payload/team.rs create mode 100644 src/models/webhook_events/payload/team_add.rs create mode 100644 src/models/webhook_events/payload/watch.rs create mode 100644 src/models/webhook_events/payload/workflow_dispatch.rs create mode 100644 src/models/webhook_events/payload/workflow_job.rs create mode 100644 src/models/webhook_events/payload/workflow_run.rs create mode 100644 tests/resources/installation_created_webhook_event.json create mode 100644 tests/resources/installation_deleted_webhook_event.json create mode 100644 tests/resources/installation_repositories_removed_webhook_event.json create mode 100644 tests/resources/issue_comment_created_webhook_event.json create mode 100644 tests/resources/issue_comment_deleted_webhook_event.json create mode 100644 tests/resources/issue_comment_edited_webhook_event.json create mode 100644 tests/resources/issues_labeled_webhook_event.json create mode 100644 tests/resources/issues_opened_webhook_event.json create mode 100644 tests/resources/ping_webhook_event.json create mode 100644 tests/resources/pull_request_closed_webhook_event.json create mode 100644 tests/resources/pull_request_opened_webhook_event.json create mode 100644 tests/resources/pull_request_synchronize_webhook_event.json create mode 100644 tests/resources/repository_deleted_webhook_event.json diff --git a/src/api/orgs.rs b/src/api/orgs.rs index cfed8f80..77bfb80f 100644 --- a/src/api/orgs.rs +++ b/src/api/orgs.rs @@ -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 /// }; diff --git a/src/models.rs b/src/models.rs index 798a1de3..b93dac80 100644 --- a/src/models.rs +++ b/src/models.rs @@ -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; @@ -97,6 +98,7 @@ id_type!( AppId, ArtifactId, AssetId, + BranchProtectionRuleId, CardId, CheckSuiteId, CheckRunId, @@ -105,6 +107,7 @@ id_type!( IssueEventId, IssueId, JobId, + HookId, LabelId, MilestoneId, NotificationId, @@ -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 { diff --git a/src/models/events.rs b/src/models/events.rs index 79b26a4e..0b623a95 100644 --- a/src/models/events.rs +++ b/src/models/events.rs @@ -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 { diff --git a/src/models/hooks.rs b/src/models/hooks.rs index 0e68d097..5c97b8d2 100644 --- a/src/models/hooks.rs +++ b/src/models/hooks.rs @@ -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, pub id: u64, + /// The type of webhook. At the time of writing, the only valid value is + /// 'web' pub name: String, - pub events: Vec, + pub events: Vec, pub config: Config, #[serde(skip_serializing_if = "Option::is_none")] + pub last_response: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub url: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub ping_url: Option, #[serde(skip_serializing_if = "Option::is_none")] pub deliveries_url: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub test_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub updated_at: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub created_at: Option>, @@ -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, + pub content_type: Option, #[serde(skip_serializing_if = "Option::is_none")] pub insecure_ssl: Option, pub url: String, #[serde(skip_serializing_if = "Option::is_none")] pub secret: Option, } + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct LastResponse { + pub code: Option, + pub status: Option, + pub message: Option, +} + +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +#[serde(rename_all = "snake_case")] +pub enum ContentType { + Json, + #[default] + Form, + #[serde(untagged)] + Other(String), +} diff --git a/src/models/pulls.rs b/src/models/pulls.rs index 2734407a..555523e7 100644 --- a/src/models/pulls.rs +++ b/src/models/pulls.rs @@ -78,7 +78,7 @@ pub struct PullRequest { #[serde(skip_serializing_if = "Option::is_none")] pub links: Option>, #[serde(skip_serializing_if = "Option::is_none")] - pub author_association: Option, + pub author_association: Option, #[serde(skip_serializing_if = "Option::is_none")] pub draft: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -255,13 +255,13 @@ pub struct Comment { pub commit_id: String, pub original_commit_id: String, #[serde(default)] - pub in_reply_to_id: Option, + pub in_reply_to_id: Option, pub user: Option, pub body: String, pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, pub html_url: String, - pub author_association: String, + pub author_association: AuthorAssociation, #[serde(rename = "_links")] pub links: Links, pub start_line: Option, @@ -272,6 +272,14 @@ pub struct Comment { pub side: Option, } +/// A Thread in a pull request review +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct Thread { + pub comments: Vec, + 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, diff --git a/src/models/reactions.rs b/src/models/reactions.rs index cc49c14d..04e09071 100644 --- a/src/models/reactions.rs +++ b/src/models/reactions.rs @@ -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, diff --git a/src/models/repos.rs b/src/models/repos.rs index 900a5c43..aa60f309 100644 --- a/src/models/repos.rs +++ b/src/models/repos.rs @@ -130,7 +130,7 @@ pub struct Commit { pub committer: Option, } -/// 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)] @@ -138,6 +138,9 @@ pub struct GitUserTime { #[serde(skip_serializing_if = "Option::is_none")] pub date: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub username: Option, } /// The author of a commit, identified by its name and email. diff --git a/src/models/teams.rs b/src/models/teams.rs index ff9dad7c..50490a53 100644 --- a/src/models/teams.rs +++ b/src/models/teams.rs @@ -12,7 +12,7 @@ pub struct Team { pub name: String, pub slug: String, pub description: Option, - pub privacy: String, + pub privacy: TeamPrivacy, pub permission: String, pub members_url: Url, pub repositories_url: Url, @@ -49,7 +49,7 @@ pub struct RequestedTeam { pub slug: String, #[serde(skip_serializing_if = "Option::is_none")] pub description: Option, - pub privacy: String, + pub privacy: TeamPrivacy, pub permission: String, pub members_url: Url, pub repositories_url: Url, @@ -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, +} diff --git a/src/models/webhook_events.rs b/src/models/webhook_events.rs new file mode 100644 index 00000000..2fb28ac7 --- /dev/null +++ b/src/models/webhook_events.rs @@ -0,0 +1,930 @@ +mod payload; + +use super::{orgs::Organization, Author, Installation, InstallationId, Repository, RepositoryId}; +use serde::{Deserialize, Serialize}; + +pub use payload::WebhookEventPayload; + +/// A GitHub event. +#[derive(Debug, Clone, PartialEq, Serialize)] +#[non_exhaustive] +pub struct WebhookEvent { + pub sender: Option, + pub repository: Option, + pub organization: Option, + pub installation: Option, + #[serde(skip)] + pub kind: WebhookEventType, + #[serde(flatten)] + pub specific: WebhookEventPayload, +} + +impl WebhookEvent { + /// Deserialize the body of a webhook event according to the category in the header of the request. + /// + /// ``` + /// use octocrab::models::webhook_events::{WebhookEvent, WebhookEventType}; + /// + /// let json = r#"{ + /// "zen": "Design for failure.", + /// "hook_id": 423885699, + /// "hook": { + /// "type": "App", + /// "id": 423885699, + /// "name": "web", + /// "active": true, + /// "events": [ + /// "issues", + /// "issue_comment", + /// "meta", + /// "pull_request", + /// "pull_request_review", + /// "pull_request_review_comment", + /// "pull_request_review_thread", + /// "repository" + /// ], + /// "config": { + /// "content_type": "json", + /// "insecure_ssl": "0", + /// "secret": "********", + /// "url": "https://smee.io/R" + /// }, + /// "updated_at": "2023-07-13T09:30:45Z", + /// "created_at": "2023-07-13T09:30:45Z", + /// "app_id": 360617, + /// "deliveries_url": "https://api.github.com/app/hook/deliveries" + /// } + /// }"#; + /// + /// // Value picked from the `X-GitHub-Event` header + /// let event_name = "ping"; + /// + /// let event = WebhookEvent::try_from_header_and_body(event_name, json)?; + /// assert_eq!(event.kind, WebhookEventType::Ping); + /// # Ok::<(), serde_json::Error>(()) + /// ``` + pub fn try_from_header_and_body(header: &str, body: &B) -> Result + where + B: AsRef<[u8]> + ?Sized, + { + let kind = if header.starts_with('"') { + serde_json::from_str::(header)? + } else { + serde_json::from_str::(&format!("\"{header}\""))? + }; + + // Intermediate structure allows to separate the common fields from + // the event specific one. + #[derive(Deserialize)] + struct Intermediate { + sender: Option, + repository: Option, + organization: Option, + installation: Option, + #[serde(flatten)] + specific: serde_json::Value, + } + + let Intermediate { + sender, + repository, + organization, + installation, + specific, + } = serde_json::from_slice::(body.as_ref())?; + + let specific = kind.parse_specific_payload(specific)?; + + Ok(Self { + sender, + repository, + organization, + installation, + kind, + specific, + }) + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +#[serde(rename_all = "snake_case")] +pub enum WebhookEventType { + /// This event occurs when there is activity relating to branch protection rules. For more information, see "About protected branches." For information about the APIs to manage branch protection rules, see the GraphQL documentation or "Branch protection" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Administration" repository permission + BranchProtectionRule, + /// This event occurs when there is activity relating to a check run. For information about check runs, see "Getting started with the Checks API." For information about the APIs to manage check runs, see the GraphQL API documentation or "Check Runs" in the REST API documentation. + /// + /// For activity relating to check suites, use the check-suite event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Checks" repository permission. To receive the rerequested and requested_action event types, the app must have at least write-level access for the "Checks" permission. GitHub Apps with write-level access for the "Checks" permission are automatically subscribed to this webhook event. + /// + /// Repository and organization webhooks only receive payloads for the created and completed event types in repositories. + /// + /// Note: The API only looks for pushes in the repository where the check run was created. Pushes to a branch in a forked repository are not detected and return an empty pull_requests array and a null value for head_branch. + CheckRun, + /// This event occurs when there is activity relating to a check suite. For information about check suites, see "Getting started with the Checks API." For information about the APIs to manage check suites, see the GraphQL API documentation or "Check Suites" in the REST API documentation. + /// + /// For activity relating to check runs, use the check_run event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Checks" permission. To receive the requested and rerequested event types, the app must have at lease write-level access for the "Checks" permission. GitHub Apps with write-level access for the "Checks" permission are automatically subscribed to this webhook event. + /// + /// Repository and organization webhooks only receive payloads for the completed event types in repositories. + /// + /// Note: The API only looks for pushes in the repository where the check suite was created. Pushes to a branch in a forked repository are not detected and return an empty pull_requests array and a null value for head_branch. + CheckSuite, + /// This event occurs when there is activity relating to code scanning alerts in a repository. For more information, see "About code scanning" and "About code scanning alerts." For information about the API to manage code scanning, see "Code scanning" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Code scanning alerts" repository permission. + CodeScanningAlert, + /// This event occurs when there is activity relating to commit comments. For more information about commit comments, see "Commenting on a pull request." For information about the APIs to manage commit comments, see the GraphQL API documentation or "Commit comments" in the REST API documentation. + /// + /// For activity relating to comments on pull request reviews, use the pull_request_review_comment event. For activity relating to issue comments, use the issue_comment event. For activity relating to discussion comments, use the discussion_comment event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + CommitComment, + /// This event occurs when a Git branch or tag is created. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + /// + /// Note: This event will not occur when more than three tags are created at once. + Create, + /// This event occurs when a Git branch or tag is deleted. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + /// + /// Note: This event will not occur when more than three tags are deleted at once. + Delete, + /// This event occurs when there is activity relating to Dependabot alerts. + /// + /// For more information about Dependabot alerts, see "About Dependabot alerts." For information about the API to manage Dependabot alerts, see "Dependabot alerts" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Dependabot alerts" repository permission. + /// + /// Note: Webhook events for Dependabot alerts are currently in beta and subject to change. + DependabotAlert, + /// This event occurs when there is activity relating to deploy keys. For more information, see "Managing deploy keys." For information about the APIs to manage deploy keys, see the GraphQL API documentation or "Deploy keys" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Deployments" repository permission. + DeployKey, + /// This event occurs when there is activity relating to deployments. For more information, see "About deployments." For information about the APIs to manage deployments, see the GraphQL API documentation or "Deployments" in the REST API documentation. + /// + /// For activity relating to deployment status, use the deployment_status event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Deployments" repository permission. + Deployment, + /// This event occurs when there is activity relating to deployment protection rules. For more information, see "Using environments for deployment." For information about the API to manage deployment protection rules, see the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Deployments" repository permission. + DeploymentProtectionRule, + /// This event occurs when there is activity relating to deployment statuses. For more information, see "About deployments." For information about the APIs to manage deployments, see the GraphQL API documentation or "Deployments" in the REST API documentation. + /// + /// For activity relating to deployment creation, use the deployment event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Deployments" repository permission. + DeploymentStatus, + /// This event occurs when there is activity relating to a discussion. For more information about discussions, see "GitHub Discussions." For information about the API to manage discussions, see the GraphQL documentation. + /// + /// For activity relating to a comment on a discussion, use the discussion_comment event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Discussions" repository permission. + /// + /// Note: Webhook events for GitHub Discussions are currently in beta and subject to change. + Discussion, + /// This event occurs when there is activity relating to a comment on a discussion. For more information about discussions, see "GitHub Discussions." For information about the API to manage discussions, see the GraphQL documentation. + /// + /// For activity relating to a discussion as opposed to comments on a discussion, use the discussion event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Discussions" repository permission. + /// + /// Note: Webhook events for GitHub Discussions are currently in beta and subject to change. + DiscussionComment, + /// This event occurs when someone forks a repository. For more information, see "Fork a repo." For information about the API to manage forks, see "Forks" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + Fork, + /// This event occurs when a user revokes their authorization of a GitHub App. For more information, see "About apps." For information about the API to manage GitHub Apps, see the GraphQL API documentation or "Apps" in the REST API documentation. + /// + /// A GitHub App receives this webhook by default and cannot unsubscribe from this event. + /// + /// Anyone can revoke their authorization of a GitHub App from their GitHub account settings page. Revoking the authorization of a GitHub App does not uninstall the GitHub App. You should program your GitHub App so that when it receives this webhook, it stops calling the API on behalf of the person who revoked the token. If your GitHub App continues to use a revoked access token, it will receive the 401 Bad Credentials error. For details about requests with a user access token, which require GitHub App authorization, see "Authenticating with a GitHub App on behalf of a user." + GithubAppAuthorization, + /// This event occurs when someone creates or updates a wiki page. For more information, see "About wikis." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + Gollum, + /// This event occurs when there is activity relating to a GitHub App installation. All GitHub Apps receive this event by default. You cannot manually subscribe to this event. + /// + /// For more information about GitHub Apps, see "About apps." For information about the APIs to manage GitHub Apps, see the GraphQL API documentation or "Apps" in the REST API documentation. + Installation, + /// This event occurs when there is activity relating to which repositories a GitHub App installation can access. All GitHub Apps receive this event by default. You cannot manually subscribe to this event. + /// + /// For more information about GitHub Apps, see "About apps." For information about the APIs to manage GitHub Apps, see the GraphQL API documentation or "Apps" in the REST API documentation. + InstallationRepositories, + /// This event occurs when there is activity relating to the user or organization account that a GitHub App is installed on. For more information, see "About apps." For information about the APIs to manage GitHub Apps, see the GraphQL API documentation or "Apps" in the REST API documentation. + InstallationTarget, + /// This event occurs when there is activity relating to a comment on an issue or pull request. For more information about issues and pull requests, see "About issues" and "About pull requests." For information about the APIs to manage issue comments, see the GraphQL documentation or "Issue comments" in the REST API documentation. + /// + /// For activity relating to an issue as opposed to comments on an issue, use the issue event. For activity related to pull request reviews or pull request review comments, use the pull_request_review or pull_request_review_comment events. For more information about the different types of pull request comments, see "Working with comments." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Issues" repository permission. + IssueComment, + /// This event occurs when there is activity relating to an issue. For more information about issues, see "About issues." For information about the APIs to manage issues, see the GraphQL documentation or "Issues" in the REST API documentation. + /// + /// For activity relating to a comment on an issue, use the issue_comment event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Issues" repository permission. + Issues, + /// This event occurs when there is activity relating to labels. For more information, see "Managing labels." For information about the APIs to manage labels, see the GraphQL documentation or "Labels" in the REST API documentation. + /// + /// If you want to receive an event when a label is added to or removed from an issue, pull request, or discussion, use the labeled or unlabeled action type for the issues, pull_request, or discussion events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Metadata" repository permission. + Label, + /// This event occurs when there is activity relating to a GitHub Marketplace purchase. For more information, see "GitHub Marketplace." For information about the APIs to manage GitHub Marketplace listings, see the GraphQL documentation or "GitHub Marketplace" in the REST API documentation. + MarketplacePurchase, + /// This event occurs when there is activity relating to collaborators in a repository. For more information, see "Adding outside collaborators to repositories in your organization." For more information about the API to manage repository collaborators, see the GraphQL API documentation or "Collaborators" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Members" organization permission. + Member, + /// This event occurs when there is activity relating to team membership. For more information, see "About teams." For more information about the APIs to manage team memberships, see the GraphQL API documentation or "Team members" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Members" organization permission. + Membership, + /// This event occurs when there is activity relating to a merge group in a merge queue. For more information, see "Managing a merge queue." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Merge queues" repository permission. + MergeGroup, + /// This event occurs when there is activity relating to a webhook itself. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Meta" app permission. + Meta, + /// This event occurs when there is activity relating to milestones. For more information, see "About milestones." For information about the APIs to manage milestones, see the GraphQL documentation or "Milestones" in the REST API documentation. + /// + /// If you want to receive an event when an issue or pull request is added to or removed from a milestone, use the milestoned or demilestoned action type for the issues or pull_request events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Issues" or "Pull requests" repository permissions. + Milestone, + /// This event occurs when organization owners or moderators block or unblock a non-member from collaborating on the organization's repositories. For more information, see "Blocking a user from your organization." For information about the APIs to manage blocked users, see the GraphQL documentation or "Blocking users" in the REST API documentation. + /// + /// If you want to receive an event when members are added or removed from an organization, use the organization event instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Administration" organization permission. + OrgBlock, + /// This event occurs when there is activity relating to an organization and its members. For more information, see "About organizations." For information about the APIs to manage organizations, see the GraphQL documentation or "Organizations" in the REST API documentation. + /// + /// If you want to receive an event when a non-member is blocked or unblocked from an organization, use the org_block event instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Members" organization permission. + Organization, + /// This event occurs when there is activity relating to GitHub Packages. For more information, see "Introduction to GitHub Packages." For information about the APIs to manage GitHub Packages, see the GraphQL API documentation or "Packages" in the REST API documentation. + /// + /// To install this event on a GitHub App, the app must have at least read-level access for the "Packages" repository permission. + Package, + /// This event occurs when there is an attempted build of a GitHub Pages site. This event occurs regardless of whether the build is successful. For more information, see "Configuring a publishing source for your GitHub Pages site." For information about the API to manage GitHub Pages, see "Pages" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Pages" repository permission. + PageBuild, + /// This event occurs when there is activity relating to a request for a fine-grained personal access token to access resources that belong to a resource owner that requires approval for token access. For more information, see "Creating a personal access token." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Personal access token requests" organization permission. + /// + /// Note: Fine-grained PATs are in public beta. Related APIs, events, and functionality are subject to change. + PersonalAccessTokenRequest, + /// This event occurs when you create a new webhook. The ping event is a confirmation from GitHub that you configured the webhook correctly. + Ping, + /// This event occurs when there is activity relating to a card on a classic project. For more information, see "About projects (classic)." For information about the API to manage classic projects, see the GraphQL API documentation or "Projects (classic)" in the REST API documentation. + /// + /// For activity relating to a project or a column on a project, use the project and project_column event. For activity relating to Projects instead of Projects (classic), use the projects_v2 event instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Projects" repository or organization permission. + ProjectCard, + /// This event occurs when there is activity relating to a classic project. For more information, see "About projects (classic)." For information about the API to manage classic projects, see the GraphQL API documentation or "Projects (classic)" in the REST API documentation. + /// + /// For activity relating to a card or column on a project, use the project_card and project_column event. For activity relating to Projects instead of Projects (classic), use the projects_v2 event instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Projects" repository or organization permission. + Project, + /// This event occurs when there is activity relating to a column on a classic project. For more information, see "About projects (classic)." For information about the API to manage classic projects, see the GraphQL API documentation or "Projects (classic)" in the REST API documentation. + /// + /// For activity relating to a project or a card on a project, use the project and project_card event. For activity relating to Projects instead of Projects (classic), use the projects_v2 event instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Projects" repository or organization permission. + ProjectColumn, + /// This event occurs when there is activity relating to an organization-level project. For more information, see "About Projects." For information about the Projects API, see the GraphQL documentation. + /// + /// For activity relating to a item on a project, use the projects_v2_item event. For activity relating to Projects (classic), use the project, project_card, and project_column` events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Projects" organization permission. + /// + /// Note: Webhook events for projects are currently in beta and subject to change. To share feedback about projects webhooks with GitHub, see the Projects webhook feedback discussion. + ProjectsV2, + /// This event occurs when there is activity relating to an item on an organization-level project. For more information, see "About Projects." For information about the Projects API, see the GraphQL documentation. + /// + /// For activity relating to a project (instead of an item on a project), use the projects_v2 event. For activity relating to Projects (classic), use the project, project_card, and project_column events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Projects" organization permission. + /// + /// Note: Webhook events for projects are currently in beta and subject to change. To share feedback about projects webhooks with GitHub, see the Projects webhook feedback discussion. + ProjectsV2Item, + /// This event occurs when repository visibility changes from private to public. For more information, see "Setting repository visibility." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Metadata" repository permission. + Public, + /// This event occurs when there is activity on a pull request. For more information, see "About pull requests." For information about the APIs to manage pull requests, see the GraphQL API documentation or "Pulls" in the REST API documentation. + /// + /// For activity related to pull request reviews, pull request review comments, pull request comments, or pull request review threads, use the pull_request_review, pull_request_review_comment, issue_comment, or pull_request_review_thread events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Pull requests" repository permission. + PullRequest, + /// This event occurs when there is activity relating to a pull request review. A pull request review is a group of pull request review comments in addition to a body comment and a state. For more information, see "About pull request reviews." For information about the APIs to manage pull request reviews, see the GraphQL API documentation or "Pull request reviews" in the REST API documentation. + /// + /// For activity related to pull request review comments, pull request comments, or pull request review threads, use the pull_request_review_comment, issue_comment, or pull_request_review_thread events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Pull requests" repository permission. + PullRequestReview, + /// This event occurs when there is activity relating to a pull request review comment. A pull request review comment is a comment on a pull request's diff. For more information, see "Commenting on a pull request." For information about the APIs to manage pull request review comments, see the GraphQL API documentation or "Pull request review comments" in the REST API documentation. + /// + /// For activity related to pull request reviews, pull request comments, or pull request review threads, use the pull_request_review, issue_comment, or pull_request_review_thread events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Pull requests" repository permission. + PullRequestReviewComment, + /// This event occurs when there is activity relating to a comment thread on a pull request. For more information, see "About pull request reviews." For information about the APIs to manage pull request review comment threads, see the GraphQL API documentation or "Pull request reviews" in the REST API documentation. + /// + /// For activity related to pull request review comments, pull request comments, or pull request reviews, use the pull_request_review_comment, issue_comment, or pull_request_review events instead. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Pull requests" repository permission. + PullRequestReviewThread, + /// This event occurs when a commit or tag is pushed. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + /// + /// Note: An event will not be created when more than three tags are pushed at once. + Push, + /// This event occurs when there is activity relating to GitHub Packages. For more information, see "Introduction to GitHub Packages." For information about the APIs to manage GitHub Packages, see the GraphQL API documentation or "Packages" in the REST API documentation. + /// + /// To install this event on a GitHub App, the app must have at least read-level access for the "Packages" repository permission. + /// + /// Note: GitHub recommends that you use the newer package event instead. + RegistryPackage, + /// This event occurs when there is activity relating to releases. For more information, see "About releases." For information about the APIs to manage releases, see the GraphQL API documentation or "Releases" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + Release, + /// This event occurs when there is activity relating to a repository security advisory. For more information about repository security advisories, see "About GitHub Security Advisories for repositories." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Repository security advisories" permission. + RepositoryAdvisory, + /// This event occurs when there is activity relating to repositories. For more information, see "About repositories." For information about the APIs to manage repositories, see the GraphQL documentation or "Repositories" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Metadata" repository permission. + Repository, + /// This event occurs when a GitHub App sends a POST request to /repos/{owner}/{repo}/dispatches. For more information, see the REST API documentation for creating a repository dispatch event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + RepositoryDispatch, + /// This event occurs when a repository is imported to GitHub. For more information, see "Importing a repository with GitHub Importer." For more information about the API to manage imports, see the REST API documentation. + RepositoryImport, + /// This event occurs when there is activity relating to a security vulnerability alert in a repository. + /// + /// Note: This event is deprecated. Use the dependabot_alert event instead. + RepositoryVulnerabilityAlert, + /// This event occurs when there is activity relating to a secret scanning alert. For more information about secret scanning, see "About secret scanning." For information about the API to manage secret scanning alerts, see "Secret scanning" in the REST API documentation. + /// + /// For activity relating to secret scanning alert locations, use the secret_scanning_alert_location event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Secret scanning alerts" repository permission. + SecretScanningAlert, + /// This event occurs when there is activity relating to the locations of a secret in a secret scanning alert. + /// + /// For more information about secret scanning, see "About secret scanning." For information about the API to manage secret scanning alerts, see "Secret scanning" in the REST API documentation. + /// + /// For activity relating to secret scanning alerts, use the secret_scanning_alert event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Secret scanning alerts" repository permission. + SecretScanningAlertLocation, + /// This event occurs when there is activity relating to a security advisory that was reviewed by GitHub. A GitHub-reviewed security advisory provides information about security-related vulnerabilities in software on GitHub. For more information about security advisories, see "About GitHub Security Advisories for repositories." For information about the API to manage security advisories, see the GraphQL documentation. + /// + /// GitHub Dependabot alerts are also powered by the security advisory dataset. For more information, see "About Dependabot alerts." + SecurityAdvisory, + /// This event occurs when code security and analysis features are enabled or disabled for a repository. For more information, see "GitHub security features." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Administration" repository permission. + SecurityAndAnalysis, + /// This event occurs when there is activity relating to a sponsorship listing. For more information, see "About GitHub Sponsors." For information about the API to manage sponsors, see the GraphQL documentation. + /// + /// You can only create a sponsorship webhook on GitHub.com. For more information, see "Configuring webhooks for events in your sponsored account." + Sponsorship, + /// This event occurs when there is activity relating to repository stars. For more information about stars, see "Saving repositories with stars." For information about the APIs to manage stars, see the GraphQL documentation or "Starring" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Metadata" repository permission. + Star, + /// This event occurs when the status of a Git commit changes. For example, commits can be marked as error, failure, pending, or success. For more information, see "About status checks." For information about the APIs to manage commit statuses, see the GraphQL documentation or "Statuses" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Commit statuses" repository permission. + Status, + /// This event occurs when a team is added to a repository. For more information, see "Managing teams and people with access to your repository." + /// + /// For activity relating to teams, see the teams event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Members" organization permission. + TeamAdd, + /// This event occurs when there is activity relating to teams in an organization. For more information, see "About teams." + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Members" organization permission. + Team, + /// This event occurs when there is activity relating to watching, or subscribing to, a repository. For more information about watching, see "Managing your subscriptions." For information about the APIs to manage watching, see "Watching" in the REST API documentation. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Metadata" repository permission. + Watch, + /// This event occurs when a GitHub Actions workflow is manually triggered. For more information, see "Manually running a workflow." + /// + /// For activity relating to workflow runs, use the workflow_run event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Contents" repository permission. + WorkflowDispatch, + /// This event occurs when there is activity relating to a job in a GitHub Actions workflow. For more information, see "Using jobs in a workflow." For information about the API to manage workflow jobs, see "Workflow jobs" in the REST API documentation. + /// + /// For activity relating to a workflow run instead of a job in a workflow run, use the workflow_run event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Actions" repository permission. + WorkflowJob, + /// This event occurs when there is activity relating to a run of a GitHub Actions workflow. For more information, see "About workflows." For information about the APIs to manage workflow runs, see the GraphQL documentation or "Workflow runs" in the REST API documentation. + /// + /// For activity relating to a job in a workflow run, use the workflow_job event. + /// + /// To subscribe to this event, a GitHub App must have at least read-level access for the "Actions" repository permission. + WorkflowRun, + #[serde(untagged)] + Unknown(String), +} + +impl WebhookEventType { + /// Parse (and verify) the payload for the specific event kind. + pub fn parse_specific_payload( + &self, + data: serde_json::Value, + ) -> Result { + match self { + WebhookEventType::BranchProtectionRule => { + Ok(WebhookEventPayload::BranchProtectionRuleWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::CheckRun => Ok(WebhookEventPayload::CheckRunWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::CheckSuite => Ok(WebhookEventPayload::CheckSuiteWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::CodeScanningAlert => { + Ok(WebhookEventPayload::CodeScanningAlertWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::CommitComment => Ok(WebhookEventPayload::CommitCommentWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Create => Ok(WebhookEventPayload::CreateWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Delete => Ok(WebhookEventPayload::DeleteWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::DependabotAlert => { + Ok(WebhookEventPayload::DependabotAlertWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::DeployKey => Ok(WebhookEventPayload::DeployKeyWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Deployment => Ok(WebhookEventPayload::DeploymentWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::DeploymentProtectionRule => { + Ok(WebhookEventPayload::DeploymentProtectionRuleWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::DeploymentStatus => { + Ok(WebhookEventPayload::DeploymentStatusWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::Discussion => Ok(WebhookEventPayload::DiscussionWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::DiscussionComment => { + Ok(WebhookEventPayload::DiscussionCommentWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Fork => Ok(WebhookEventPayload::ForkWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::GithubAppAuthorization => { + Ok(WebhookEventPayload::GithubAppAuthorizationWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Gollum => Ok(WebhookEventPayload::GollumWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Installation => Ok(WebhookEventPayload::InstallationWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::InstallationRepositories => { + Ok(WebhookEventPayload::InstallationRepositoriesWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::InstallationTarget => { + Ok(WebhookEventPayload::InstallationTargetWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::IssueComment => Ok(WebhookEventPayload::IssueCommentWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Issues => Ok(WebhookEventPayload::IssuesWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Label => Ok(WebhookEventPayload::LabelWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::MarketplacePurchase => { + Ok(WebhookEventPayload::MarketplacePurchaseWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Member => Ok(WebhookEventPayload::MemberWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Membership => Ok(WebhookEventPayload::MembershipWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::MergeGroup => Ok(WebhookEventPayload::MergeGroupWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Meta => Ok(WebhookEventPayload::MetaWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Milestone => Ok(WebhookEventPayload::MilestoneWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::OrgBlock => Ok(WebhookEventPayload::OrgBlockWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Organization => Ok(WebhookEventPayload::OrganizationWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Package => Ok(WebhookEventPayload::PackageWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::PageBuild => Ok(WebhookEventPayload::PageBuildWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::PersonalAccessTokenRequest => { + Ok(WebhookEventPayload::PersonalAccessTokenRequestWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Ping => Ok(WebhookEventPayload::PingWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::ProjectCard => Ok(WebhookEventPayload::ProjectCardWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Project => Ok(WebhookEventPayload::ProjectWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::ProjectColumn => Ok(WebhookEventPayload::ProjectColumnWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::ProjectsV2 => Ok(WebhookEventPayload::ProjectsV2WebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::ProjectsV2Item => { + Ok(WebhookEventPayload::ProjectsV2ItemWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::Public => Ok(WebhookEventPayload::PublicWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::PullRequest => Ok(WebhookEventPayload::PullRequestWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::PullRequestReview => { + Ok(WebhookEventPayload::PullRequestReviewWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::PullRequestReviewComment => { + Ok(WebhookEventPayload::PullRequestReviewCommentWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::PullRequestReviewThread => { + Ok(WebhookEventPayload::PullRequestReviewThreadWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Push => Ok(WebhookEventPayload::PushWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::RegistryPackage => { + Ok(WebhookEventPayload::RegistryPackageWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::Release => Ok(WebhookEventPayload::ReleaseWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::RepositoryAdvisory => { + Ok(WebhookEventPayload::RepositoryAdvisoryWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Repository => Ok(WebhookEventPayload::RepositoryWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::RepositoryDispatch => { + Ok(WebhookEventPayload::RepositoryDispatchWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::RepositoryImport => { + Ok(WebhookEventPayload::RepositoryImportWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::RepositoryVulnerabilityAlert => Ok( + WebhookEventPayload::RepositoryVulnerabilityAlertWebhookEvent(Box::new( + serde_json::from_value(data)?, + )), + ), + WebhookEventType::SecretScanningAlert => { + Ok(WebhookEventPayload::SecretScanningAlertWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::SecretScanningAlertLocation => Ok( + WebhookEventPayload::SecretScanningAlertLocationWebhookEvent(Box::new( + serde_json::from_value(data)?, + )), + ), + WebhookEventType::SecurityAdvisory => { + Ok(WebhookEventPayload::SecurityAdvisoryWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::SecurityAndAnalysis => { + Ok(WebhookEventPayload::SecurityAndAnalysisWebhookEvent( + Box::new(serde_json::from_value(data)?), + )) + } + WebhookEventType::Sponsorship => Ok(WebhookEventPayload::SponsorshipWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Star => Ok(WebhookEventPayload::StarWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Status => Ok(WebhookEventPayload::StatusWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::TeamAdd => Ok(WebhookEventPayload::TeamAddWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Team => Ok(WebhookEventPayload::TeamWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::Watch => Ok(WebhookEventPayload::WatchWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))), + WebhookEventType::WorkflowDispatch => { + Ok(WebhookEventPayload::WorkflowDispatchWebhookEvent(Box::new( + serde_json::from_value(data)?, + ))) + } + WebhookEventType::WorkflowJob => Ok(WebhookEventPayload::WorkflowJobWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::WorkflowRun => Ok(WebhookEventPayload::WorkflowRunWebhookEvent( + Box::new(serde_json::from_value(data)?), + )), + WebhookEventType::Unknown(_) => { + Ok(WebhookEventPayload::UnknownWebhookEvent(Box::new(data))) + } + } + } +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum EventInstallation { + /// A full installation object which is present for `Installation*` related webhook events. + Full(Box), + /// The minimal installation object is present for all other event types. + Minimal(Box), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct EventInstallationId { + pub id: InstallationId, + pub node_id: String, +} + +/// A repository in installation related webhook events. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct InstallationEventRepository { + pub id: RepositoryId, + pub node_id: String, + pub name: String, + pub full_name: String, + pub private: bool, +} + +#[cfg(test)] +mod tests { + use super::payload::*; + use super::*; + + #[test] + fn deserialize_installation_created() { + let json = include_str!("../../tests/resources/installation_created_webhook_event.json"); + let event = WebhookEventType::Installation + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::InstallationWebhookEvent(install_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + install_event.action, + InstallationWebhookEventAction::Created + ); + assert_eq!(install_event.repositories.len(), 3); + assert_eq!(install_event.repositories[2].name, "octocrab"); + } + + #[test] + fn deserialize_installation_deleted() { + let json = include_str!("../../tests/resources/installation_deleted_webhook_event.json"); + let event = WebhookEventType::Installation + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::InstallationWebhookEvent(install_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + install_event.action, + InstallationWebhookEventAction::Deleted + ); + assert_eq!(install_event.repositories.len(), 3); + assert_eq!(install_event.repositories[2].name, "octocrab"); + } + + #[test] + fn deserialize_installation_repositories_removed() { + let json = include_str!( + "../../tests/resources/installation_repositories_removed_webhook_event.json" + ); + let event = WebhookEventType::InstallationRepositories + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::InstallationRepositoriesWebhookEvent(install_repositories_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + install_repositories_event.action, + InstallationRepositoriesWebhookEventAction::Removed + ); + assert_eq!(install_repositories_event.repositories_removed.len(), 1); + assert_eq!( + install_repositories_event.repository_selection, + InstallationRepositoriesWebhookEventSelection::All + ); + } + + #[test] + fn deserialize_issue_comment_created() { + let json = include_str!("../../tests/resources/issue_comment_created_webhook_event.json"); + let event = WebhookEventType::IssueComment + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::IssueCommentWebhookEvent(issue_comment_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + issue_comment_event.action, + IssueCommentWebhookEventAction::Created + ); + assert_eq!(*issue_comment_event.comment.id, 1633968123); + } + + #[test] + fn deserialize_issue_comment_deleted() { + let json = include_str!("../../tests/resources/issue_comment_deleted_webhook_event.json"); + let event = WebhookEventType::IssueComment + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::IssueCommentWebhookEvent(issue_comment_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + issue_comment_event.action, + IssueCommentWebhookEventAction::Deleted + ); + } + + #[test] + fn deserialize_issue_comment_edited() { + let json = include_str!("../../tests/resources/issue_comment_edited_webhook_event.json"); + let event = WebhookEventType::IssueComment + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::IssueCommentWebhookEvent(issue_comment_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + issue_comment_event.action, + IssueCommentWebhookEventAction::Edited + ); + assert_eq!(issue_comment_event.changes.unwrap().body.from, "Old Body"); + } + + #[test] + fn deserialize_issues_labeled() { + let json = include_str!("../../tests/resources/issues_labeled_webhook_event.json"); + let event = WebhookEventType::Issues + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::IssuesWebhookEvent(issues_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!(issues_event.action, IssuesWebhookEventAction::Labeled); + } + + #[test] + fn deserialize_issues_opened() { + let json = include_str!("../../tests/resources/issues_opened_webhook_event.json"); + let event = WebhookEventType::Issues + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::IssuesWebhookEvent(issues_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!(issues_event.action, IssuesWebhookEventAction::Opened); + } + + #[test] + fn deserialize_ping() { + let json = include_str!("../../tests/resources/ping_webhook_event.json"); + let event = WebhookEventType::Ping + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::PingWebhookEvent(ping_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!(ping_event.hook.unwrap().id, 423885699); + } + + #[test] + fn deserialize_pull_request_closed() { + let json = include_str!("../../tests/resources/pull_request_closed_webhook_event.json"); + let event = WebhookEventType::PullRequest + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::PullRequestWebhookEvent(pull_request_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + pull_request_event.action, + PullRequestWebhookEventAction::Closed + ); + assert_eq!(pull_request_event.pull_request.number, 2); + } + + #[test] + fn deserialize_pull_request_opened() { + let json = include_str!("../../tests/resources/pull_request_opened_webhook_event.json"); + let event = WebhookEventType::PullRequest + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::PullRequestWebhookEvent(pull_request_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + pull_request_event.action, + PullRequestWebhookEventAction::Opened + ); + } + + #[test] + fn deserialize_pull_request_synchronize() { + let json = + include_str!("../../tests/resources/pull_request_synchronize_webhook_event.json"); + let event = WebhookEventType::PullRequest + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::PullRequestWebhookEvent(pull_request_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + pull_request_event.action, + PullRequestWebhookEventAction::Synchronize + ); + } + + #[test] + fn deserialize_repository_deleted() { + let json = include_str!("../../tests/resources/repository_deleted_webhook_event.json"); + let event = WebhookEventType::Repository + .parse_specific_payload(serde_json::from_str(json).unwrap()) + .unwrap(); + let WebhookEventPayload::RepositoryWebhookEvent(repository_event) = event else {panic!(" event is of the wrong type {:?}", event)}; + assert_eq!( + repository_event.action, + RepositoryWebhookEventAction::Deleted + ); + } +} diff --git a/src/models/webhook_events/payload.rs b/src/models/webhook_events/payload.rs new file mode 100644 index 00000000..93f1436b --- /dev/null +++ b/src/models/webhook_events/payload.rs @@ -0,0 +1,193 @@ +mod branch_protection_rule; +mod check_run; +mod check_suite; +mod code_scanning_alert; +mod commit_comment; +mod create; +mod delete; +mod dependabot_alert; +mod deploy_key; +mod deployment; +mod deployment_protection_rule; +mod deployment_status; +mod discussion; +mod discussion_comment; +mod fork; +mod github_app_authorization; +mod gollum; +mod installation; +mod installation_repositories; +mod installation_target; +mod issue_comment; +mod issues; +mod label; +mod marketplace_purchase; +mod member; +mod membership; +mod merge_group; +mod meta; +mod milestone; +mod org_block; +mod organization; +mod package; +mod page_build; +mod personal_access_token_request; +mod ping; +mod project; +mod project_card; +mod project_column; +mod projects_v2; +mod projects_v2_item; +mod public; +mod pull_request; +mod pull_request_review; +mod pull_request_review_comment; +mod pull_request_review_thread; +mod push; +mod registry_package; +mod release; +mod repository; +mod repository_advisory; +mod repository_dispatch; +mod repository_import; +mod repository_vulnerability_alert; +mod secret_scanning_alert; +mod secret_scanning_alert_location; +mod security_advisory; +mod security_and_analysis; +mod sponsorship; +mod star; +mod status; +mod team; +mod team_add; +mod watch; +mod workflow_dispatch; +mod workflow_job; +mod workflow_run; + +pub use self::{ + branch_protection_rule::*, check_run::*, check_suite::*, code_scanning_alert::*, + commit_comment::*, create::*, delete::*, dependabot_alert::*, deploy_key::*, deployment::*, + deployment_protection_rule::*, deployment_status::*, discussion::*, discussion_comment::*, + fork::*, github_app_authorization::*, gollum::*, installation::*, installation_repositories::*, + installation_target::*, issue_comment::*, issues::*, label::*, marketplace_purchase::*, + member::*, membership::*, merge_group::*, meta::*, milestone::*, org_block::*, organization::*, + package::*, page_build::*, personal_access_token_request::*, ping::*, project::*, + project_card::*, project_column::*, projects_v2::*, projects_v2_item::*, public::*, + pull_request::*, pull_request_review::*, pull_request_review_comment::*, + pull_request_review_thread::*, push::*, registry_package::*, release::*, repository::*, + repository_advisory::*, repository_dispatch::*, repository_import::*, + repository_vulnerability_alert::*, secret_scanning_alert::*, secret_scanning_alert_location::*, + security_advisory::*, security_and_analysis::*, sponsorship::*, star::*, status::*, team::*, + team_add::*, watch::*, workflow_dispatch::*, workflow_job::*, workflow_run::*, +}; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub enum WebhookEventPayload { + BranchProtectionRuleWebhookEvent(Box), + CheckRunWebhookEvent(Box), + CheckSuiteWebhookEvent(Box), + CodeScanningAlertWebhookEvent(Box), + CommitCommentWebhookEvent(Box), + CreateWebhookEvent(Box), + DeleteWebhookEvent(Box), + DependabotAlertWebhookEvent(Box), + DeployKeyWebhookEvent(Box), + DeploymentWebhookEvent(Box), + DeploymentProtectionRuleWebhookEvent(Box), + DeploymentStatusWebhookEvent(Box), + DiscussionWebhookEvent(Box), + DiscussionCommentWebhookEvent(Box), + ForkWebhookEvent(Box), + GithubAppAuthorizationWebhookEvent(Box), + GollumWebhookEvent(Box), + InstallationWebhookEvent(Box), + InstallationRepositoriesWebhookEvent(Box), + InstallationTargetWebhookEvent(Box), + IssueCommentWebhookEvent(Box), + IssuesWebhookEvent(Box), + LabelWebhookEvent(Box), + MarketplacePurchaseWebhookEvent(Box), + MemberWebhookEvent(Box), + MembershipWebhookEvent(Box), + MergeGroupWebhookEvent(Box), + MetaWebhookEvent(Box), + MilestoneWebhookEvent(Box), + OrgBlockWebhookEvent(Box), + OrganizationWebhookEvent(Box), + PackageWebhookEvent(Box), + PageBuildWebhookEvent(Box), + PersonalAccessTokenRequestWebhookEvent(Box), + PingWebhookEvent(Box), + ProjectCardWebhookEvent(Box), + ProjectWebhookEvent(Box), + ProjectColumnWebhookEvent(Box), + ProjectsV2WebhookEvent(Box), + ProjectsV2ItemWebhookEvent(Box), + PublicWebhookEvent(Box), + PullRequestWebhookEvent(Box), + PullRequestReviewWebhookEvent(Box), + PullRequestReviewCommentWebhookEvent(Box), + PullRequestReviewThreadWebhookEvent(Box), + PushWebhookEvent(Box), + RegistryPackageWebhookEvent(Box), + ReleaseWebhookEvent(Box), + RepositoryAdvisoryWebhookEvent(Box), + RepositoryWebhookEvent(Box), + RepositoryDispatchWebhookEvent(Box), + RepositoryImportWebhookEvent(Box), + RepositoryVulnerabilityAlertWebhookEvent(Box), + SecretScanningAlertWebhookEvent(Box), + SecretScanningAlertLocationWebhookEvent(Box), + SecurityAdvisoryWebhookEvent(Box), + SecurityAndAnalysisWebhookEvent(Box), + SponsorshipWebhookEvent(Box), + StarWebhookEvent(Box), + StatusWebhookEvent(Box), + TeamAddWebhookEvent(Box), + TeamWebhookEvent(Box), + WatchWebhookEvent(Box), + WorkflowDispatchWebhookEvent(Box), + WorkflowJobWebhookEvent(Box), + WorkflowRunWebhookEvent(Box), + UnknownWebhookEvent(Box), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum RefType { + Tag, + Branch, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum PusherType { + User, + #[serde(untagged)] + DeployKey(String), +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum MembershipScope { + Team, + Organization, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct OldValue +where + T: Serialize, + T: std::fmt::Debug + Clone + PartialEq, +{ + /// Old value, when the webhook payload is a change + pub from: T, +} diff --git a/src/models/webhook_events/payload/branch_protection_rule.rs b/src/models/webhook_events/payload/branch_protection_rule.rs new file mode 100644 index 00000000..333f54a6 --- /dev/null +++ b/src/models/webhook_events/payload/branch_protection_rule.rs @@ -0,0 +1,76 @@ +use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; + +use crate::models::{BranchProtectionRuleId, RepositoryId}; + +use super::OldValue; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct BranchProtectionRuleWebhookEventPayload { + pub action: BranchProtectionRuleWebhookEventAction, + pub changes: Option, + pub enterprise: Option, + pub rule: BranchProtectionRule, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum BranchProtectionRuleWebhookEventAction { + Created, + Deleted, + Edited, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct BranchProtectionRuleWebhookEventChanges { + pub admin_enforced: Option>>, + pub authorized_actor_names: Option>>, + pub authorized_actors_only: Option>>, + pub authorized_dismissal_actors_only: Option>>, + pub linear_history_requirement_enforcement_level: Option>, + pub required_status_checks: Option>>, + pub required_status_checks_enforcement_level: Option>, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct BranchProtectionRule { + pub admin_enfored: bool, + pub allow_deletions_enforcement_level: BranchProtectionRuleLevel, + pub allow_force_pushes_enforcement_level: BranchProtectionRuleLevel, + pub authorized_actor_names: Vec, + pub authorized_actors_only: bool, + pub authorized_dismissal_actors_only: bool, + pub create_protected: Option, + pub created_at: DateTime, + pub dismiss_stale_reviews_on_push: bool, + pub id: BranchProtectionRuleId, + pub ignore_approvals_from_contributors: bool, + pub linear_history_requirement_enforcement_level: BranchProtectionRuleLevel, + pub merge_queue_enforcement_level: BranchProtectionRuleLevel, + pub name: String, + pub pull_request_reviews_enforcement_level: BranchProtectionRuleLevel, + pub repository_id: RepositoryId, + pub require_code_owner_review: bool, + pub require_last_push_approval: Option, + pub required_approving_review_count: i64, + pub required_conversation_resolution_level: BranchProtectionRuleLevel, + pub required_deployments_enforcement_level: BranchProtectionRuleLevel, + pub required_status_checks: Vec, + pub required_status_checks_enforcement_level: BranchProtectionRuleLevel, + pub signature_requirement_enforcement_level: BranchProtectionRuleLevel, + pub strict_required_status_checks_policy: bool, + pub updated_at: DateTime, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum BranchProtectionRuleLevel { + Off, + NonAdmins, + Everyone, +} diff --git a/src/models/webhook_events/payload/check_run.rs b/src/models/webhook_events/payload/check_run.rs new file mode 100644 index 00000000..12f19f03 --- /dev/null +++ b/src/models/webhook_events/payload/check_run.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CheckRunWebhookEventPayload { + pub action: CheckRunWebhookEventAction, + pub check_run: serde_json::Value, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum CheckRunWebhookEventAction { + Completed, + Created, + RequestedAction, + Rerequested, +} diff --git a/src/models/webhook_events/payload/check_suite.rs b/src/models/webhook_events/payload/check_suite.rs new file mode 100644 index 00000000..b64fb86a --- /dev/null +++ b/src/models/webhook_events/payload/check_suite.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CheckSuiteWebhookEventPayload { + pub action: CheckSuiteWebhookEventAction, + pub enterprise: Option, + pub check_suite: serde_json::Value, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum CheckSuiteWebhookEventAction { + Completed, + Requested, + Rerequested, +} diff --git a/src/models/webhook_events/payload/code_scanning_alert.rs b/src/models/webhook_events/payload/code_scanning_alert.rs new file mode 100644 index 00000000..848b3aa7 --- /dev/null +++ b/src/models/webhook_events/payload/code_scanning_alert.rs @@ -0,0 +1,25 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CodeScanningAlertWebhookEventPayload { + pub action: CodeScanningAlertWebhookEventAction, + pub alert: serde_json::Value, + /// The commit SHA of the code scanning alert. When the action is reopened_by_user or closed_by_user, the event was triggered by the sender and this value will be empty. + pub commit_oid: String, + pub enterprise: Option, + /// The Git reference of the code scanning alert. When the action is reopened_by_user or closed_by_user, the event was triggered by the sender and this value will be empty. + pub r#ref: String, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum CodeScanningAlertWebhookEventAction { + AppearedInBranch, + ClosedByUser, + Created, + Fixed, + Reopened, + ReopenedByUser, +} diff --git a/src/models/webhook_events/payload/commit_comment.rs b/src/models/webhook_events/payload/commit_comment.rs new file mode 100644 index 00000000..caa1c0ae --- /dev/null +++ b/src/models/webhook_events/payload/commit_comment.rs @@ -0,0 +1,40 @@ +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; +use url::Url; + +use crate::models::{reactions::ReactionContent, Author, AuthorAssociation, CommentId}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CommitCommentWebhookEventPayload { + pub action: CommitCommentWebhookEventAction, + pub comment: CommitComment, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum CommitCommentWebhookEventAction { + Created, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub struct CommitComment { + pub author_association: AuthorAssociation, + pub body: String, + pub commit_id: String, + pub created_at: String, + pub html_url: Url, + pub id: CommentId, + pub line: Option, + pub node_id: String, + pub path: Option, + pub position: Option, + pub reactions: Option>, + pub updated_at: String, + pub url: Url, + pub user: Option, +} diff --git a/src/models/webhook_events/payload/create.rs b/src/models/webhook_events/payload/create.rs new file mode 100644 index 00000000..0f10d634 --- /dev/null +++ b/src/models/webhook_events/payload/create.rs @@ -0,0 +1,14 @@ +use serde::{Deserialize, Serialize}; + +use super::{PusherType, RefType}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct CreateWebhookEventPayload { + pub description: Option, + pub enterprise: Option, + pub master_branch: String, + pub pusher_type: PusherType, + pub r#ref: String, + pub ref_type: RefType, +} diff --git a/src/models/webhook_events/payload/delete.rs b/src/models/webhook_events/payload/delete.rs new file mode 100644 index 00000000..aae210b7 --- /dev/null +++ b/src/models/webhook_events/payload/delete.rs @@ -0,0 +1,21 @@ +use serde::{Deserialize, Serialize}; + +use super::{PusherType, RefType}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DeleteWebhookEventPayload { + pub enterprise: Option, + pub pusher_type: PusherType, + pub r#ref: String, + pub ref_type: RefType, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DeleteWebhookEventAction { + Created, + Deleted, + Edited, +} diff --git a/src/models/webhook_events/payload/dependabot_alert.rs b/src/models/webhook_events/payload/dependabot_alert.rs new file mode 100644 index 00000000..83b7a93c --- /dev/null +++ b/src/models/webhook_events/payload/dependabot_alert.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DependabotAlertWebhookEventPayload { + pub action: DependabotAlertWebhookEventAction, + pub alert: serde_json::Value, + pub enterprise: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DependabotAlertWebhookEventAction { + AutoDismissed, + AutoReopened, + Created, + Dismissed, + Fixed, + Reintroduced, + Reopened, +} diff --git a/src/models/webhook_events/payload/deploy_key.rs b/src/models/webhook_events/payload/deploy_key.rs new file mode 100644 index 00000000..be0aca5a --- /dev/null +++ b/src/models/webhook_events/payload/deploy_key.rs @@ -0,0 +1,17 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DeployKeyWebhookEventPayload { + pub action: DeployKeyWebhookEventAction, + pub enterprise: Option, + pub key: serde_json::Value, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DeployKeyWebhookEventAction { + Created, + Deleted, +} diff --git a/src/models/webhook_events/payload/deployment.rs b/src/models/webhook_events/payload/deployment.rs new file mode 100644 index 00000000..99ec6bc7 --- /dev/null +++ b/src/models/webhook_events/payload/deployment.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DeploymentWebhookEventPayload { + pub action: DeploymentWebhookEventAction, + pub deployment: serde_json::Value, + pub enterprise: Option, + pub workflow: serde_json::Value, + pub workflow_run: serde_json::Value, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DeploymentWebhookEventAction { + Created, +} diff --git a/src/models/webhook_events/payload/deployment_protection_rule.rs b/src/models/webhook_events/payload/deployment_protection_rule.rs new file mode 100644 index 00000000..ca43e209 --- /dev/null +++ b/src/models/webhook_events/payload/deployment_protection_rule.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DeploymentProtectionRuleWebhookEventPayload { + pub action: DeploymentProtectionRuleWebhookEventAction, + pub environment: Option, + pub event: Option, + pub deployment_callback_url: Option, + pub deployment: Option, + pub pull_requests: Option>, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DeploymentProtectionRuleWebhookEventAction { + Requested, +} diff --git a/src/models/webhook_events/payload/deployment_status.rs b/src/models/webhook_events/payload/deployment_status.rs new file mode 100644 index 00000000..6ab03af9 --- /dev/null +++ b/src/models/webhook_events/payload/deployment_status.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DeploymentStatusWebhookEventPayload { + pub action: DeploymentStatusWebhookEventAction, + pub check_run: Option, + pub deployment: serde_json::Value, + pub deployment_status: serde_json::Value, + pub enterprise: Option, + pub workflow: Option, + pub workflow_run: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DeploymentStatusWebhookEventAction { + Created, +} diff --git a/src/models/webhook_events/payload/discussion.rs b/src/models/webhook_events/payload/discussion.rs new file mode 100644 index 00000000..0d5b8ea9 --- /dev/null +++ b/src/models/webhook_events/payload/discussion.rs @@ -0,0 +1,33 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DiscussionWebhookEventPayload { + pub action: DiscussionWebhookEventAction, + pub answer: Option, + pub discussion: serde_json::Value, + pub enterprise: Option, + pub changes: Option, + pub label: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DiscussionWebhookEventAction { + Answered, + CategoryChanged, + Closed, + Created, + Deleted, + Edited, + Labeled, + Locked, + Pinned, + Reopened, + Transferred, + Unanswered, + Unlabeled, + Unlocked, + Unpinned, +} diff --git a/src/models/webhook_events/payload/discussion_comment.rs b/src/models/webhook_events/payload/discussion_comment.rs new file mode 100644 index 00000000..be7ea472 --- /dev/null +++ b/src/models/webhook_events/payload/discussion_comment.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct DiscussionCommentWebhookEventPayload { + pub action: DiscussionCommentWebhookEventAction, + pub changes: Option, + pub comment: serde_json::Value, + pub discussion: serde_json::Value, + pub enterprise: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum DiscussionCommentWebhookEventAction { + Created, + Deleted, + Edited, +} diff --git a/src/models/webhook_events/payload/fork.rs b/src/models/webhook_events/payload/fork.rs new file mode 100644 index 00000000..3f21958c --- /dev/null +++ b/src/models/webhook_events/payload/fork.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +use crate::models::Repository; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct ForkWebhookEventPayload { + // TODO: Make sure that it's a crate::models::Repository + pub forkee: Repository, + pub enterprise: Option, +} diff --git a/src/models/webhook_events/payload/github_app_authorization.rs b/src/models/webhook_events/payload/github_app_authorization.rs new file mode 100644 index 00000000..da2bd376 --- /dev/null +++ b/src/models/webhook_events/payload/github_app_authorization.rs @@ -0,0 +1,15 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct GithubAppAuthorizationWebhookEventPayload { + pub action: GithubAppAuthorizationWebhookEventAction, + pub enterprise: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum GithubAppAuthorizationWebhookEventAction { + Revoked, +} diff --git a/src/models/webhook_events/payload/gollum.rs b/src/models/webhook_events/payload/gollum.rs new file mode 100644 index 00000000..b3fc53b9 --- /dev/null +++ b/src/models/webhook_events/payload/gollum.rs @@ -0,0 +1,9 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct GollumWebhookEventPayload { + pub enterprise: Option, + /// The pages that were updated + pub pages: Vec, +} diff --git a/src/models/webhook_events/payload/installation.rs b/src/models/webhook_events/payload/installation.rs new file mode 100644 index 00000000..af3e4159 --- /dev/null +++ b/src/models/webhook_events/payload/installation.rs @@ -0,0 +1,23 @@ +use serde::{Deserialize, Serialize}; + +use crate::models::webhook_events::InstallationEventRepository; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct InstallationWebhookEventPayload { + pub action: InstallationWebhookEventAction, + pub enterprise: Option, + pub repositories: Vec, + pub requester: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum InstallationWebhookEventAction { + Created, + Deleted, + NewPermissionsAccepted, + Suspend, + Unsuspend, +} diff --git a/src/models/webhook_events/payload/installation_repositories.rs b/src/models/webhook_events/payload/installation_repositories.rs new file mode 100644 index 00000000..cda98984 --- /dev/null +++ b/src/models/webhook_events/payload/installation_repositories.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +use crate::models::webhook_events::InstallationEventRepository; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct InstallationRepositoriesWebhookEventPayload { + pub action: InstallationRepositoriesWebhookEventAction, + pub enterprise: Option, + pub repositories_added: Vec, + pub repositories_removed: Vec, + pub repository_selection: InstallationRepositoriesWebhookEventSelection, + pub requester: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum InstallationRepositoriesWebhookEventAction { + Added, + Removed, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum InstallationRepositoriesWebhookEventSelection { + All, + Selected, +} diff --git a/src/models/webhook_events/payload/installation_target.rs b/src/models/webhook_events/payload/installation_target.rs new file mode 100644 index 00000000..e72a0043 --- /dev/null +++ b/src/models/webhook_events/payload/installation_target.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct InstallationTargetWebhookEventPayload { + pub account: serde_json::Value, + pub action: String, + pub changes: serde_json::Value, + pub enterprise: Option, + pub target_type: String, +} diff --git a/src/models/webhook_events/payload/issue_comment.rs b/src/models/webhook_events/payload/issue_comment.rs new file mode 100644 index 00000000..0cef4c56 --- /dev/null +++ b/src/models/webhook_events/payload/issue_comment.rs @@ -0,0 +1,30 @@ +use serde::{Deserialize, Serialize}; + +use crate::models::issues::{Comment, Issue}; + +use super::OldValue; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct IssueCommentWebhookEventPayload { + pub action: IssueCommentWebhookEventAction, + pub changes: Option, + pub comment: Comment, + pub enterprise: Option, + pub issue: Issue, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +#[non_exhaustive] +pub enum IssueCommentWebhookEventAction { + Created, + Deleted, + Edited, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct IssueCommentWebhookEventChanges { + pub body: OldValue, +} diff --git a/src/models/webhook_events/payload/issues.rs b/src/models/webhook_events/payload/issues.rs new file mode 100644 index 00000000..cf679bfb --- /dev/null +++ b/src/models/webhook_events/payload/issues.rs @@ -0,0 +1,46 @@ +use serde::{Deserialize, Serialize}; + +use crate::models::{issues::Issue, Author, Label, Milestone}; + +use super::OldValue; + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[non_exhaustive] +pub struct IssuesWebhookEventPayload { + pub action: IssuesWebhookEventAction, + pub assignee: Option, + pub enterprise: Option, + pub issue: Issue, + pub milestone: Option, + pub label: Option