diff --git a/plugin/notify/github/github.go b/plugin/notify/github/github.go new file mode 100644 index 000000000..38c6f3028 --- /dev/null +++ b/plugin/notify/github/github.go @@ -0,0 +1,149 @@ +package github + +import ( + "fmt" + "net/url" + "os" + "strings" + + "code.google.com/p/goauth2/oauth" + "github.com/drone/drone/shared/model" + "github.com/google/go-github/github" +) + +// GitHub enterprise URL +var URL = os.Getenv("GITHUB_ENTERPRISE_API") + +const ( + NotifyDisabled = "disabled" + NotifyFalse = "false" + NotifyOff = "off" +) + +const ( + StatusPending = "peding" + StatusSuccess = "success" + StatusFailure = "failure" + StatusError = "error" +) + +const ( + DescPending = "this build is pending" + DescSuccess = "the build was succcessful" + DescFailure = "the build failed" + DescError = "oops, something went wrong" +) + +type GitHub string + +// Send uses the github status API to update the build +// status in github or github enterprise. +func (g GitHub) Send(context *model.Request) error { + + // a user can toggle the status api on / off + // in the .drone.yml + switch g { + case NotifyDisabled, NotifyOff, NotifyFalse: + return nil + } + + // this should only be executed for GitHub and + // GitHub enterprise requests. + switch context.Repo.Remote { + case model.RemoteGithub, model.RemoteGithubEnterprise: + break + default: + return nil + } + + var target = getTarget( + context.Host, + context.Repo.Host, + context.Repo.Owner, + context.Repo.Name, + context.Commit.Branch, + context.Commit.Sha, + ) + + return send( + context.Repo.Host, + context.Repo.Owner, + context.Repo.Name, + context.Commit.Sha, + target, + getDesc(context.Commit.Status), + getStatus(context.Commit.Status), + context.User.Token, + ) +} + +func send(host, owner, repo, ref, status, target, desc, token string) error { + transport := &oauth.Transport{ + Token: &oauth.Token{AccessToken: token}, + } + + data := github.RepoStatus{ + Context: github.String("Drone"), + State: github.String(status), + Description: github.String(desc), + TargetURL: github.String(target), + } + + client := github.NewClient(transport.Client()) + + // if this is for github enterprise we need to set + // the base url. Per the documentation, we need to + // ensure there is a trailing slash. + if host != model.RemoteGithub { + client.BaseURL, _ = url.Parse(URL) + if !strings.HasSuffix(client.BaseURL.Path, "/") { + client.BaseURL.Path = client.BaseURL.Path + "/" + } + } + + _, _, err := client.Repositories.CreateStatus(owner, repo, ref, &data) + return err +} + +// getStatus is a helper functin that converts a Drone +// status to a GitHub status. +func getStatus(status string) string { + switch status { + case model.StatusEnqueue, model.StatusStarted: + return StatusPending + case model.StatusSuccess: + return StatusSuccess + case model.StatusFailure: + return StatusFailure + case model.StatusError, model.StatusKilled: + return StatusError + default: + return StatusError + } +} + +// getDesc is a helper function that generates a description +// message for the build based on the status. +func getDesc(status string) string { + switch status { + case model.StatusEnqueue, model.StatusStarted: + return DescPending + case model.StatusSuccess: + return DescSuccess + case model.StatusFailure: + return DescFailure + case model.StatusError, model.StatusKilled: + return DescError + default: + return DescError + } +} + +// getTarget is a helper function that generates a URL +// for the user to click and jump to the build results. +// +// for example: +// https://drone.io/github.com/drone/drone-test-go/master/c22aec9c53 +func getTarget(url, host, owner, repo, branch, commit string) string { + return fmt.Sprintf("%s/%s/%s/%s/%s/%s", url, host, owner, repo, branch, commit) +} diff --git a/plugin/notify/notification.go b/plugin/notify/notification.go index b7609540c..f9b8c9eed 100644 --- a/plugin/notify/notification.go +++ b/plugin/notify/notification.go @@ -4,6 +4,7 @@ import ( "log" "github.com/drone/drone/plugin/notify/email" + "github.com/drone/drone/plugin/notify/github" "github.com/drone/drone/shared/model" ) @@ -20,6 +21,8 @@ type Notification struct { Hipchat *Hipchat `yaml:"hipchat,omitempty"` Irc *IRC `yaml:"irc,omitempty"` Slack *Slack `yaml:"slack,omitempty"` + + GitHub github.GitHub `yaml:"github_status"` } func (n *Notification) Send(context *model.Request) error { @@ -63,5 +66,10 @@ func (n *Notification) Send(context *model.Request) error { } } + // send email notifications + if err := n.GitHub.Send(context); err != nil { + log.Println(err) + } + return nil }