From 082a3c8db795364c4dac5daf8d59afb4b61af524 Mon Sep 17 00:00:00 2001 From: Rob Berry Date: Tue, 29 Jan 2019 12:40:19 +0000 Subject: [PATCH] Handle PullRequestEvent where related PR has empty body It doesn't seem to be covered in the github docs but it is possible to create a pull request with no body/description in which case the body is sent as Null which fails to decode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` λ> eitherDecodeStrict b :: Either String PullRequestEvent Left "Error in $['pull_request'].body: expected Text, encountered Null" ``` --- fixtures/pull-request-event-null-body.json | 415 ++++++++++++++ github-webhooks.cabal | 3 +- spec/DecodeEventsSpec.hs | 402 ++++++++++++- src/GitHub/Data/Webhooks/Payload.hs | 632 ++++++++++----------- 4 files changed, 1130 insertions(+), 322 deletions(-) create mode 100644 fixtures/pull-request-event-null-body.json diff --git a/fixtures/pull-request-event-null-body.json b/fixtures/pull-request-event-null-body.json new file mode 100644 index 0000000..3827ab0 --- /dev/null +++ b/fixtures/pull-request-event-null-body.json @@ -0,0 +1,415 @@ +{ + "action": "opened", + "number": 1, + "pull_request": { + "url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1", + "id": 34778301, + "html_url": "https://github.com/baxterthehacker/public-repo/pull/1", + "diff_url": "https://github.com/baxterthehacker/public-repo/pull/1.diff", + "patch_url": "https://github.com/baxterthehacker/public-repo/pull/1.patch", + "issue_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1", + "number": 1, + "state": "open", + "locked": false, + "title": "Update the README with new information", + "user": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "body": null, + "created_at": "2015-05-05T23:40:27Z", + "updated_at": "2015-05-05T23:40:27Z", + "closed_at": null, + "merged_at": null, + "merge_commit_sha": null, + "assignee": null, + "milestone": null, + "commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/commits", + "review_comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/comments", + "review_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments{/number}", + "comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1/comments", + "statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c", + "head": { + "label": "baxterthehacker:changes", + "ref": "changes", + "sha": "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c", + "user": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 35129377, + "name": "public-repo", + "full_name": "baxterthehacker/public-repo", + "owner": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/baxterthehacker/public-repo", + "description": "", + "fork": false, + "url": "https://api.github.com/repos/baxterthehacker/public-repo", + "forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks", + "keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams", + "hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks", + "issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events", + "assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags", + "blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages", + "stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers", + "contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors", + "subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers", + "subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription", + "commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges", + "archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads", + "issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}", + "created_at": "2015-05-05T23:40:12Z", + "updated_at": "2015-05-05T23:40:12Z", + "pushed_at": "2015-05-05T23:40:26Z", + "git_url": "git://github.com/baxterthehacker/public-repo.git", + "ssh_url": "git@github.com:baxterthehacker/public-repo.git", + "clone_url": "https://github.com/baxterthehacker/public-repo.git", + "svn_url": "https://github.com/baxterthehacker/public-repo", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 1, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "master" + } + }, + "base": { + "label": "baxterthehacker:master", + "ref": "master", + "sha": "9049f1265b7d61be4a8904a9a27120d2064dab3b", + "user": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "repo": { + "id": 35129377, + "name": "public-repo", + "full_name": "baxterthehacker/public-repo", + "owner": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/baxterthehacker/public-repo", + "description": "", + "fork": false, + "url": "https://api.github.com/repos/baxterthehacker/public-repo", + "forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks", + "keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams", + "hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks", + "issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events", + "assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags", + "blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages", + "stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers", + "contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors", + "subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers", + "subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription", + "commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges", + "archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads", + "issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}", + "created_at": "2015-05-05T23:40:12Z", + "updated_at": "2015-05-05T23:40:12Z", + "pushed_at": "2015-05-05T23:40:26Z", + "git_url": "git://github.com/baxterthehacker/public-repo.git", + "ssh_url": "git@github.com:baxterthehacker/public-repo.git", + "clone_url": "https://github.com/baxterthehacker/public-repo.git", + "svn_url": "https://github.com/baxterthehacker/public-repo", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 1, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "master" + } + }, + "_links": { + "self": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1" + }, + "html": { + "href": "https://github.com/baxterthehacker/public-repo/pull/1" + }, + "issue": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1" + }, + "comments": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/issues/1/comments" + }, + "review_comments": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/comments" + }, + "review_comment": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments{/number}" + }, + "commits": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/commits" + }, + "statuses": { + "href": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c" + } + }, + "merged": false, + "mergeable": null, + "mergeable_state": "unknown", + "merged_by": null, + "comments": 0, + "review_comments": 0, + "commits": 1, + "additions": 1, + "deletions": 1, + "changed_files": 1 + }, + "repository": { + "id": 35129377, + "name": "public-repo", + "full_name": "baxterthehacker/public-repo", + "owner": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "private": false, + "html_url": "https://github.com/baxterthehacker/public-repo", + "description": "", + "fork": false, + "url": "https://api.github.com/repos/baxterthehacker/public-repo", + "forks_url": "https://api.github.com/repos/baxterthehacker/public-repo/forks", + "keys_url": "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}", + "collaborators_url": "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}", + "teams_url": "https://api.github.com/repos/baxterthehacker/public-repo/teams", + "hooks_url": "https://api.github.com/repos/baxterthehacker/public-repo/hooks", + "issue_events_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}", + "events_url": "https://api.github.com/repos/baxterthehacker/public-repo/events", + "assignees_url": "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}", + "branches_url": "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}", + "tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/tags", + "blobs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}", + "git_tags_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}", + "git_refs_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}", + "trees_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}", + "statuses_url": "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}", + "languages_url": "https://api.github.com/repos/baxterthehacker/public-repo/languages", + "stargazers_url": "https://api.github.com/repos/baxterthehacker/public-repo/stargazers", + "contributors_url": "https://api.github.com/repos/baxterthehacker/public-repo/contributors", + "subscribers_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscribers", + "subscription_url": "https://api.github.com/repos/baxterthehacker/public-repo/subscription", + "commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}", + "git_commits_url": "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}", + "comments_url": "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}", + "issue_comment_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}", + "contents_url": "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}", + "compare_url": "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}", + "merges_url": "https://api.github.com/repos/baxterthehacker/public-repo/merges", + "archive_url": "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}", + "downloads_url": "https://api.github.com/repos/baxterthehacker/public-repo/downloads", + "issues_url": "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}", + "pulls_url": "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}", + "milestones_url": "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}", + "notifications_url": "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}", + "labels_url": "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}", + "releases_url": "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}", + "created_at": "2015-05-05T23:40:12Z", + "updated_at": "2015-05-05T23:40:12Z", + "pushed_at": "2015-05-05T23:40:26Z", + "git_url": "git://github.com/baxterthehacker/public-repo.git", + "ssh_url": "git@github.com:baxterthehacker/public-repo.git", + "clone_url": "https://github.com/baxterthehacker/public-repo.git", + "svn_url": "https://github.com/baxterthehacker/public-repo", + "homepage": null, + "size": 0, + "stargazers_count": 0, + "watchers_count": 0, + "language": null, + "has_issues": true, + "has_downloads": true, + "has_wiki": true, + "has_pages": true, + "forks_count": 0, + "mirror_url": null, + "open_issues_count": 1, + "forks": 0, + "open_issues": 1, + "watchers": 0, + "default_branch": "master" + }, + "sender": { + "login": "baxterthehacker", + "id": 6752317, + "avatar_url": "https://avatars.githubusercontent.com/u/6752317?v=3", + "gravatar_id": "", + "url": "https://api.github.com/users/baxterthehacker", + "html_url": "https://github.com/baxterthehacker", + "followers_url": "https://api.github.com/users/baxterthehacker/followers", + "following_url": "https://api.github.com/users/baxterthehacker/following{/other_user}", + "gists_url": "https://api.github.com/users/baxterthehacker/gists{/gist_id}", + "starred_url": "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}", + "subscriptions_url": "https://api.github.com/users/baxterthehacker/subscriptions", + "organizations_url": "https://api.github.com/users/baxterthehacker/orgs", + "repos_url": "https://api.github.com/users/baxterthehacker/repos", + "events_url": "https://api.github.com/users/baxterthehacker/events{/privacy}", + "received_events_url": "https://api.github.com/users/baxterthehacker/received_events", + "type": "User", + "site_admin": false + }, + "installation": { + "id": 234 + } +} diff --git a/github-webhooks.cabal b/github-webhooks.cabal index 2c627ba..6a60060 100644 --- a/github-webhooks.cabal +++ b/github-webhooks.cabal @@ -2,7 +2,7 @@ -- -- see: https://github.com/sol/hpack -- --- hash: fa98648f69f235f9a9cb69aea03e51473ebe2de375abab406423f9ef4420423b +-- hash: a1c4c8d07282b16c71f35367bc54136dd3c7724e45dbc279eec0ea418cd14a9a name: github-webhooks version: 0.10.0 @@ -45,6 +45,7 @@ extra-source-files: fixtures/project-column-event.json fixtures/project-event.json fixtures/public-event.json + fixtures/pull-request-event-null-body.json fixtures/pull-request-event.json fixtures/pull-request-review-comment-event.json fixtures/pull-request-review-event.json diff --git a/spec/DecodeEventsSpec.hs b/spec/DecodeEventsSpec.hs index e0d447e..7b91ff1 100644 --- a/spec/DecodeEventsSpec.hs +++ b/spec/DecodeEventsSpec.hs @@ -3,12 +3,12 @@ module DecodeEventsSpec ( spec ) where +import Control.Monad (void) +import Data.Aeson (FromJSON, eitherDecode') +import qualified Data.ByteString.Lazy as BSL +import qualified Data.Text as T +import qualified Data.Vector as V import Test.Hspec -import Control.Monad ( void ) -import Data.Aeson ( FromJSON, eitherDecode' ) -import qualified Data.Text as T -import qualified Data.ByteString.Lazy as BSL -import qualified Data.Vector as V import GitHub.Data.Webhooks.Events import GitHub.Data.Webhooks.Payload @@ -62,6 +62,7 @@ spec = do it "can decode ProjectEvent" $ fixtureShouldMatch "fixtures/project-event.json" projectEventFixture it "can decode PublicEvent" $ fixtureShouldMatch "fixtures/public-event.json" publicEventFixture it "can decode PullRequestEvent" $ fixtureShouldMatch "fixtures/pull-request-event.json" pullRequestEventFixture + it "can decode PullRequestEvent when body is null" $ fixtureShouldMatch "fixtures/pull-request-event-null-body.json" pullRequestEventNullBodyFixture it "can decode PullRequestReviewCommentEvent" $ fixtureShouldMatch "fixtures/pull-request-review-comment-event.json" pullRequestReviewCommentEventFixture it "can decode PullRequestReviewEvent" $ fixtureShouldMatch "fixtures/pull-request-review-event.json" pullRequestReviewEventFixture it "can decode PushEvent" $ fixtureShouldMatch "fixtures/push-event.json" pushEventFixture @@ -3264,6 +3265,397 @@ pullRequestEventFixture = PullRequestEvent , evPullReqInstallationId = Just 234 } +pullRequestEventNullBodyFixture :: PullRequestEvent +pullRequestEventNullBodyFixture = PullRequestEvent + { evPullReqAction = PullRequestOpenedAction + , evPullReqNumber = 1 + , evPullReqPayload = + HookPullRequest + { whPullReqUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1" + , whPullReqId = 34778301 + , whPullReqHtmlUrl = URL "https://github.com/baxterthehacker/public-repo/pull/1" + , whPullReqDiffUrl = URL "https://github.com/baxterthehacker/public-repo/pull/1.diff" + , whPullReqPatchUrl = URL "https://github.com/baxterthehacker/public-repo/pull/1.patch" + , whPullReqIssueUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/1" + , whPullReqNumber = 1 + , whPullReqState = "open" + , whPullReqIsLocked = False + , whPullReqTitle = "Update the README with new information" + , whPullReqUser = + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whPullReqBody = "" + , whPullReqCreatedAt = read "2015-05-05 23:40:27" + , whPullReqUpdatedAt = read "2015-05-05 23:40:27" + , whPullReqClosedAt = Nothing + , whPullReqMergedAt = Nothing + , whPullReqMergeCommitSha = Nothing + , whPullReqAssignee = Nothing + , whPullReqMilestone = Nothing + , whPullReqCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/commits" + , whPullReqRevCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls/1/comments" + , whPullReqRevCommentUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls/comments{/number}" + , whPullReqCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/1/comments" + , whPullReqStatusesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/statuses/0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c" + , whPullReqBase = + PullRequestTarget + { whPullReqTargetSha = "9049f1265b7d61be4a8904a9a27120d2064dab3b" + , whPullReqTargetUser = + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whPullReqTargetRepo = + HookRepository + { whRepoId = 35129377 + , whRepoName = "public-repo" + , whRepoFullName = "baxterthehacker/public-repo" + , whRepoOwner = + Right + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whRepoIsPrivate = False + , whRepoHtmlUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoDescription = "" + , whRepoIsAFork = False + , whRepoUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo" + , whRepoForksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/forks" + , whRepoKeysUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}" + , whRepoCollaboratorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}" + , whRepoTeamsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/teams" + , whRepoHooksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/hooks" + , whRepoIssueEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}" + , whRepoEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/events" + , whRepoAssigneesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}" + , whRepoBranchesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}" + , whRepoTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/tags" + , whRepoBlobsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}" + , whRepoGitTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}" + , whRepoGitRefsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}" + , whRepoTreesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}" + , whRepoStatusesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}" + , whRepoLanguagesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/languages" + , whRepoStargazersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/stargazers" + , whRepoContributorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contributors" + , whRepoSubscribersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscribers" + , whRepoSubscriptionUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscription" + , whRepoCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}" + , whRepoGitCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}" + , whRepoCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}" + , whRepoIssueCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}" + , whRepoContentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}" + , whRepoCompareUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}" + , whRepoMergesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/merges" + , whRepoArchiveUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}" + , whRepoDownloadsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/downloads" + , whRepoIssuesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}" + , whRepoPullsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}" + , whRepoMilestonesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}" + , whRepoNotificationsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}" + , whRepoLabelsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}" + , whRepoReleasesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}" + , whRepoCreatedAt = read "2015-05-05 23:40:12" + , whRepoUpdatedAt = read "2015-05-05 23:40:12" + , whRepoPushedAt = read "2015-05-05 23:40:26" + , whRepoGitUrl = URL "git://github.com/baxterthehacker/public-repo.git" + , whRepoSshUrl = URL "git@github.com:baxterthehacker/public-repo.git" + , whRepoCloneUrl = URL "https://github.com/baxterthehacker/public-repo.git" + , whRepoSvnUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoHomepage = Nothing + , whRepoSize = 0 + , whRepoStargazersCount = 0 + , whRepoWatchersCount = 0 + , whRepoLanguage = Nothing + , whRepoHasIssues = True + , whRepoHasDownloads = True + , whRepoHasWiki = True + , whRepoHasPages = True + , whRepoForkCount = 0 + , whRepoMirrorUrl = Nothing + , whRepoOpenIssuesCount = 1 + , whRepoDefaultBranchName = "master" + } + , whPullReqTargetLabel = "baxterthehacker:master" + , whPullReqTargetRef = "master" + } + , whPullReqHead = + PullRequestTarget + { whPullReqTargetSha = "0d1a26e67d8f5eaf1f6ba5c57fc3c7d91ac0fd1c" + , whPullReqTargetUser = + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whPullReqTargetRepo = + HookRepository + { whRepoId = 35129377 + , whRepoName = "public-repo" + , whRepoFullName = "baxterthehacker/public-repo" + , whRepoOwner = + Right + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whRepoIsPrivate = False + , whRepoHtmlUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoDescription = "" + , whRepoIsAFork = False + , whRepoUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo" + , whRepoForksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/forks" + , whRepoKeysUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}" + , whRepoCollaboratorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}" + , whRepoTeamsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/teams" + , whRepoHooksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/hooks" + , whRepoIssueEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}" + , whRepoEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/events" + , whRepoAssigneesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}" + , whRepoBranchesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}" + , whRepoTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/tags" + , whRepoBlobsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}" + , whRepoGitTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}" + , whRepoGitRefsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}" + , whRepoTreesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}" + , whRepoStatusesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}" + , whRepoLanguagesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/languages" + , whRepoStargazersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/stargazers" + , whRepoContributorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contributors" + , whRepoSubscribersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscribers" + , whRepoSubscriptionUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscription" + , whRepoCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}" + , whRepoGitCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}" + , whRepoCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}" + , whRepoIssueCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}" + , whRepoContentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}" + , whRepoCompareUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}" + , whRepoMergesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/merges" + , whRepoArchiveUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}" + , whRepoDownloadsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/downloads" + , whRepoIssuesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}" + , whRepoPullsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}" + , whRepoMilestonesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}" + , whRepoNotificationsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}" + , whRepoLabelsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}" + , whRepoReleasesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}" + , whRepoCreatedAt = read "2015-05-05 23:40:12" + , whRepoUpdatedAt = read "2015-05-05 23:40:12" + , whRepoPushedAt = read "2015-05-05 23:40:26" + , whRepoGitUrl = URL "git://github.com/baxterthehacker/public-repo.git" + , whRepoSshUrl = URL "git@github.com:baxterthehacker/public-repo.git" + , whRepoCloneUrl = URL "https://github.com/baxterthehacker/public-repo.git" + , whRepoSvnUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoHomepage = Nothing + , whRepoSize = 0 + , whRepoStargazersCount = 0 + , whRepoWatchersCount = 0 + , whRepoLanguage = Nothing + , whRepoHasIssues = True + , whRepoHasDownloads = True + , whRepoHasWiki = True + , whRepoHasPages = True + , whRepoForkCount = 0 + , whRepoMirrorUrl = Nothing + , whRepoOpenIssuesCount = 1 + , whRepoDefaultBranchName = "master" + } + , whPullReqTargetLabel = "baxterthehacker:changes" + , whPullReqTargetRef = "changes" + } + , whPullReqCommentCount = Just 0 + , whPullReqRevCommentCount = Just 0 + , whPullReqCommitCount = Just 1 + , whPullReqAdditionsCount = Just 1 + , whPullReqDeletionsCount = Just 1 + , whPullReqFileChangeCount = Just 1 + } + , evPullReqRepo = + HookRepository + { whRepoId = 35129377 + , whRepoName = "public-repo" + , whRepoFullName = "baxterthehacker/public-repo" + , whRepoOwner = + Right HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , whRepoIsPrivate = False + , whRepoHtmlUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoDescription = "" + , whRepoIsAFork = False + , whRepoUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo" + , whRepoForksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/forks" + , whRepoKeysUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/keys{/key_id}" + , whRepoCollaboratorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/collaborators{/collaborator}" + , whRepoTeamsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/teams" + , whRepoHooksUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/hooks" + , whRepoIssueEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/events{/number}" + , whRepoEventsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/events" + , whRepoAssigneesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/assignees{/user}" + , whRepoBranchesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/branches{/branch}" + , whRepoTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/tags" + , whRepoBlobsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/blobs{/sha}" + , whRepoGitTagsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/tags{/sha}" + , whRepoGitRefsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/refs{/sha}" + , whRepoTreesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/trees{/sha}" + , whRepoStatusesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/statuses/{sha}" + , whRepoLanguagesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/languages" + , whRepoStargazersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/stargazers" + , whRepoContributorsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contributors" + , whRepoSubscribersUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscribers" + , whRepoSubscriptionUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/subscription" + , whRepoCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/commits{/sha}" + , whRepoGitCommitsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/git/commits{/sha}" + , whRepoCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/comments{/number}" + , whRepoIssueCommentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues/comments{/number}" + , whRepoContentsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/contents/{+path}" + , whRepoCompareUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/compare/{base}...{head}" + , whRepoMergesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/merges" + , whRepoArchiveUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/{archive_format}{/ref}" + , whRepoDownloadsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/downloads" + , whRepoIssuesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/issues{/number}" + , whRepoPullsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/pulls{/number}" + , whRepoMilestonesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/milestones{/number}" + , whRepoNotificationsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/notifications{?since,all,participating}" + , whRepoLabelsUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/labels{/name}" + , whRepoReleasesUrl = URL "https://api.github.com/repos/baxterthehacker/public-repo/releases{/id}" + , whRepoCreatedAt = read "2015-05-05 23:40:12" + , whRepoUpdatedAt = read "2015-05-05 23:40:12" + , whRepoPushedAt = read "2015-05-05 23:40:26" + , whRepoGitUrl = URL "git://github.com/baxterthehacker/public-repo.git" + , whRepoSshUrl = URL "git@github.com:baxterthehacker/public-repo.git" + , whRepoCloneUrl = URL "https://github.com/baxterthehacker/public-repo.git" + , whRepoSvnUrl = URL "https://github.com/baxterthehacker/public-repo" + , whRepoHomepage = Nothing + , whRepoSize = 0 + , whRepoStargazersCount = 0 + , whRepoWatchersCount = 0 + , whRepoLanguage = Nothing + , whRepoHasIssues = True + , whRepoHasDownloads = True + , whRepoHasWiki = True + , whRepoHasPages = True + , whRepoForkCount = 0 + , whRepoMirrorUrl = Nothing + , whRepoOpenIssuesCount = 1 + , whRepoDefaultBranchName = "master" + } + , evPullReqSender = + HookUser + { whUserLogin = "baxterthehacker" + , whUserId = 6752317 + , whUserAvatarUrl = URL "https://avatars.githubusercontent.com/u/6752317?v=3" + , whUserGravatarId = URL "" + , whUserUrl = URL "https://api.github.com/users/baxterthehacker" + , whUserHtmlUrl = URL "https://github.com/baxterthehacker" + , whUserFollowersUrl = URL "https://api.github.com/users/baxterthehacker/followers" + , whUserFollowingUrl = URL "https://api.github.com/users/baxterthehacker/following{/other_user}" + , whUserGistsUrl = URL "https://api.github.com/users/baxterthehacker/gists{/gist_id}" + , whUserStarredUrl = URL "https://api.github.com/users/baxterthehacker/starred{/owner}{/repo}" + , whUserSubscriptionsUrl = URL "https://api.github.com/users/baxterthehacker/subscriptions" + , whUserOrganizationsUrl = URL "https://api.github.com/users/baxterthehacker/orgs" + , whUserReposUrl = URL "https://api.github.com/users/baxterthehacker/repos" + , whUserEventsUrl = URL "https://api.github.com/users/baxterthehacker/events{/privacy}" + , whUserReceivedEventsUrl = URL "https://api.github.com/users/baxterthehacker/received_events" + , whUserType = OwnerUser + , whUserIsAdminOfSite = False + } + , evPullReqInstallationId = Just 234 + } + pullRequestReviewCommentEventFixture :: PullRequestReviewCommentEvent pullRequestReviewCommentEventFixture = PullRequestReviewCommentEvent { evPullReqRevComAction = PullRequestReviewCommentCreatedAction diff --git a/src/GitHub/Data/Webhooks/Payload.hs b/src/GitHub/Data/Webhooks/Payload.hs index 8705b28..d64d167 100644 --- a/src/GitHub/Data/Webhooks/Payload.hs +++ b/src/GitHub/Data/Webhooks/Payload.hs @@ -44,15 +44,15 @@ module GitHub.Data.Webhooks.Payload , HookPullRequestReviewComment(..) ) where -import Data.Aeson (FromJSON(..), withObject, withText, (.!=), (.:), (.:?)) +import Control.Applicative ((<|>)) import Control.DeepSeq (NFData (..)) import Control.DeepSeq.Generics (genericRnf) -import Control.Applicative ((<|>)) +import Data.Aeson (FromJSON (..), withObject, withText, (.!=), (.:), (.:?)) import Data.Data (Data, Typeable) -import Data.Time (UTCTime) -import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import Data.Text (Text) import qualified Data.Text as T +import Data.Time (UTCTime) +import Data.Time.Clock.POSIX (posixSecondsToUTCTime) import Data.Vector (Vector) import GHC.Generics (Generic) @@ -68,9 +68,9 @@ instance NFData OwnerType instance FromJSON OwnerType where parseJSON = withText "Owner type" $ \t -> case T.toLower t of - "user" -> pure OwnerUser - "organization" -> pure OwnerOrganization - _ -> fail $ "Unknown owner type: " ++ T.unpack t + "user" -> pure OwnerUser + "organization" -> pure OwnerOrganization + _ -> fail $ "Unknown owner type: " ++ T.unpack t -- | Represents an internet address that would be suitable to query @@ -95,25 +95,25 @@ type IssueState = Text -- | Represents the "issue" field in the 'IssueCommentEvent' -- and 'IssueEvent' payload. data HookIssue = HookIssue - { whIssueUrl :: !URL - , whIssueLabelsUrl :: !URL - , whIssueCommentsUrl :: !URL - , whIssueEventsUrl :: !URL - , whIssueHtmlUrl :: !URL - , whIssueId :: !Int - , whIssueNumber :: !Int - , whIssueTitle :: !Text - , whIssueUser :: !HookUser - , whIssueLabels :: !(Vector HookIssueLabels) - , whIssueState :: IssueState - , whIssueIsLocked :: !Bool - , whIssueAssignee :: !(Maybe HookUser) - , whIssueMilestone :: !(Maybe HookMilestone) - , whIssueCommentCount :: !Int - , whIssueCreatedAt :: !UTCTime - , whIssueUpdatedAt :: !UTCTime - , whIssueClosedAt :: !(Maybe UTCTime) - , whIssueBody :: !Text + { whIssueUrl :: !URL + , whIssueLabelsUrl :: !URL + , whIssueCommentsUrl :: !URL + , whIssueEventsUrl :: !URL + , whIssueHtmlUrl :: !URL + , whIssueId :: !Int + , whIssueNumber :: !Int + , whIssueTitle :: !Text + , whIssueUser :: !HookUser + , whIssueLabels :: !(Vector HookIssueLabels) + , whIssueState :: IssueState + , whIssueIsLocked :: !Bool + , whIssueAssignee :: !(Maybe HookUser) + , whIssueMilestone :: !(Maybe HookMilestone) + , whIssueCommentCount :: !Int + , whIssueCreatedAt :: !UTCTime + , whIssueUpdatedAt :: !UTCTime + , whIssueClosedAt :: !(Maybe UTCTime) + , whIssueBody :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -121,70 +121,70 @@ instance NFData HookIssue where rnf = genericRnf -- | Represents the "repository" field in all types of payload. data HookRepository = HookRepository - { whRepoId :: !Int - , whRepoName :: !Text - , whRepoFullName :: !Text - , whRepoOwner :: !(Either HookSimpleUser HookUser) - , whRepoIsPrivate :: !Bool - , whRepoHtmlUrl :: !URL - , whRepoDescription :: !Text - , whRepoIsAFork :: !Bool - , whRepoUrl :: !URL - , whRepoForksUrl :: !URL - , whRepoKeysUrl :: !URL - , whRepoCollaboratorsUrl :: !URL - , whRepoTeamsUrl :: !URL - , whRepoHooksUrl :: !URL - , whRepoIssueEventsUrl :: !URL - , whRepoEventsUrl :: !URL - , whRepoAssigneesUrl :: !URL - , whRepoBranchesUrl :: !URL - , whRepoTagsUrl :: !URL - , whRepoBlobsUrl :: !URL - , whRepoGitTagsUrl :: !URL - , whRepoGitRefsUrl :: !URL - , whRepoTreesUrl :: !URL - , whRepoStatusesUrl :: !URL - , whRepoLanguagesUrl :: !URL - , whRepoStargazersUrl :: !URL - , whRepoContributorsUrl :: !URL - , whRepoSubscribersUrl :: !URL - , whRepoSubscriptionUrl :: !URL - , whRepoCommitsUrl :: !URL - , whRepoGitCommitsUrl :: !URL - , whRepoCommentsUrl :: !URL - , whRepoIssueCommentsUrl :: !URL - , whRepoContentsUrl :: !URL - , whRepoCompareUrl :: !URL - , whRepoMergesUrl :: !URL - , whRepoArchiveUrl :: !URL - , whRepoDownloadsUrl :: !URL - , whRepoIssuesUrl :: !URL - , whRepoPullsUrl :: !URL - , whRepoMilestonesUrl :: !URL - , whRepoNotificationsUrl :: !URL - , whRepoLabelsUrl :: !URL - , whRepoReleasesUrl :: !URL - , whRepoCreatedAt :: !UTCTime - , whRepoUpdatedAt :: !UTCTime - , whRepoPushedAt :: !UTCTime - , whRepoGitUrl :: !URL - , whRepoSshUrl :: !URL - , whRepoCloneUrl :: !URL - , whRepoSvnUrl :: !URL - , whRepoHomepage :: !(Maybe URL) - , whRepoSize :: !Int - , whRepoStargazersCount :: !Int - , whRepoWatchersCount :: !Int - , whRepoLanguage :: !(Maybe Text) - , whRepoHasIssues :: !Bool - , whRepoHasDownloads :: !Bool - , whRepoHasWiki :: !Bool - , whRepoHasPages :: !Bool - , whRepoForkCount :: !Int - , whRepoMirrorUrl :: !(Maybe URL) - , whRepoOpenIssuesCount :: !Int - , whRepoDefaultBranchName :: !Text + { whRepoId :: !Int + , whRepoName :: !Text + , whRepoFullName :: !Text + , whRepoOwner :: !(Either HookSimpleUser HookUser) + , whRepoIsPrivate :: !Bool + , whRepoHtmlUrl :: !URL + , whRepoDescription :: !Text + , whRepoIsAFork :: !Bool + , whRepoUrl :: !URL + , whRepoForksUrl :: !URL + , whRepoKeysUrl :: !URL + , whRepoCollaboratorsUrl :: !URL + , whRepoTeamsUrl :: !URL + , whRepoHooksUrl :: !URL + , whRepoIssueEventsUrl :: !URL + , whRepoEventsUrl :: !URL + , whRepoAssigneesUrl :: !URL + , whRepoBranchesUrl :: !URL + , whRepoTagsUrl :: !URL + , whRepoBlobsUrl :: !URL + , whRepoGitTagsUrl :: !URL + , whRepoGitRefsUrl :: !URL + , whRepoTreesUrl :: !URL + , whRepoStatusesUrl :: !URL + , whRepoLanguagesUrl :: !URL + , whRepoStargazersUrl :: !URL + , whRepoContributorsUrl :: !URL + , whRepoSubscribersUrl :: !URL + , whRepoSubscriptionUrl :: !URL + , whRepoCommitsUrl :: !URL + , whRepoGitCommitsUrl :: !URL + , whRepoCommentsUrl :: !URL + , whRepoIssueCommentsUrl :: !URL + , whRepoContentsUrl :: !URL + , whRepoCompareUrl :: !URL + , whRepoMergesUrl :: !URL + , whRepoArchiveUrl :: !URL + , whRepoDownloadsUrl :: !URL + , whRepoIssuesUrl :: !URL + , whRepoPullsUrl :: !URL + , whRepoMilestonesUrl :: !URL + , whRepoNotificationsUrl :: !URL + , whRepoLabelsUrl :: !URL + , whRepoReleasesUrl :: !URL + , whRepoCreatedAt :: !UTCTime + , whRepoUpdatedAt :: !UTCTime + , whRepoPushedAt :: !UTCTime + , whRepoGitUrl :: !URL + , whRepoSshUrl :: !URL + , whRepoCloneUrl :: !URL + , whRepoSvnUrl :: !URL + , whRepoHomepage :: !(Maybe URL) + , whRepoSize :: !Int + , whRepoStargazersCount :: !Int + , whRepoWatchersCount :: !Int + , whRepoLanguage :: !(Maybe Text) + , whRepoHasIssues :: !Bool + , whRepoHasDownloads :: !Bool + , whRepoHasWiki :: !Bool + , whRepoHasPages :: !Bool + , whRepoForkCount :: !Int + , whRepoMirrorUrl :: !(Maybe URL) + , whRepoOpenIssuesCount :: !Int + , whRepoDefaultBranchName :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -193,10 +193,10 @@ instance NFData HookRepository where rnf = genericRnf -- | Represents the "repositories_added" and "repositories_removed" -- field in the 'InstallationRepositoriesEvent' payload. data HookRepositorySimple = HookRepositorySimple - { whSimplRepoId :: !Int - , whSimplRepoName :: !Text - , whSimplRepoFullName :: !Text - , whSimplRepoIsPrivate :: !Bool + { whSimplRepoId :: !Int + , whSimplRepoName :: !Text + , whSimplRepoFullName :: !Text + , whSimplRepoIsPrivate :: !Bool } deriving (Eq, Show, Typeable, Data, Generic) @@ -204,9 +204,9 @@ instance NFData HookRepositorySimple where rnf = genericRnf -- | Represents the "label" field in the 'LabelEvent' payload. data HookRepositoryLabel = HookRepositoryLabel - { whRepoLabelUrl :: !URL - , whRepoLabelName :: !Text - , whRepoLabelColor :: !Text + { whRepoLabelUrl :: !URL + , whRepoLabelName :: !Text + , whRepoLabelColor :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -214,23 +214,23 @@ instance NFData HookRepositoryLabel where rnf = genericRnf -- | Represents the "user" field in all types of payload. data HookUser = HookUser - { whUserLogin :: !Text - , whUserId :: !Int - , whUserAvatarUrl :: !URL - , whUserGravatarId :: !URL - , whUserUrl :: !URL - , whUserHtmlUrl :: !URL - , whUserFollowersUrl :: !URL - , whUserFollowingUrl :: !URL - , whUserGistsUrl :: !URL - , whUserStarredUrl :: !URL - , whUserSubscriptionsUrl :: !URL - , whUserOrganizationsUrl :: !URL - , whUserReposUrl :: !URL - , whUserEventsUrl :: !URL - , whUserReceivedEventsUrl :: !URL - , whUserType :: !OwnerType - , whUserIsAdminOfSite :: !Bool + { whUserLogin :: !Text + , whUserId :: !Int + , whUserAvatarUrl :: !URL + , whUserGravatarId :: !URL + , whUserUrl :: !URL + , whUserHtmlUrl :: !URL + , whUserFollowersUrl :: !URL + , whUserFollowingUrl :: !URL + , whUserGistsUrl :: !URL + , whUserStarredUrl :: !URL + , whUserSubscriptionsUrl :: !URL + , whUserOrganizationsUrl :: !URL + , whUserReposUrl :: !URL + , whUserEventsUrl :: !URL + , whUserReceivedEventsUrl :: !URL + , whUserType :: !OwnerType + , whUserIsAdminOfSite :: !Bool } deriving (Eq, Show, Typeable, Data, Generic) @@ -238,9 +238,9 @@ instance NFData HookUser where rnf = genericRnf -- FIXME: Not sure where this is. data HookSimpleUser = HookSimpleUser - { whSimplUserName :: !Text - , whSimplUserEmail :: !Text - , whSimplUserLogin :: !(Maybe Text) + { whSimplUserName :: !Text + , whSimplUserEmail :: !Text + , whSimplUserLogin :: !(Maybe Text) } deriving (Eq, Show, Typeable, Data, Generic) @@ -248,17 +248,17 @@ instance NFData HookSimpleUser where rnf = genericRnf -- | Represents the "organization" field in all types of payload. data HookOrganization = HookOrganization - { whOrgLogin :: !Text - , whOrgId :: !Int - , whOrgUrl :: !URL - , whOrgReposUrl :: !URL - , whOrgEventsUrl :: !URL - , whOrgHooksUrl :: !(Maybe URL) - , whOrgIssuesUrl :: !(Maybe URL) - , whOrgMembersUrl :: !URL - , whOrgPublicMembersUrl :: !URL - , whOrgAvatarUrl :: !URL - , whOrgDescription :: !Text + { whOrgLogin :: !Text + , whOrgId :: !Int + , whOrgUrl :: !URL + , whOrgReposUrl :: !URL + , whOrgEventsUrl :: !URL + , whOrgHooksUrl :: !(Maybe URL) + , whOrgIssuesUrl :: !(Maybe URL) + , whOrgMembersUrl :: !URL + , whOrgPublicMembersUrl :: !URL + , whOrgAvatarUrl :: !URL + , whOrgDescription :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -266,10 +266,10 @@ instance NFData HookOrganization where rnf = genericRnf -- | Represents the "invitation" field in the 'OrganizationEvent' payload. data HookOrganizationInvitation = HookOrganizationInvitation - { whOrgInvitationId :: !Int - , whOrgInvitationLogin :: !Text - , whOrgInvitationEmail :: !(Maybe Text) - , whOrgInvitationRole :: !Text + { whOrgInvitationId :: !Int + , whOrgInvitationLogin :: !Text + , whOrgInvitationEmail :: !(Maybe Text) + , whOrgInvitationRole :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -277,11 +277,11 @@ instance NFData HookOrganizationInvitation where rnf = genericRnf -- | Represents the "membership" field in the 'OrganizationEvent' payload. data HookOrganizationMembership = HookOrganizationMembership - { whOrgMembershipUrl :: !URL - , whOrgMembershipState :: !Text - , whOrgMembershipRole :: !Text - , whOrgMembershipOrgUrl :: !URL - , whOrgMembershipUser :: !HookUser + { whOrgMembershipUrl :: !URL + , whOrgMembershipState :: !Text + , whOrgMembershipRole :: !Text + , whOrgMembershipOrgUrl :: !URL + , whOrgMembershipUser :: !HookUser } deriving (Eq, Show, Typeable, Data, Generic) @@ -290,13 +290,13 @@ instance NFData HookOrganizationMembership where rnf = genericRnf -- | Represents the "team" field in the 'TeamEvent' and -- 'TeamAddEvent' payload. data HookTeam = HookTeam - { whTeamName :: !Text - , whTeamId :: !Int - , whTeamSlug :: !Text - , whTeamPermission :: !Text - , whTeamUrl :: !URL - , whTeamMembersUrl :: !URL - , whTeamRepositoriesUrl :: !URL + { whTeamName :: !Text + , whTeamId :: !Int + , whTeamSlug :: !Text + , whTeamPermission :: !Text + , whTeamUrl :: !URL + , whTeamMembersUrl :: !URL + , whTeamRepositoriesUrl :: !URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -307,21 +307,21 @@ type MilestoneState = Text -- | Represents the "milestone" field in the 'MilestoneEvent' payload. data HookMilestone = HookMilestone - { whMilestoneUrl :: !URL - , whMilestoneHtmlUrl :: !URL - , whMilestoneLabelsUrl :: !URL - , whMilestoneId :: !Int - , whMilestoneNumber :: !Int - , whMilestoneTitle :: !Text - , whMilestoneDescription :: !(Maybe Text) - , whMilestoneCreator :: !HookUser - , whMilestoneOpenIssues :: !Int - , whMilestoneClosedIssues :: !Int - , whMilestoneState :: !MilestoneState - , whMilestoneCreatedAt :: !UTCTime - , whMilestoneUpdatedAt :: !UTCTime - , whMilestoneDueOn :: !(Maybe UTCTime) - , whMilestoneClosedAt :: !(Maybe UTCTime) + { whMilestoneUrl :: !URL + , whMilestoneHtmlUrl :: !URL + , whMilestoneLabelsUrl :: !URL + , whMilestoneId :: !Int + , whMilestoneNumber :: !Int + , whMilestoneTitle :: !Text + , whMilestoneDescription :: !(Maybe Text) + , whMilestoneCreator :: !HookUser + , whMilestoneOpenIssues :: !Int + , whMilestoneClosedIssues :: !Int + , whMilestoneState :: !MilestoneState + , whMilestoneCreatedAt :: !UTCTime + , whMilestoneUpdatedAt :: !UTCTime + , whMilestoneDueOn :: !(Maybe UTCTime) + , whMilestoneClosedAt :: !(Maybe UTCTime) } deriving (Eq, Show, Typeable, Data, Generic) @@ -333,11 +333,11 @@ type MembershipRole = Text -- FIXME: Not sure where this is. data HookMembership = HookMembership - { whMembershipUrl :: !URL - , whMembershipState :: !MembershipState - , whMembershipRole :: !MembershipRole - , whMembershipOrgUrl :: !URL - , whMembershipUser :: !HookUser + { whMembershipUrl :: !URL + , whMembershipState :: !MembershipState + , whMembershipRole :: !MembershipRole + , whMembershipOrgUrl :: !URL + , whMembershipUser :: !HookUser } deriving (Eq, Show, Typeable, Data, Generic) @@ -348,17 +348,17 @@ type ProjectState = Text -- | Represents the "project" field in the 'ProjectEvent' payload. data HookProject = HookProject - { whProjectOwnerUrl :: !URL - , whProjectUrl :: !URL - , whProjectColumnsUrl :: !URL - , whProjectId :: !Int - , whProjectName :: !Text - , whProjectBody :: !Text - , whProjectNumber :: !Int - , whProjectState :: !ProjectState - , whProjectCreator :: !HookUser - , whProjectCreatedAt :: !UTCTime - , whProjectUpdatedAt :: !UTCTime + { whProjectOwnerUrl :: !URL + , whProjectUrl :: !URL + , whProjectColumnsUrl :: !URL + , whProjectId :: !Int + , whProjectName :: !Text + , whProjectBody :: !Text + , whProjectNumber :: !Int + , whProjectState :: !ProjectState + , whProjectCreator :: !HookUser + , whProjectCreatedAt :: !UTCTime + , whProjectUpdatedAt :: !UTCTime } deriving (Eq, Show, Typeable, Data, Generic) @@ -366,15 +366,15 @@ instance NFData HookProject where rnf = genericRnf -- | Represents the "project_card" field in the 'ProjectCardEvent' payload. data HookProjectCard = HookProjectCard - { whProjectCardUrl :: !URL - , whProjectCardColumnUrl :: !URL - , whProjectCardColumnId :: !Int - , whProjectCardId :: !Int - , whProjectCardNote :: !(Maybe Text) - , whProjectCardCreator :: !HookUser - , whProjectCardCreatedAt :: !UTCTime - , whProjectCardUpdatedAt :: !UTCTime - , whProjectCardContentUrl :: !URL + { whProjectCardUrl :: !URL + , whProjectCardColumnUrl :: !URL + , whProjectCardColumnId :: !Int + , whProjectCardId :: !Int + , whProjectCardNote :: !(Maybe Text) + , whProjectCardCreator :: !HookUser + , whProjectCardCreatedAt :: !UTCTime + , whProjectCardUpdatedAt :: !UTCTime + , whProjectCardContentUrl :: !URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -382,13 +382,13 @@ instance NFData HookProjectCard where rnf = genericRnf -- | Represents the "project_column" field in the 'ProjectColumnEvent' payload. data HookProjectColumn = HookProjectColumn - { whProjectColumnUrl :: !URL - , whProjectColumnProjUrl :: !URL - , whProjectColumnCardsUrl :: !URL - , whProjectColumnId :: !Int - , whProjectColumnName :: !Text - , whProjectColumnCreatedAt :: !UTCTime - , whProjectColumnUpdatedAt :: !UTCTime + { whProjectColumnUrl :: !URL + , whProjectColumnProjUrl :: !URL + , whProjectColumnCardsUrl :: !URL + , whProjectColumnId :: !Int + , whProjectColumnName :: !Text + , whProjectColumnCreatedAt :: !UTCTime + , whProjectColumnUpdatedAt :: !UTCTime } deriving (Eq, Show, Typeable, Data, Generic) @@ -397,11 +397,11 @@ instance NFData HookProjectColumn where rnf = genericRnf -- | Represents the "issue.labels" field in the -- 'IssueCommentEvent' and 'IssueEvent' payloads. data HookIssueLabels = HookIssueLabels - { whIssueLabelId :: !(Maybe Int) -- ^ Not always sent. - , whIssueLabelUrl :: !URL - , whIssueLabelName :: !Text - , whIssueLabelColor :: !Text - , whIssueLabelIsDefault :: !Bool -- ^ Defaults to false when not present. + { whIssueLabelId :: !(Maybe Int) -- ^ Not always sent. + , whIssueLabelUrl :: !URL + , whIssueLabelName :: !Text + , whIssueLabelColor :: !Text + , whIssueLabelIsDefault :: !Bool -- ^ Defaults to false when not present. } deriving (Eq, Show, Typeable, Data, Generic) @@ -411,12 +411,12 @@ instance NFData HookIssueLabels where rnf = genericRnf -- FIXME: Missing nested metadata that provides commit description -- FIXME: Missing property "parent" (no examples provided) data HookCommit = HookCommit - { whCommitSha :: !Text -- ^ Sometimes called the commit 'id'. - , whCommitUrl :: !URL - , whCommitHtmlUrl :: !(Maybe URL) -- ^ Not always sent. - , whCommitCommentsUrl :: !(Maybe URL) -- ^ Not always sent. - , whCommitAuthor :: !(Either HookSimpleUser HookUser) - , whCommitCommitter :: !(Either HookSimpleUser HookUser) + { whCommitSha :: !Text -- ^ Sometimes called the commit 'id'. + , whCommitUrl :: !URL + , whCommitHtmlUrl :: !(Maybe URL) -- ^ Not always sent. + , whCommitCommentsUrl :: !(Maybe URL) -- ^ Not always sent. + , whCommitAuthor :: !(Either HookSimpleUser HookUser) + , whCommitCommitter :: !(Either HookSimpleUser HookUser) } deriving (Eq, Show, Typeable, Data, Generic) @@ -425,75 +425,75 @@ instance NFData HookCommit where rnf = genericRnf -- FIXME: Missing property "assets" (no examples provided) data HookRelease = HookRelease - { whReleaseUrl :: !URL - , whReleaseAssetsUrl :: !URL - , whReleaseUploadUrl :: !URL - , whReleaseHtmlUrl :: !URL - , whReleaseId :: !Int - , whReleaseTagName :: !Text - , whReleaseTargetCommitish :: !Text - , whReleaseName :: !(Maybe Text) - , whReleaseIsDraft :: !Bool - , whReleaseAuthor :: !HookUser - , whReleaseIsPreRelease :: !Bool - , whReleaseCreatedAt :: !UTCTime - , whReleasePublishedAt :: !(Maybe UTCTime) - , whReleaseTarballUrl :: !URL - , whReleaseZipballUrl :: !URL - , whReleaseBody :: !(Maybe Text) + { whReleaseUrl :: !URL + , whReleaseAssetsUrl :: !URL + , whReleaseUploadUrl :: !URL + , whReleaseHtmlUrl :: !URL + , whReleaseId :: !Int + , whReleaseTagName :: !Text + , whReleaseTargetCommitish :: !Text + , whReleaseName :: !(Maybe Text) + , whReleaseIsDraft :: !Bool + , whReleaseAuthor :: !HookUser + , whReleaseIsPreRelease :: !Bool + , whReleaseCreatedAt :: !UTCTime + , whReleasePublishedAt :: !(Maybe UTCTime) + , whReleaseTarballUrl :: !URL + , whReleaseZipballUrl :: !URL + , whReleaseBody :: !(Maybe Text) } deriving (Eq, Show, Typeable, Data, Generic) instance NFData HookRelease where rnf = genericRnf data HookPullRequest = HookPullRequest - { whPullReqUrl :: !URL - , whPullReqId :: !Int - , whPullReqHtmlUrl :: !URL - , whPullReqDiffUrl :: !URL - , whPullReqPatchUrl :: !URL - , whPullReqIssueUrl :: !URL - , whPullReqNumber :: !Int - , whPullReqState :: !Text -- FIXME: Smart constructor? - , whPullReqIsLocked :: !Bool - , whPullReqTitle :: !Text - , whPullReqUser :: !HookUser - , whPullReqBody :: !Text - , whPullReqCreatedAt :: !UTCTime - , whPullReqUpdatedAt :: !UTCTime - , whPullReqClosedAt :: !(Maybe UTCTime) - , whPullReqMergedAt :: !(Maybe UTCTime) - , whPullReqMergeCommitSha :: !(Maybe Text) - , whPullReqAssignee :: !(Maybe HookUser) - , whPullReqMilestone :: !(Maybe HookMilestone) - , whPullReqCommitsUrl :: !URL - , whPullReqRevCommentsUrl :: !URL - , whPullReqRevCommentUrl :: !URL - , whPullReqCommentsUrl :: !URL - , whPullReqStatusesUrl :: !URL - , whPullReqBase :: !PullRequestTarget - , whPullReqHead :: !PullRequestTarget + { whPullReqUrl :: !URL + , whPullReqId :: !Int + , whPullReqHtmlUrl :: !URL + , whPullReqDiffUrl :: !URL + , whPullReqPatchUrl :: !URL + , whPullReqIssueUrl :: !URL + , whPullReqNumber :: !Int + , whPullReqState :: !Text -- FIXME: Smart constructor? + , whPullReqIsLocked :: !Bool + , whPullReqTitle :: !Text + , whPullReqUser :: !HookUser + , whPullReqBody :: !Text + , whPullReqCreatedAt :: !UTCTime + , whPullReqUpdatedAt :: !UTCTime + , whPullReqClosedAt :: !(Maybe UTCTime) + , whPullReqMergedAt :: !(Maybe UTCTime) + , whPullReqMergeCommitSha :: !(Maybe Text) + , whPullReqAssignee :: !(Maybe HookUser) + , whPullReqMilestone :: !(Maybe HookMilestone) + , whPullReqCommitsUrl :: !URL + , whPullReqRevCommentsUrl :: !URL + , whPullReqRevCommentUrl :: !URL + , whPullReqCommentsUrl :: !URL + , whPullReqStatusesUrl :: !URL + , whPullReqBase :: !PullRequestTarget + , whPullReqHead :: !PullRequestTarget -- , whPullReqIsMerged :: !Bool -- , whPullReqIsMergeable :: !Bool -- , whPullReqMergeableState :: !Text -- , whPullReqMergedBy :: !(Maybe HookUser) - , whPullReqCommentCount :: !(Maybe Int) -- ^ Not sent with all events. - , whPullReqRevCommentCount :: !(Maybe Int) -- ^ Not sent with all events. - , whPullReqCommitCount :: !(Maybe Int) -- ^ Not sent with all events. - , whPullReqAdditionsCount :: !(Maybe Int) -- ^ Not sent with all events. - , whPullReqDeletionsCount :: !(Maybe Int) -- ^ Not sent with all events. - , whPullReqFileChangeCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqCommentCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqRevCommentCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqCommitCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqAdditionsCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqDeletionsCount :: !(Maybe Int) -- ^ Not sent with all events. + , whPullReqFileChangeCount :: !(Maybe Int) -- ^ Not sent with all events. } deriving (Eq, Show, Typeable, Data, Generic) instance NFData HookPullRequest where rnf = genericRnf data PullRequestTarget = PullRequestTarget - { whPullReqTargetSha :: !Text - , whPullReqTargetUser :: !HookUser - , whPullReqTargetRepo :: !HookRepository + { whPullReqTargetSha :: !Text + , whPullReqTargetUser :: !HookUser + , whPullReqTargetRepo :: !HookRepository , whPullReqTargetLabel :: !Text -- ex "user:branch" - , whPullReqTargetRef :: !Text -- ex "somebranch" + , whPullReqTargetRef :: !Text -- ex "somebranch" } deriving (Eq, Show, Typeable, Data, Generic) @@ -501,13 +501,13 @@ instance NFData PullRequestTarget where rnf = genericRnf -- | Represents the "pull_request" field in the 'PullRequestReviewEvent' payload. data HookPullRequestReview = HookPullRequestReview - { whPullReqReviewId :: !Int - , whPullReqReviewUser :: !HookUser - , whPullReqReviewBody :: !Text + { whPullReqReviewId :: !Int + , whPullReqReviewUser :: !HookUser + , whPullReqReviewBody :: !Text , whPullReqReviewSubmittedAt :: !UTCTime - , whPullReqReviewState :: !Text - , whPullReqReviewHtmlUrl :: !URL - , whPullReqReviewPullUrl :: !URL + , whPullReqReviewState :: !Text + , whPullReqReviewHtmlUrl :: !URL + , whPullReqReviewPullUrl :: !URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -515,11 +515,11 @@ instance NFData HookPullRequestReview where rnf = genericRnf -- | Represents the "installation" field in the 'InstallationEvent' payload. data HookInstallation = HookInstallation - { whInstallationId :: !Int - , whInstallationAccount :: !HookUser - , whInstallationRepoSel :: !Text - , whInstallationTokenUrl :: !URL - , whInstallationRepoUrl :: !URL + { whInstallationId :: !Int + , whInstallationAccount :: !HookUser + , whInstallationRepoSel :: !Text + , whInstallationTokenUrl :: !URL + , whInstallationRepoUrl :: !URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -528,19 +528,19 @@ instance NFData HookInstallation where rnf = genericRnf -- | Represents the "deployment" field in the -- 'DeploymentEvent' and 'DeploymentStatusEvent' payload. data HookDeployment = HookDeployment - { whDeploymentUrl :: !URL - , whDeploymentId :: !Int - , whDeploymentSha :: !Text - , whDeploymentRef :: !Text - , whDeploymentTask :: !Text + { whDeploymentUrl :: !URL + , whDeploymentId :: !Int + , whDeploymentSha :: !Text + , whDeploymentRef :: !Text + , whDeploymentTask :: !Text -- , whDeploymentPayload - , whDeploymentEnv :: !Text - , whDeploymentDescription :: !(Maybe Text) - , whDeploymentCreator :: !HookUser - , whDeploymentCreatedAt :: !UTCTime - , whDeploymentUpdatedAt :: !UTCTime - , whDeploymentStatusesUrl :: !URL - , whDeploymentRepoUrl :: !URL + , whDeploymentEnv :: !Text + , whDeploymentDescription :: !(Maybe Text) + , whDeploymentCreator :: !HookUser + , whDeploymentCreatedAt :: !UTCTime + , whDeploymentUpdatedAt :: !UTCTime + , whDeploymentStatusesUrl :: !URL + , whDeploymentRepoUrl :: !URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -549,11 +549,11 @@ instance NFData HookDeployment where rnf = genericRnf -- | Represents the "deployment_status" field in the -- 'DeploymentStatusEvent' payload. data HookDeploymentStatus = HookDeploymentStatus - { whDeploymentStatusUrl :: !URL - , whDeploymentStatusId :: !Int - , whDeploymentStatusState :: !Text - , whDeploymentStatusCreator :: !HookUser - , whDeploymentStatusDesc :: !(Maybe Text) + { whDeploymentStatusUrl :: !URL + , whDeploymentStatusId :: !Int + , whDeploymentStatusState :: !Text + , whDeploymentStatusCreator :: !HookUser + , whDeploymentStatusDesc :: !(Maybe Text) , whDeploymentStatusTargetUrl :: !(Maybe URL) , whDeploymentStatusCreatedAt :: !UTCTime , whDeploymentStatusUpdatedAt :: !UTCTime @@ -566,12 +566,12 @@ instance NFData HookDeploymentStatus where rnf = genericRnf -- | Represents the "pages" field in the 'GollumEvent' payload. data HookWikiPage = HookWikiPage - { whWikiPageName :: !Text - , whWikiPageTitle :: !Text - , whWikiPageSummary :: !(Maybe Text) - , wkWikiPageAction :: !Text - , whWikiPageSha :: !Text - , whWikiPageHtmlUrl :: URL + { whWikiPageName :: !Text + , whWikiPageTitle :: !Text + , whWikiPageSummary :: !(Maybe Text) + , wkWikiPageAction :: !Text + , whWikiPageSha :: !Text + , whWikiPageHtmlUrl :: URL } deriving (Eq, Show, Typeable, Data, Generic) @@ -579,14 +579,14 @@ instance NFData HookWikiPage where rnf = genericRnf -- | Represents the "build" field in the 'PageBuildEvent' payload. data HookPageBuildResult = HookPageBuildResult - { whPageBuildUrl :: !URL - , whPageBuildStatus :: !Text - , whPageBuildError :: !(Maybe Text) - , whPageBuildPusher :: !HookUser - , whPageBuildCommitSha :: !Text - , whPageBuildDuration :: !Int - , whPageBuildCreatedAt :: !UTCTime - , whPageBuildUpdatedAt :: !UTCTime + { whPageBuildUrl :: !URL + , whPageBuildStatus :: !Text + , whPageBuildError :: !(Maybe Text) + , whPageBuildPusher :: !HookUser + , whPageBuildCommitSha :: !Text + , whPageBuildDuration :: !Int + , whPageBuildCreatedAt :: !UTCTime + , whPageBuildUpdatedAt :: !UTCTime } deriving (Eq, Show, Typeable, Data, Generic) @@ -594,14 +594,14 @@ instance NFData HookPageBuildResult where rnf = genericRnf -- | Represents the "issue" field in 'IssueComentEvent' payload. data HookIssueComment = HookIssueComment - { whIssueCommentUrl :: !URL - , whIssueCommentHtmlUrl :: !URL - , whIssueCommentIssueUrl :: !URL - , whIssueCommentId :: !Int - , whIssueCommentUser :: !HookUser - , whIssueCommentCreatedAt :: !UTCTime - , whIssueCommentUpdatedAt :: !UTCTime - , whIssueCommentBody :: !Text + { whIssueCommentUrl :: !URL + , whIssueCommentHtmlUrl :: !URL + , whIssueCommentIssueUrl :: !URL + , whIssueCommentId :: !Int + , whIssueCommentUser :: !HookUser + , whIssueCommentCreatedAt :: !UTCTime + , whIssueCommentUpdatedAt :: !UTCTime + , whIssueCommentBody :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -609,17 +609,17 @@ instance NFData HookIssueComment where rnf = genericRnf -- | Represents the "comment" field in the 'CommitCommentEvent' payload. data HookCommitComment = HookCommitComment - { whCommitCommentUrl :: !URL - , whCommitCommentHtmlUrl :: !URL - , whCommitCommentId :: !Int - , whCommitCommentUser :: !HookUser - , whCommitCommentPos :: !(Maybe Int) - , whCommitCommentLine :: !(Maybe Int) - , whCommitCommentPath :: !(Maybe Text) - , whCommitCommentCommitSha :: !Text - , whCommitCommentCreatedAt :: !UTCTime - , whCommitCommentUpdatedAt :: !UTCTime - , whCommitCommentBody :: !Text + { whCommitCommentUrl :: !URL + , whCommitCommentHtmlUrl :: !URL + , whCommitCommentId :: !Int + , whCommitCommentUser :: !HookUser + , whCommitCommentPos :: !(Maybe Int) + , whCommitCommentLine :: !(Maybe Int) + , whCommitCommentPath :: !(Maybe Text) + , whCommitCommentCommitSha :: !Text + , whCommitCommentCreatedAt :: !UTCTime + , whCommitCommentUpdatedAt :: !UTCTime + , whCommitCommentBody :: !Text } deriving (Eq, Show, Typeable, Data, Generic) @@ -929,7 +929,7 @@ instance FromJSON HookPullRequest where <*> o .: "locked" <*> o .: "title" <*> o .: "user" - <*> o .: "body" + <*> o .:? "body" .!= "" <*> o .: "created_at" <*> o .: "updated_at" <*> o .:? "closed_at"