Skip to content

Commit 302e89a

Browse files
authored
Merge pull request #1185 from code-corps/fix-partially-supported-github-errored-events
Cleaned up unsupported and ignored event handling
2 parents 090b3a5 + 65f5143 commit 302e89a

File tree

21 files changed

+697
-245
lines changed

21 files changed

+697
-245
lines changed

lib/code_corps/github/event/installation/installation.ex

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@ defmodule CodeCorps.GitHub.Event.Installation do
1616
alias Ecto.{Changeset, Multi}
1717

1818
@type outcome :: {:ok, GithubAppInstallation.t} |
19-
{:error, :not_yet_implemented} |
20-
{:error, :unexpected_action} |
21-
{:error, :unexpected_payload} |
22-
{:error, :validation_error_on_syncing_installation} |
23-
{:error, :multiple_unprocessed_installations_found} |
24-
{:error, :github_api_error_on_syncing_repos} |
25-
{:error, :validation_error_on_deleting_removed_repos} |
26-
{:error, :validation_error_on_syncing_existing_repos} |
27-
{:error, :validation_error_on_marking_installation_processed}
19+
{:error, :unexpected_payload} |
20+
{:error, :validation_error_on_syncing_installation} |
21+
{:error, :multiple_unprocessed_installations_found} |
22+
{:error, :github_api_error_on_syncing_repos} |
23+
{:error, :validation_error_on_deleting_removed_repos} |
24+
{:error, :validation_error_on_syncing_existing_repos} |
25+
{:error, :validation_error_on_marking_installation_processed}
2826

2927
@doc """
3028
Handles the "Installation" GitHub Webhook event.
@@ -51,7 +49,6 @@ defmodule CodeCorps.GitHub.Event.Installation do
5149
def handle(payload) do
5250
Multi.new
5351
|> Multi.run(:payload, fn _ -> payload |> validate_payload() end)
54-
|> Multi.run(:action, fn _ -> payload |> validate_action() end)
5552
|> Multi.run(:user, fn _ -> payload |> find_user() end)
5653
|> Multi.run(:installation, fn %{user: user} -> install_for_user(user, payload) end)
5754
|> Multi.merge(&process_repos/1)
@@ -84,8 +81,6 @@ defmodule CodeCorps.GitHub.Event.Installation do
8481
@spec marshall_result(tuple) :: tuple
8582
defp marshall_result({:ok, %{processed_installation: installation}}), do: {:ok, installation}
8683
defp marshall_result({:error, :payload, :invalid, _steps}), do: {:error, :unexpected_payload}
87-
defp marshall_result({:error, :action, :unexpected_action, _steps}), do: {:error, :unexpected_action}
88-
defp marshall_result({:error, :action, :not_yet_implemented, _steps}), do: {:error, :not_yet_implemented}
8984
defp marshall_result({:error, :user, :unexpected_user_payload, _steps}), do: {:error, :unexpected_payload}
9085
defp marshall_result({:error, :installation, :unexpected_installation_payload, _steps}), do: {:error, :unexpected_payload}
9186
defp marshall_result({:error, :installation, %Changeset{}, _steps}), do: {:error, :validation_error_on_syncing_installation}
@@ -103,11 +98,4 @@ defmodule CodeCorps.GitHub.Event.Installation do
10398
false -> {:error, :invalid}
10499
end
105100
end
106-
107-
@spec validate_action(map) :: {:ok, :implemented} |
108-
{:error, :not_yet_implemented} |
109-
{:error, :unexpected_action}
110-
defp validate_action(%{"action" => "created"}), do: {:ok, :implemented}
111-
defp validate_action(%{"action" => "deleted"}), do: {:error, :not_yet_implemented}
112-
defp validate_action(%{}), do: {:error, :unexpected_action}
113101
end

lib/code_corps/github/event/installation_repositories/installation_repositories.ex

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ defmodule CodeCorps.GitHub.Event.InstallationRepositories do
2020
alias Ecto.{Changeset, Multi}
2121

2222
@type outcome :: {:ok, list(GithubRepo.t)} |
23-
{:error, :unmatched_installation} |
24-
{:error, :unexpected_action} |
25-
{:error, :unexpected_payload} |
26-
{:error, :validation_error_on_syncing_repos} |
27-
{:error, :unexpected_transaction_outcome}
23+
{:error, :unmatched_installation} |
24+
{:error, :unexpected_payload} |
25+
{:error, :validation_error_on_syncing_repos} |
26+
{:error, :unexpected_transaction_outcome}
2827

2928
@doc """
3029
Handles an "InstallationRepositories" GitHub Webhook event. The event could be
@@ -47,7 +46,6 @@ defmodule CodeCorps.GitHub.Event.InstallationRepositories do
4746
def handle(payload) do
4847
Multi.new
4948
|> Multi.run(:payload, fn _ -> payload |> validate_payload() end)
50-
|> Multi.run(:action, fn _ -> payload |> validate_action() end)
5149
|> Multi.run(:installation, fn _ -> payload |> match_installation() end)
5250
|> Multi.run(:repos, fn %{installation: installation} -> installation |> sync_repos(payload) end)
5351
|> Repo.transaction
@@ -62,11 +60,6 @@ defmodule CodeCorps.GitHub.Event.InstallationRepositories do
6260
end
6361
end
6462

