Add Processing + registration functionality

* Also updated/added comments
This commit is contained in:
joeybloggs
2015-10-29 16:53:20 -04:00
parent 28bd4943bc
commit c6507a6c00
4 changed files with 223 additions and 60 deletions
+95 -15
View File
@@ -1,15 +1,26 @@
package github
import "github.com/joeybloggs/webhooks"
import (
"crypto/hmac"
"crypto/sha1"
"encoding/hex"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/joeybloggs/webhooks"
)
// Webhook instance contains all methods needed to process events
type Webhook struct {
provider webhooks.Provider
provider webhooks.Provider
secret string
eventFuncs map[Event]webhooks.ProcessPayloadFunc
}
// Config defines the configuration to create a new GitHubWebhook instance
type Config struct {
Provider webhooks.Provider
Secret string
}
// Event defines a GitHub hook event type
@@ -17,7 +28,6 @@ type Event string
// GitHub hook types
const (
// AnyEvent Event = "*"
CommitCommentEvent Event = "commit_comment"
CreateEvent Event = "create"
DeleteEvent Event = "delete"
@@ -53,19 +63,89 @@ const (
IssueSubtype EventSubtype = "issues"
)
// Provider returns the Webhook's provider
func (w Webhook) Provider() webhooks.Provider {
return w.provider
}
// UnderlyingProvider returns the Config's Provider
func (c Config) UnderlyingProvider() webhooks.Provider {
return c.Provider
}
// New creates and returns a WebHook instance denoted by the Provider type
func New(config *Config) *Webhook {
return &Webhook{
provider: config.Provider,
provider: webhooks.GitHub,
secret: config.Secret,
eventFuncs: map[Event]webhooks.ProcessPayloadFunc{},
}
}
// Provider returns the current hooks provider ID
func (hook Webhook) Provider() webhooks.Provider {
return hook.provider
}
// RegisterEvents registers the function to call when the specified event(s) are encountered
func (hook Webhook) RegisterEvents(fn webhooks.ProcessPayloadFunc, events ...Event) {
for _, event := range events {
hook.eventFuncs[event] = fn
}
}
// ParsePayload parses and verifies the payload and fires off the mapped function, if it exists.
func (hook Webhook) ParsePayload(w http.ResponseWriter, r *http.Request) {
event := r.Header.Get("X-GitHub-Event")
if len(event) == 0 {
http.Error(w, "400 Bad Request - Missing X-GitHub-Event Header", http.StatusBadRequest)
return
}
gitHubEvent := Event(event)
fn, ok := hook.eventFuncs[gitHubEvent]
// if no event registered
if !ok {
return
}
payload, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// If we have a Secret set, we should check the MAC
if len(hook.secret) > 0 {
signature := r.Header.Get("X-Hub-Signature")
if len(signature) == 0 {
http.Error(w, "403 Forbidden - Missing X-Hub-Signature required for HMAC verification", http.StatusForbidden)
return
}
mac := hmac.New(sha1.New, []byte(hook.secret))
_, err := mac.Write(payload)
if err != nil {
http.Error(w, "400 Bad Request - HMAC verification failed with body parsing", http.StatusBadRequest)
return
}
expectedMAC := hex.EncodeToString(mac.Sum(nil))
if !hmac.Equal([]byte(signature[5:]), []byte(expectedMAC)) {
http.Error(w, "403 Forbidden - HMAC verification failed", http.StatusForbidden)
return
}
}
var results interface{}
switch gitHubEvent {
case ReleaseEvent:
var release ReleasePayload
json.Unmarshal([]byte(payload), &release)
results = release
}
go func(fn webhooks.ProcessPayloadFunc, results interface{}) {
// put in recovery here!
fn(results)
}(fn, results)
}
+1 -1
View File
@@ -177,7 +177,7 @@ func TestCommitCommentHook(t *testing.T) {
json.Unmarshal([]byte(body), &cc)
Equal(t, cc.Comment.Line, nil)
Equal(t, cc.Comment.Line, 0)
}
func TestCreateHook(t *testing.T) {
+29 -29
View File
@@ -22,9 +22,9 @@ type StatusPayload struct {
ID int `json:"id"`
SHA string `json:"sha"`
Name string `json:"name"`
TragetURL *string `json:"target_url"`
TragetURL string `json:"target_url"`
Context string `json:"context"`
Desctiption *string `json:"description"`
Desctiption string `json:"description"`
State string `json:"state"`
Commit StatusCommit `json:"commit"`
Branches []Branch `json:"branches"`
@@ -58,7 +58,7 @@ type PushPayload struct {
Created bool `json:"created"`
Deleted bool `json:"deleted"`
Forced bool `json:"forced"`
BaseRef *string `json:"base_ref"`
BaseRef string `json:"base_ref"`
Compare string `json:"compare"`
Commits []Commit `json:"commits"`
HeadCommit HeadCommit `json:"head_commit"`
@@ -159,7 +159,7 @@ type DeploymentPayload struct {
Sender Sender `json:"sender"`
}
// CommitComment contains the information for GitHub's commit_comment hook event
// CommitCommentPayload contains the information for GitHub's commit_comment hook event
type CommitCommentPayload struct {
Action string `json:"action"`
RefType string `json:"ref_type"`
@@ -245,7 +245,7 @@ type Repository struct {
Size int `json:"size"`
StargazersCount int `json:"stargazers_count"`
WatchersCount int `json:"watchers_count"`
Language *string `json:"language"`
Language string `json:"language"`
HasIssues bool `json:"has_issues"`
HasDownloads bool `json:"has_downloads"`
HasWiki bool `json:"has_wiki"`
@@ -326,9 +326,9 @@ type Comment struct {
HTMLURL string `json:"html_url"`
ID int `json:"id"`
User User `json:"user"`
Position *int `json:"position"`
Line *int `json:"line"`
Path *string `json:"path"`
Position int `json:"position"`
Line int `json:"line"`
Path string `json:"path"`
CommitID string `json:"commit_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
@@ -344,7 +344,7 @@ type Deployment struct {
Task string `json:"task"`
//paylod
Environment string `json:"environment"`
Description *string `json:"description"`
Description string `json:"description"`
Creator Creator `json:"creator"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
@@ -358,7 +358,7 @@ type DeploymentStatus struct {
ID int `json:"id"`
State string `json:"state"`
Creator Creator `json:"creator"`
Description *string `json:"description"`
Description string `json:"description"`
TargetURL string `json:"target_url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
@@ -374,22 +374,22 @@ type Forkee struct {
// Page contains GitHub's page information
type Page struct {
PageName string `json:"page_name"`
Title string `json:"title"`
Summary *string `json:"summary"`
Action string `json:"action"`
SHA string `json:"sha"`
HTMLURL string `json:"html_url"`
PageName string `json:"page_name"`
Title string `json:"title"`
Summary string `json:"summary"`
Action string `json:"action"`
SHA string `json:"sha"`
HTMLURL string `json:"html_url"`
}
// Page contains GitHub's label information
// Label contains GitHub's label information
type Label struct {
URL string `json:"url"`
Name string `json:"name"`
Color string `json:"color"`
}
// Page contains GitHub's issue information
// Issue contains GitHub's issue information
type Issue struct {
URL string `json:"url"`
LabelsURL string `json:"labels_url"`
@@ -403,8 +403,8 @@ type Issue struct {
Labels []Label `json:"labels"`
State string `json:"state"`
Locked bool `json:"locked"`
Assignee *string `json:"assignee"`
Milestone *string `json:"milestone"`
Assignee string `json:"assignee"`
Milestone string `json:"milestone"`
Comments int `json:"comments"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
@@ -567,9 +567,9 @@ type PullRequest struct {
UpdatedAt time.Time `json:"updated_at"`
ClosedAt time.Time `json:"closed_at"`
MergedAt time.Time `json:"merged_at"`
MergeCommitSHA *string `json:"merge_commit_sha"`
Assignee *string `json:"assignee"`
Milestone *string `json:"milestone"`
MergeCommitSHA string `json:"merge_commit_sha"`
Assignee string `json:"assignee"`
Milestone string `json:"milestone"`
CommitsURL string `json:"commits_url"`
ReviewCommentsURL string `json:"review_comments_url"`
ReviewCommentURL string `json:"review_comment_url"`
@@ -579,9 +579,9 @@ type PullRequest struct {
Base Base `json:"base"`
Links LinksPullRequest `json:"_links"`
Merged bool `json:"merged"`
Mergable *bool `json:"mergeable"`
Mergable bool `json:"mergeable"`
MergableState string `json:"mergeable_state"`
MergedBy *string `json:"merged_by"`
MergedBy string `json:"merged_by"`
Comments int `json:"comments"`
ReviewComments int `json:"review_comments"`
Commits int `json:"commits"`
@@ -633,10 +633,10 @@ type Release struct {
AssetsURL string `json:"assets_url"`
UploadURL string `json:"upload_url"`
HTMLURL string `json:"html_url"`
ID string `json:"id"`
ID int `json:"id"`
TagName string `json:"tag_name"`
TargetCommitish string `json:"target_commitish"`
Name *string `json:"name"`
Name string `json:"name"`
Draft bool `json:"draft"`
Author Author `json:"author"`
Prelelease bool `json:"prerelease"`
@@ -645,7 +645,7 @@ type Release struct {
Assets []string `json:"assets"`
TarballURL string `json:"tarball_url"`
ZipballURL string `json:"zipball_url"`
Body *string `json:"body"`
Body string `json:"body"`
}
// BranchCommit contains GitHub's branch commit information
@@ -695,7 +695,7 @@ type StatusCommit struct {
Commit StatusCommitInner `json:"commit"`
URL string `json:"url"`
HTMLURL string `json:"html_url"`
CommentsURL string `json:"comments_url`
CommentsURL string `json:"comments_url"`
Author Author `json:"author"`
Committer Commiter `json:"committer"`
Parents []string `json:"parents"`