-
-
Notifications
You must be signed in to change notification settings - Fork 397
/
github_webhook.go
115 lines (105 loc) 路 3.2 KB
/
github_webhook.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/google/go-github/v28/github"
"github.com/reviewdog/reviewdog/doghouse/server/storage"
)
type githubWebhookHandler struct {
secret []byte
ghInstStore storage.GitHubInstallationStore
}
func (g *githubWebhookHandler) handleWebhook(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
ctx := r.Context()
payload, err := g.validatePayload(r)
if err != nil {
w.WriteHeader(http.StatusUnauthorized)
return
}
var handleFunc func(ctx context.Context, payload []byte) (status int, err error)
switch github.WebHookType(r) {
case "installation":
handleFunc = g.handleInstallationEvent
case "check_suite":
handleFunc = g.handleCheckSuiteEvent
}
if handleFunc != nil {
status, err := handleFunc(ctx, payload)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "failed to handle %s event: %v", github.WebHookType(r), err)
return
}
w.WriteHeader(status)
fmt.Fprintf(w, "resource created. event: %s", github.WebHookType(r))
return
}
w.WriteHeader(http.StatusAccepted)
}
func (g *githubWebhookHandler) validatePayload(r *http.Request) (payload []byte, err error) {
return github.ValidatePayload(r, g.secret)
}
func (g *githubWebhookHandler) handleCheckSuiteEvent(ctx context.Context, payload []byte) (status int, err error) {
var c CheckSuiteEvent
if err := json.Unmarshal(payload, &c); err != nil {
return 0, err
}
switch c.Action {
case "requested":
// Update InstallationID on check_suite event in case the users re-install
// the app.
return http.StatusCreated, g.ghInstStore.Put(ctx, &storage.GitHubInstallation{
InstallationID: c.Installation.ID,
AccountName: c.Repository.Owner.Login,
AccountID: c.Repository.Owner.ID,
})
}
return http.StatusAccepted, nil
}
func (g *githubWebhookHandler) handleInstallationEvent(ctx context.Context, payload []byte) (status int, err error) {
var e InstallationEvent
if err := json.Unmarshal(payload, &e); err != nil {
return 0, err
}
switch e.Action {
case "created":
return http.StatusCreated, g.ghInstStore.Put(ctx, &storage.GitHubInstallation{
InstallationID: e.Installation.ID,
AccountName: e.Installation.Account.Login,
AccountID: e.Installation.Account.ID,
})
}
return http.StatusAccepted, nil
}
// Example: https://gist.github.com/haya14busa/7a9a87da5159d6853fed865ca5ad5ec7
type InstallationEvent struct {
Action string `json:"action,omitempty"`
Installation struct {
ID int64 `json:"id,omitempty"`
Account struct {
Login string `json:"login"`
ID int64 `json:"id"`
} `json:"account"`
} `json:"installation,omitempty"`
}
// Example: https://gist.github.com/haya14busa/2aaffaa89a224ee2ffcbd3d414d6d009
type CheckSuiteEvent struct {
Action string `json:"action,omitempty"`
Repository struct {
ID int64 `json:"id,omitempty"`
FullName string `json:"full_name,omitempty"`
Owner struct {
Login string `json:"login"`
ID int64 `json:"id"`
} `json:"owner"`
} `json:"repository,omitempty"`
Installation struct {
ID int64 `json:"id,omitempty"`
} `json:"installation,omitempty"`
}