65-
@valid_actions ~w(added removed)
66-
@spec validate_action(map) :: {:ok, :implemented} | {:error, :unexpected_action}
67-
defp validate_action(%{"action" => action}) when action in @valid_actions, do: {:ok, :implemented}
68-
defp validate_action(%{}), do: {:error, :unexpected_action}
69-
7063
@spec match_installation(map) :: {:ok, GithubAppInstallation.t} |
7164
{:error, :unmatched_installation}
7265
defp match_installation(%{"installation" => %{"id" => github_id}}) do
@@ -123,7 +116,6 @@ defmodule CodeCorps.GitHub.Event.InstallationRepositories do
123116
@spec marshall_result(tuple) :: tuple
124117
defp marshall_result({:ok, %{repos: repos}}), do: {:ok, repos}
125118
defp marshall_result({:error, :payload, :invalid, _steps}), do: {:error, :unexpected_payload}
126-
defp marshall_result({:error, :action, :unexpected_action, _steps}), do: {:error, :unexpected_action}
127119
defp marshall_result({:error, :installation, :unmatched_installation, _steps}), do: {:error, :unmatched_installation}
128120
defp marshall_result({:error, :repos, {_repos, _changesets}, _steps}), do: {:error, :validation_error_on_syncing_repos}
129121
defp marshall_result({:error, _errored_step, _error_response, _steps}), do: {:error, :unexpected_transaction_outcome}

lib/code_corps/github/event/issue_comment/issue_comment.ex

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ defmodule CodeCorps.GitHub.Event.IssueComment do
1212
}
1313
alias GitHub.Sync
1414

15-
@type outcome :: Sync.outcome
16-
| {:error, :unexpected_action}
17-
| {:error, :unexpected_payload}
15+
@type outcome :: Sync.outcome | {:error, :unexpected_payload}
1816

1917
@doc ~S"""
2018
Handles the "IssueComment" GitHub webhook
@@ -27,26 +25,18 @@ defmodule CodeCorps.GitHub.Event.IssueComment do
2725
"""
2826
@spec handle(map) :: outcome
2927
def handle(payload) do
30-
with {:ok, :valid} <- validate_payload(payload),
31-
{:ok, :implemented} <- validate_action(payload) do
28+
with {:ok, :valid} <- validate_payload(payload) do
3229
Sync.issue_comment_event(payload)
3330
else
3431
{:error, error} -> {:error, error}
3532
end
3633
end
3734

