-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathhandlers.go
148 lines (137 loc) · 4.48 KB
/
handlers.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
"path/filepath"
"strings"
"github.com/concourse/concourse/atc"
)
type GithubWebhookHandler struct {
queue *RequestWorkqueue
}
func (gh *GithubWebhookHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
var pushEvent struct {
Ref string `json:"ref"`
Before string `json:"before"`
After string `json:"after"`
CompareURL string `json:"compare"`
Repository struct {
FullName string `json:"full_name"`
CloneURL string `json:"clone_url"`
GitURL string `json:"git_url"`
DefaultBranch string `json:"default_branch"`
} `json:"repository"`
Commits []struct {
ID string `json:"id"`
Message string `json:"message"`
AddedFiles []string `json:"added"`
RemovedFiles []string `json:"removed"`
ModifiedFiles []string `json:"modified"`
} `json:"commits"`
}
if req.Body == nil {
rw.WriteHeader(400)
log.Printf("Empty body")
return
}
err := json.NewDecoder(req.Body).Decode(&pushEvent)
if err != nil {
rw.WriteHeader(400)
log.Printf("Failed to parse request body: %s", err)
return
}
if pushEvent.After == "0000000000000000000000000000000000000000" {
log.Printf("Skipping deletion event for ref %s in %s", pushEvent.Ref, pushEvent.Repository.CloneURL)
return
}
log.Printf("Received webhhook for %s, ref %s, %s", pushEvent.Repository.CloneURL, pushEvent.Ref, pushEvent.CompareURL)
//collect list of changed files
filesChanged := []string{}
for _, commit := range pushEvent.Commits {
filesChanged = append(filesChanged, commit.AddedFiles...)
filesChanged = append(filesChanged, commit.RemovedFiles...)
filesChanged = append(filesChanged, commit.ModifiedFiles...)
}
ScanResourceCache(func(pipeline Pipeline, resource atc.ResourceConfig) bool {
if resource.Type != "git" && resource.Type != "pull-request" && resource.Type != "git-proxy" {
return true
}
if uri, ok := resource.Source["uri"].(string); ok {
if SameGitRepository(uri, pushEvent.Repository.CloneURL) {
if resource.Type == "git" || resource.Type == "git-proxy" {
//skip, if push is for branch not tracked by resource
branch, _ := resource.Source["branch"].(string)
if branch == "" {
branch = pushEvent.Repository.DefaultBranch
}
if strings.TrimPrefix(pushEvent.Ref, "refs/heads/") != branch {
log.Printf("Skipping resource %s/%s in team %s. Which is tracking branch %s", pipeline.Name, resource.Name, pipeline.Team, branch)
return true
}
}
//skip if path filter of resource does not match any of the changed files
if ps, ok := resource.Source["paths"].([]interface{}); ok && len(ps) > 0 {
paths := make([]string, 0, len(ps))
for _, p := range ps {
if pstring, ok := p.(string); ok {
paths = append(paths, pstring)
}
}
if len(paths) > 0 && !matchFiles(paths, filesChanged) {
log.Printf("Skipping resource %s/%s in team %s, due to path filter", pipeline.Name, resource.Name, pipeline.Team)
return true
}
debugf("resource %s/%s has matching path filter: %#v", pipeline.Name, resource.Name, resource.Source)
} else {
debugf("resource %s/%s has no path filter: %#v", pipeline.Name, resource.Name, resource.Source)
}
queryParams := url.Values{}
for key, vals := range pipeline.QueryParams {
for _, val := range vals {
queryParams.Add(key, val)
}
}
queryParams.Set("webhook_token", resource.WebhookToken)
webhookURL := fmt.Sprintf("%s/api/v1/teams/%s/pipelines/%s/resources/%s/check/webhook?%s",
concourseURL,
pipeline.Team,
pipeline.Name,
resource.Name,
queryParams.Encode(),
)
gh.queue.Add(webhookURL)
}
}
return true
})
}
func matchFiles(patterns []string, files []string) bool {
for _, file := range files {
for _, pattern := range patterns {
// direct match
if file == pattern {
debugf("direct match: %v == %v", file, pattern)
return true
}
// directory match
if strings.HasSuffix(pattern, "/") && strings.HasPrefix(file, pattern) {
debugf("directory match: %s matches %s", file, pattern)
return true
}
// directory without trainling / match
if strings.HasPrefix(file, pattern+"/") {
debugf("prefix match: %s matches %s", file, pattern)
return true
}
//last resort glob match
if ok, _ := filepath.Match(pattern, file); ok {
debugf("glob match: %s matches %s", file, pattern)
return true
}
}
}
return false
}