Skip to content

Commit 4424806

Browse files
author
zoidbergwill
committed
WIP: Move to golang-http-template
Closes alexellis#96 Might also close alexellis#123 Signed-off-by: zoidbergwill <zoidbergwill@users.noreply.github.com>
1 parent ede7834 commit 4424806

File tree

2 files changed

+290
-21
lines changed

2 files changed

+290
-21
lines changed

derek.yml

+8-21
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1+
version: 1.0
12
provider:
23
name: openfaas
34
gateway: http://127.0.0.1:8080
4-
55
functions:
6-
derek-0913:
7-
handler: ./
8-
image: alexellis/derek:0.9.13
9-
lang: dockerfile
10-
environment:
11-
debug: true
12-
customers_url: https://raw.githubusercontent.com/alexellis/derek/master/.CUSTOMERS
13-
validate_hmac: true
14-
validate_customers: false
15-
secret_path: /var/openfaas/secrets/ # use /run/secrets/ for older OpenFaaS versions
16-
write_debug: true
17-
read_timeout: 10s
18-
write_timeout: 10s
19-
combine_output: false
20-
environment_file:
21-
- secrets.yml
22-
# See secrets.example.yml
23-
secrets:
24-
- derek-secret-key
25-
- derek-private-key
6+
# TODO: Double check port stuff
7+
# TODO: bring back environment config
8+
# TODO: bring back secrets
9+
derek:
10+
lang: golang-http
11+
handler: ./http-handler
12+
image: derek-2:latest
2613

http-handler/handler.go