38-
@spec validate_payload(map) :: {:ok, :valid}
39-
| {:error, :unexpected_payload}
35+
@spec validate_payload(map) :: {:ok, :valid} | {:error, :unexpected_payload}
4036
defp validate_payload(%{} = payload) do
4137
case payload |> Validator.valid? do
4238
true -> {:ok, :valid}
4339
false -> {:error, :unexpected_payload}
4440
end
4541
end
46-
47-
@implemented_actions ~w(created edited deleted)
48-
49-
@spec validate_action(map) :: {:ok, :implemented} | {:error, :unexpected_action}
50-
defp validate_action(%{"action" => action}) when action in @implemented_actions, do: {:ok, :implemented}
51-
defp validate_action(%{}), do: {:error, :unexpected_action}
5242
end

lib/code_corps/github/event/issues/issues.ex

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ defmodule CodeCorps.GitHub.Event.Issues do
1313
}
1414
alias GitHub.Sync
1515

16-
@type outcome :: Sync.outcome
17-
| {:error, :unexpected_action}
18-
| {:error, :not_fully_implemented}
19-
| {:error, :unexpected_payload}
16+
@type outcome :: Sync.outcome | {:ok, :ignored} | {:error, :unexpected_payload}
2017

2118
@doc ~S"""
2219
Handles the "Issues" GitHub webhook
@@ -29,8 +26,7 @@ defmodule CodeCorps.GitHub.Event.Issues do
2926
"""
3027
@spec handle(map) :: outcome
3128
def handle(payload) do
32-
with {:ok, :valid} <- validate_payload(payload),
33-
{:ok, :implemented} <- validate_action(payload) do
29+
with {:ok, :valid} <- validate_payload(payload) do
3430
Sync.issue_event(payload)
3531
else
3632
{:error, error} -> {:error, error}
@@ -45,14 +41,4 @@ defmodule CodeCorps.GitHub.Event.Issues do
4541
false -> {:error, :unexpected_payload}
4642
end
4743
end
48-
49-
@implemented_actions ~w(opened closed edited reopened)
50-
@unimplemented_actions ~w(assigned unassigned milestoned demilestoned labeled unlabeled)
51-
52-
@spec validate_action(map) :: {:ok, :implemented}
53-
| {:error, :not_fully_implemented }
54-
| {:error, :unexpected_action}
55-
defp validate_action(%{"action" => action}) when action in @implemented_actions, do: {:ok, :implemented}
56-
defp validate_action(%{"action" => action}) when action in @unimplemented_actions, do: {:error, :not_fully_implemented}
57-
defp validate_action(_payload), do: {:error, :unexpected_action}
5844
end

lib/code_corps/github/event/pull_request/pull_request.ex

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@ defmodule CodeCorps.GitHub.Event.PullRequest do
1313
}
1414
alias GitHub.Sync
1515

16-
@type outcome :: Sync.outcome
17-
| {:error, :unexpected_action}
18-
| {:error, :not_fully_implemented}
19-
| {:error, :unexpected_payload}
16+
@type outcome :: Sync.outcome | {:error, :unexpected_payload}
2017

2118
@doc ~S"""
2219
Handles the "PullRequest" GitHub webhook
@@ -29,8 +26,7 @@ defmodule CodeCorps.GitHub.Event.PullRequest do
2926
"""
3027
@spec handle(map) :: outcome
3128
def handle(payload) do
32-
with {:ok, :valid} <- validate_payload(payload),
33-
{:ok, :implemented} <- validate_action(payload) do
29+
with {:ok, :valid} <- validate_payload(payload) do
3430
Sync.pull_request_event(payload)
3531
else
3632
{:error, error} -> {:error, error}
@@ -45,14 +41,4 @@ defmodule CodeCorps.GitHub.Event.PullRequest do
4541
false -> {:error, :unexpected_payload}
4642
end
4743
end
48-
49-
@implemented_actions ~w(opened closed edited reopened)
50-
@unimplemented_actions ~w(assigned unassigned review_requested review_request_removed labeled unlabeled)
51-
52-
@spec validate_action(map) :: {:ok, :implemented}
53-
| {:error, :not_fully_implemented }
54-
| {:error, :unexpected_action}
55-
defp validate_action(%{"action" => action}) when action in @implemented_actions, do: {:ok, :implemented}
56-
defp validate_action(%{"action" => action}) when action in @unimplemented_actions, do: {:error, :not_fully_implemented}
57-
defp validate_action(_payload), do: {:error, :unexpected_action}
5844
end