+282
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
package function
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io/ioutil"
7+
"log"
8+
"net/http"
9+
"os"
10+
11+
"github.com/google/go-github/github"
12+
13+
"github.com/alexellis/derek/auth"
14+
"github.com/alexellis/derek/config"
15+
16+
"github.com/alexellis/derek/handler"
17+
18+
"github.com/alexellis/derek/types"
19+
"github.com/alexellis/hmac"
20+
21+
handler "github.com/openfaas/templates-sdk/go-http"
22+
)
23+
24+
// Example handle
25+
// Handle a function invocation
26+
// func Handle(req handler.Request) (handler.Response, error) {
27+
// var err error
28+
29+
// message := fmt.Sprintf("Body: %s", string(req.Body))
30+
31+
// return handler.Response{
32+
// Body: []byte(message),
33+
// StatusCode: http.StatusOK,
34+
// }, err
35+
// }
36+
37+
const (
38+
dcoCheck = "dco_check"
39+
comments = "comments"
40+
deleted = "deleted"
41+
prDescriptionRequired = "pr_description_required"
42+
hacktoberfest = "hacktoberfest"
43+
noNewbies = "no_newbies"
44+
releaseNotes = "release_notes"
45+
)
46+
47+
func Handle(req handler.Request) (handler.Response, error) {
48+
validateHmac := hmacValidation()
49+
50+
requestRaw, _ := ioutil.ReadAll(req.Body)
51+
52+
xHubSignature := r.Header.Get("X-Hub-Signature")
53+
54+
if validateHmac && len(xHubSignature) == 0 {
55+
return handler.Response{
56+
Body: []byte("must provide X-Hub-Signature"),
57+
StatusCode: http.StatusInternalServerError,
58+
}, nil
59+
}
60+
61+
config, configErr := config.NewConfig()
62+
if configErr != nil {
63+
return handler.Response{
64+
Body: []byte(configErr.Error()),
65+
StatusCode: http.StatusInternalServerError,
66+
}, configErr
67+
}
68+
69+
if validateHmac {
70+
err := hmac.Validate(requestRaw, xHubSignature, config.SecretKey)
71+
if err != nil {
72+
return handler.Response{
73+
Body: []byte(err.Error()),
74+
StatusCode: http.StatusInternalServerError,
75+
}, err
76+
}
77+
}
78+
79+
eventType := req.Header.Get("X-Github-Event")
80+
81+
if err := handleEvent(eventType, requestRaw, config); err != nil {
82+
return handler.Response{
83+
Body: []byte(err.Error()),
84+
StatusCode: http.StatusInternalServerError,
85+
}, err
86+
}
87+
}
88+
89+
func handleEvent(eventType string, bytesIn []byte, config config.Config) error {
90+
91+
switch eventType {
92+
case "pull_request":
93+
req := types.PullRequestOuter{}
94+
if err := json.Unmarshal(bytesIn, &req); err != nil {
95+
return fmt.Errorf("Cannot parse input %s", err.Error())
96+
}
97+
98+
customer, err := auth.IsCustomer(req.Repository.Owner.Login, &http.Client{})
99+
if err != nil {
100+
return fmt.Errorf("Unable to verify customer: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
101+
} else if !customer {
102+
return fmt.Errorf("No customer found for: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
103+
}
104+
105+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repository.Owner.Login, req.Repository.Name, "pull_request")
106+
107+
var derekConfig *types.DerekRepoConfig
108+
if req.Repository.Private {
109+
derekConfig, err = handler.GetPrivateRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch, req.Installation.ID, config)
110+
} else {
111+
derekConfig, err = handler.GetRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch)
112+
}
113+
114+
if err != nil {
115+
return fmt.Errorf("Unable to access maintainers file at: %s/%s\nError: %s",
116+
req.Repository.Owner.Login,
117+
req.Repository.Name,
118+
err.Error())
119+
}
120+
121+
if req.Action != handler.ClosedConstant && req.PullRequest.State != handler.ClosedConstant {
122+
contributingURL := getContributingURL(derekConfig.ContributingURL, req.Repository.Owner.Login, req.Repository.Name)
123+
124+
if handler.EnabledFeature(dcoCheck, derekConfig) {
125+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repository.Owner.Login, req.Repository.Name, "derek:dco_check")
126+
127+
handler.HandlePullRequest(req, contributingURL, config)
128+
}
129+
130+
if handler.EnabledFeature(prDescriptionRequired, derekConfig) {
131+
handler.VerifyPullRequestDescription(req, contributingURL, config)
132+
}
133+
134+
if handler.EnabledFeature(noNewbies, derekConfig) {
135+
isSpamPR, _ := handler.HandleFirstTimerPR(req, contributingURL, config)
136+
if isSpamPR {
137+
return nil
138+
}
139+
}
140+
141+
if handler.EnabledFeature(hacktoberfest, derekConfig) {
142+
isSpamPR, _ := handler.HandleHacktoberfestPR(req, contributingURL, config)
143+
if isSpamPR {
144+
return nil
145+
}
146+
}
147+
}
148+
break
149+
150+
case "issues":
151+
152+
req := types.IssuesOuter{}
153+
if err := json.Unmarshal(bytesIn, &req); err != nil {
154+
return fmt.Errorf("Cannot parse input %s", err.Error())
155+
}
156+
157+
if req.Action == "opened" {
158+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repository.Owner.Login, req.Repository.Name, "issues")
159+
160+
customer, err := auth.IsCustomer(req.Repository.Owner.Login, &http.Client{})
161+
if err != nil {
162+
return fmt.Errorf("Unable to verify customer: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
163+
} else if !customer {
164+
return fmt.Errorf("No customer found for: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
165+
}
166+
167+
var derekConfig *types.DerekRepoConfig
168+
if req.Repository.Private {
169+
derekConfig, err = handler.GetPrivateRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch, req.Installation.ID, config)
170+
} else {
171+
derekConfig, err = handler.GetRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch)
172+
}
173+
if err != nil {
174+
return fmt.Errorf("Unable to access maintainers file at: %s/%s\nError: %s",
175+
req.Repository.Owner.Login,
176+
req.Repository.Name,
177+
err.Error())
178+
}
179+
180+
if len(derekConfig.RequiredInIssues) > 0 {
181+
err := handler.CheckIssueTemplateHeadings(req, derekConfig, config)
182+
if err != nil {
183+
return err
184+
}
185+
}
186+
}
187+
188+
case "issue_comment":
189+
req := types.IssueCommentOuter{}
190+
if err := json.Unmarshal(bytesIn, &req); err != nil {
191+
return fmt.Errorf("Cannot parse input %s", err.Error())
192+
}
193+
194+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repository.Owner.Login, req.Repository.Name, "issue_comment")
195+
196+
customer, err := auth.IsCustomer(req.Repository.Owner.Login, &http.Client{})
197+
if err != nil {
198+
return fmt.Errorf("Unable to verify customer: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
199+
} else if !customer {
200+
return fmt.Errorf("No customer found for: %s/%s", req.Repository.Owner.Login, req.Repository.Name)
201+
}
202+
203+
var derekConfig *types.DerekRepoConfig
204+
if req.Repository.Private {
205+
derekConfig, err = handler.GetPrivateRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch, req.Installation.ID, config)
206+
} else {
207+
derekConfig, err = handler.GetRepoConfig(req.Repository.Owner.Login, req.Repository.Name, req.Repository.DefaultBranch)
208+
}
209+
210+
if err != nil {
211+
return fmt.Errorf("Unable to access maintainers file at: %s/%s\nError: %s",
212+
req.Repository.Owner.Login,
213+
req.Repository.Name,
214+
err.Error())
215+
}
216+
217+
if req.Action != deleted {
218+
if handler.PermittedUserFeature(comments, derekConfig, req.Comment.User.Login) {
219+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repository.Owner.Login, req.Repository.Name, "derek:handle_comment")
220+
221+
handler.HandleComment(req, config, derekConfig)
222+
}
223+
}
224+
225+
case "release":
226+
req := github.ReleaseEvent{}
227+
228+
if err := json.Unmarshal(bytesIn, &req); err != nil {
229+
return fmt.Errorf("Cannot parse input %s", err.Error())
230+
}
231+
232+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repo.Owner.GetLogin(), req.Repo.GetName(), "release")
233+
234+
if req.GetAction() == "created" {
235+
customer, err := auth.IsCustomer(req.Repo.Owner.GetLogin(), &http.Client{})
236+
if err != nil {
237+
return fmt.Errorf("unable to verify customer: %s/%s", req.Repo.Owner.GetLogin(), req.Repo.GetName())
238+
} else if customer == false {
239+
return fmt.Errorf("no customer found for: %s/%s", req.Repo.Owner.GetLogin(), req.Repo.GetName())
240+
}
241+
242+
var derekConfig *types.DerekRepoConfig
243+
if req.Repo.GetPrivate() {
244+
derekConfig, err = handler.GetPrivateRepoConfig(req.Repo.Owner.GetLogin(), req.Repo.GetName(), req.Repo.GetDefaultBranch(), int(req.Installation.GetID()), config)
245+
if err != nil {
246+
return fmt.Errorf("unable to get private repo config: %s", err)
247+
}
248+
} else {
249+
derekConfig, err = handler.GetRepoConfig(req.Repo.Owner.GetLogin(), req.Repo.GetName(), req.Repo.GetDefaultBranch())
250+
if err != nil {
251+
return fmt.Errorf("unable to get repo config: %s", err)
252+
}
253+
}
254+
255+
err = fmt.Errorf(`"release_notes" feature not enabled`)
256+
if handler.EnabledFeature(releaseNotes, derekConfig) {
257+
log.Printf("Owner: %s, repo: %s, action: %s", req.Repo.Owner.GetLogin(), req.Repo.GetName(), "derek:handle_release")
258+
259+
handler := handler.NewReleaseHandler(config, int(req.Installation.GetID()))
260+
err = handler.Handle(req)
261+
}
262+
return err
263+
}
264+
265+
default:
266+
return fmt.Errorf("X_Github_Event want: ['pull_request', 'issue_comment', 'release'], got: " + eventType)
267+
}
268+
269+
return nil
270+
}
271+
272+
func getContributingURL(contributingURL, owner, repositoryName string) string {
273+
if len(contributingURL) == 0 {
274+
contributingURL = fmt.Sprintf("https://github.com/%s/%s/blob/master/CONTRIBUTING.md", owner, repositoryName)
275+
}
276+
return contributingURL
277+
}
278+
279+
func hmacValidation() bool {
280+
val := os.Getenv("validate_hmac")
281+
return (val != "false") && (val != "0")
282+
}

0 commit comments

Comments
 (0)