lib/code_corps/github/webhook/event_support.ex

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,66 @@ defmodule CodeCorps.GitHub.Webhook.EventSupport do
33
Determines event support for a GitHub event type
44
"""
55

6-
@supported_events ~w(
7-
installation installation_repositories issue_comment issues pull_request
8-
)
6+
@type support_status :: :supported | :unsupported | :ignored
97

10-
@type support_status :: :supported | :unsupported
8+
@supported_events [
9+
{"installation", "created"},
10+
{"installation_repositories", "added"},
11+
{"installation_repositories", "removed"},
12+
{"issue_comment", "created"},
13+
{"issue_comment", "edited"},
14+
{"issue_comment", "deleted"},
15+
{"issues", "opened"},
16+
{"issues", "edited"},
17+
{"issues", "closed"},
18+
{"issues", "reopened"},
19+
{"pull_request", "opened"},
20+
{"pull_request", "edited"},
21+
{"pull_request", "closed"},
22+
{"pull_request", "reopened"},
23+
]
1124

12-
@doc """
13-
Returns :supported if the GitHub event type is in the list of events we
14-
support, :unsupported otherwise.
15-
"""
16-
@spec status(any) :: support_status
17-
def status(event_type) when event_type in @supported_events, do: :supported
18-
def status(_), do: :unsupported
25+
@doc ~S"""
26+
Utility function. Returns list of supported events as `{type, action}` tuples.
1927
20-
@doc """
21-
Convenience function. Makes the internal list of supported events public.
28+
Supported events are events of types and actions we currently fully support.
2229
"""
23-
@spec supported_events :: list
30+
@spec supported_events :: list(tuple)
2431
def supported_events, do: @supported_events
32+
33+
@unsupported_events [
34+
{"installation", "deleted"},
35+
{"issues", "assigned"},
36+
{"issues", "unassigned"},
37+
{"issues", "labeled"},
38+
{"issues", "unlabeled"},
39+
{"issues", "milestoned"},
40+
{"issues", "demilestoned"},
41+
{"pull_request", "assigned"},
42+
{"pull_request", "unassigned"},
43+
{"pull_request", "review_requested"},
44+
{"pull_request", "review_request_removed"},
45+
{"pull_request", "labeled"},
46+
{"pull_request", "unlabeled"},
47+
{"pull_request", "synchronize"},
48+
]
49+
50+
@doc ~S"""
51+
Utility function. Returns list of unsupported events as `{type, action}`
52+
tuples.
53+
54+
Unsupported events are events of types we technically support, but actions we
55+
do not yet implement the handling of.
56+
"""
57+
@spec unsupported_events :: list(tuple)
58+
def unsupported_events, do: @unsupported_events
59+
60+
@doc ~S"""
61+
Returns `:handled` if the GitHub event/action is being handled by the system,
62+
`:ignored` otherwise.
63+
"""
64+
@spec status(String.t, String.t) :: support_status
65+
def status(type, action) when {type, action} in @supported_events, do: :supported
66+
def status(type, action) when {type, action} in @unsupported_events, do: :unsupported
67+
def status(_type, _action), do: :ignored
2568
end

lib/code_corps/github/webhook/handler.ex

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,46 +11,59 @@ defmodule CodeCorps.GitHub.Webhook.Handler do
1111
GitHub.Event.IssueComment,
1212
GitHub.Event.Issues,
1313
GitHub.Event.PullRequest,
14-
GitHub.Webhook.EventSupport,
1514
Repo
1615
}
1716

1817
@doc """
19-
Handles a GitHub event based on its type.
18+
Handles a fully supported GitHub event based on its type and action.
19+
20+
The handling process consistes of 3 steps
21+
22+
- create event record marked as "unprocessed"
23+
- mark event record as processing and handle it
24+
- mark event record as processed or errored depending on handling outcome
2025
"""
21-
def handle(type, id, payload) do
22-
with %{} = params <- build_params(type, id, payload),
23-
{:ok, %GithubEvent{} = event} <- params |> create_event(),
24-
{:ok, %GithubEvent{status: "processing"} = event} <- event |> Event.start_processing
25-
do
26-
payload |> do_handle(type) |> Event.stop_processing(event)
26+
@spec handle_supported(String.t, String.t, map) :: {:ok, GithubEvent.t}
27+
def handle_supported(type, id, %{} = payload) do
28+
with {:ok, %GithubEvent{} = event} <- type |> build_params(id, "unprocessed", payload) |> create_event() do
29+
payload |> apply_handler(type) |> Event.stop_processing(event)
2730
end
2831
end
2932

30-
defp build_params(type, id, %{"action" => action, "sender" => _} = payload) do
33+
@doc ~S"""
34+
Handles an unsupported supported GitHub event.
35+
36+
"unsupported" means that, while we generally support this event type,
37+
we do not yet support this specific event action.
38+
39+
The process consistes of simply storing the event and marking it as
40+
"unsupported".
41+
"""
42+
@spec handle_unsupported(String.t, String.t, map) :: {:ok, GithubEvent.t}
43+
def handle_unsupported(type, id, %{} = payload) do
44+
type |> build_params(id, "unsupported", payload) |> create_event()
45+
end
46+
47+
@spec build_params(String.t, String.t, String.t, map) :: map
48+
defp build_params(type, id, status, %{"action" => action} = payload) do
3149
%{
3250
action: action,
3351
github_delivery_id: id,
3452
payload: payload,
35-
status: type |> get_status(),
53+
status: status,
3654
type: type
3755
}
3856
end
3957

40-
defp create_event(params) do
41-
%GithubEvent{} |> GithubEvent.changeset(params) |> Repo.insert
42-
end
43-
44-
defp get_status(type) do
45-
case EventSupport.status(type) do
46-
:unsupported -> "unhandled"
47-
:supported -> "unprocessed"
48-
end
58+
@spec create_event(map) :: {:ok, GithubEvent.t}
59+
defp create_event(%{} = params) do
60+
%GithubEvent{} |> GithubEvent.changeset(params) |> Repo.insert()
4961
end
5062

51-
defp do_handle(payload, "installation"), do: Installation.handle(payload)
52-
defp do_handle(payload, "installation_repositories"), do: InstallationRepositories.handle(payload)
53-
defp do_handle(payload, "issue_comment"), do: IssueComment.handle(payload)
54-
defp do_handle(payload, "issues"), do: Issues.handle(payload)
55-
defp do_handle(payload, "pull_request"), do: PullRequest.handle(payload)
63+
@spec apply_handler(map, String.t) :: tuple
64+
defp apply_handler(payload, "installation"), do: Installation.handle(payload)
65+
defp apply_handler(payload, "installation_repositories"), do: InstallationRepositories.handle(payload)
66+
defp apply_handler(payload, "issue_comment"), do: IssueComment.handle(payload)
67+
defp apply_handler(payload, "issues"), do: Issues.handle(payload)
68+
defp apply_handler(payload, "pull_request"), do: PullRequest.handle(payload)
5669
end

lib/code_corps/github/webhook/processor.ex

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)