added email notifications

This commit is contained in:
Brad Rydzewski 2014-08-03 14:45:50 -07:00
parent aec5d06ff1
commit 994b6f0994
7 changed files with 276 additions and 74 deletions

View file

@ -7,4 +7,42 @@
# -port=":8080": # -port=":8080":
# -workers="4": # -workers="4":
# #
#DRONED_OPTS="--port=:80" #DRONED_OPTS="--port=:80"
# Email configuration
#SMTP_HOST=
#SMTP_PORT=
#SMTP_FROM=
#SMTP_USER=
#SMTP_PASS=
# GitHub configuration
#GITHUB_CLIENT=
#GITHUB_SECRET=
# GitHub Enterprise configuration
#GITHUB_ENTERPRISE_CLIENT=
#GITHUB_ENTERPRISE_SECRET=
#GITHUB_ENTERPRISE_URL=
#GITHUB_ENTERPRISE_API=
# GitLab configuration
#GITLAB_URL=
# Atlassian Bitbucket configuration
#BITBUCKET_CLIENT=
#BITBUCKET_SECRET=
# Atlassian Stash configuration
#STASH_CLIENT=
#STASH_SECRET=
#STASH_URL=
#STASH_API=
# Optional global configuration options.
#
# This allows you, for example, to set a default Hipchat token
# so that you don't need to specify in each .drone.yml file.
#HIPCHAT_TOKEN=
#SLACK_TOKEN=
#ZAPIER_TOKEN=

View file

@ -4,9 +4,10 @@ chdir /var/lib/drone
console log console log
script script
DRONED_OPTS="--port=:80" set -a
if [ -f /etc/default/$UPSTART_JOB ]; then DRONED_OPTS="--port=:80"
. /etc/default/$UPSTART_JOB if [ -f /etc/default/$UPSTART_JOB ]; then
fi . /etc/default/$UPSTART_JOB
/usr/local/bin/droned $DRONED_OPTS fi
/usr/local/bin/droned $DRONED_OPTS
end script end script

View file

@ -1,48 +0,0 @@
package notify
import (
"github.com/drone/drone/shared/model"
)
type Email struct {
Recipients []string `yaml:"recipients,omitempty"`
Success string `yaml:"on_success"`
Failure string `yaml:"on_failure"`
}
// Send will send an email, either success or failure,
// based on the Commit Status.
func (e *Email) Send(context *model.Request) error {
switch {
case context.Commit.Status == "Success" && e.Success != "never":
return e.sendSuccess(context)
case context.Commit.Status == "Failure" && e.Failure != "never":
return e.sendFailure(context)
}
return nil
}
// sendFailure sends email notifications to the list of
// recipients indicating the build failed.
func (e *Email) sendFailure(context *model.Request) error {
// loop through and email recipients
//for _, email := range e.Recipients {
//if err := mail.SendFailure(context.Repo.Name, context.Commit.HashShort(), email, context); err != nil {
// return err
//}
//}
return nil
}
// sendSuccess sends email notifications to the list of
// recipients indicating the build was a success.
func (e *Email) sendSuccess(context *model.Request) error {
// loop through and email recipients
//for _, email := range e.Recipients {
// if err := mail.SendSuccess(context.Repo.Name, context.Commit.HashShort(), email, context); err != nil {
// return err
// }
//}
return nil
}

View file

@ -0,0 +1,161 @@
package email
import (
"bytes"
"fmt"
"net"
"net/smtp"
"os"
"strings"
"github.com/drone/drone/shared/model"
)
const (
NotifyAlways = "always" // always send email notification
NotifyNever = "never" // never send email notifications
NotifyAuthor = "author" // only send email notifications to the author
NotifyTrue = "true" // alias for NotifyTrue
NotifyFalse = "false" // alias for NotifyFalse
NotifyOn = "on" // alias for NotifyTrue
NotifyOff = "off" // alias for NotifyFalse
NotifyBlame = "blame" // alias for NotifyAuthor
)
const (
SubjectSuccess = "[SUCCESS] %s/%s %s"
SubjectFailure = "[FAILURE] %s/%s %s"
)
var (
DefaultHost = os.Getenv("SMTP_HOST")
DefaultPort = os.Getenv("SMTP_PORT")
DefaultFrom = os.Getenv("SMTP_FROM")
DefaultUser = os.Getenv("SMTP_USER")
DefaultPass = os.Getenv("SMTP_PASS")
)
type Email struct {
Recipients []string `yaml:"recipients"`
Success string `yaml:"on_success"`
Failure string `yaml:"on_failure"`
Host string `yaml:"host"`
Port string `yaml:"port"`
From string `yaml:"from"`
Username string `yaml:"username"`
Password string `yaml:"password"`
}
// Send will send an email, either success or failure,
// based on the Commit Status.
func (e *Email) Send(context *model.Request) error {
var status = context.Commit.Status
switch status {
// no builds are triggered for pending builds
case model.StatusEnqueue, model.StatusStarted:
return nil
case model.StatusSuccess:
return e.sendSuccess(context)
default:
return e.sendFailure(context)
}
}
// sendFailure sends email notifications to the list of
// recipients indicating the build failed.
func (e *Email) sendFailure(context *model.Request) error {
switch e.Failure {
case NotifyFalse, NotifyNever, NotifyOff:
return nil
// if configured to email the author, replace
// the recipiends with the commit author email.
case NotifyBlame, NotifyAuthor:
e.Recipients = []string{context.Commit.Author}
}
// generate the email failure template
var buf bytes.Buffer
err := failureTemplate.ExecuteTemplate(&buf, "_", context)
if err != nil {
return err
}
// generate the email subject
var subject = fmt.Sprintf(
SubjectFailure,
context.Repo.Owner,
context.Repo.Name,
context.Commit.ShaShort(),
)
return e.send(subject, buf.String(), e.Recipients)
}
// sendSuccess sends email notifications to the list of
// recipients indicating the build was a success.
func (e *Email) sendSuccess(context *model.Request) error {
switch e.Success {
case NotifyFalse, NotifyNever, NotifyOff:
return nil
// if configured to email the author, replace
// the recipiends with the commit author email.
case NotifyBlame, NotifyAuthor:
e.Recipients = []string{context.Commit.Author}
}
// generate the email success template
var buf bytes.Buffer
err := successTemplate.ExecuteTemplate(&buf, "_", context)
if err != nil {
return err
}
// generate the email subject
var subject = fmt.Sprintf(
SubjectSuccess,
context.Repo.Owner,
context.Repo.Name,
context.Commit.ShaShort(),
)
return e.send(subject, buf.String(), e.Recipients)
}
func (e *Email) send(subject, body string, recipients []string) error {
if len(recipients) == 0 {
return nil
}
// the user can provide their own smtp server
// configuration. If None provided, attempt to
// use the global configuration set in the environet
// variables.
if len(DefaultHost) != 0 {
e.Host = DefaultHost
e.Port = DefaultPort
e.From = DefaultFrom
e.Username = DefaultUser
e.Password = DefaultPass
}
var auth smtp.Auth
var addr = net.JoinHostPort(e.Host, e.Port)
// setup the authentication to the smtp server
// if the username and password are provided.
if len(e.Username) > 0 {
auth = smtp.PlainAuth("", e.Username, e.Password, e.Host)
}
// genereate the raw email message
var to = strings.Join(e.Recipients, ",")
var raw = fmt.Sprintf(rawMessage, e.From, to, subject, body)
return smtp.SendMail(addr, auth, e.From, e.Recipients, []byte(raw))
}

View file

@ -0,0 +1,36 @@
package email
import (
"html/template"
)
// raw email message template
var rawMessage = `From: %s
To: %s
Subject: %s
MIME-version: 1.0
Content-Type: text/html; charset="UTF-8"
%s`
// default success email template
var successTemplate = template.Must(template.New("_").Parse(`
<p><b>Build was Successful</b></p>
<p>Repository : {{.Repo.Owner}}/{{.Repo.Name}}</p>
<p>Commit : {{.Commit.ShaShort}}</p>
<p>Author : {{.Commit.Author}}</p>
<p>Branch : {{.Commit.Branch}}</p>
<p>Message:</p>
<p>{{ .Commit.Message }}</p>
`))
// default failure email template
var failureTemplate = template.Must(template.New("_").Parse(`
<p><b>Build Failed</b></p>
<p>Repository : {{.Repo.Owner}}/{{.Repo.Name}}</p>
<p>Commit : {{.Commit.ShaShort}}</p>
<p>Author : {{.Commit.Author}}</p>
<p>Branch : {{.Commit.Branch}}</p>
<p>Message:</p>
<p>{{ .Commit.Message }}</p>
`))

View file

@ -1,6 +1,9 @@
package notify package notify
import ( import (
"log"
"github.com/drone/drone/plugin/notify/email"
"github.com/drone/drone/shared/model" "github.com/drone/drone/shared/model"
) )
@ -12,32 +15,52 @@ type Sender interface {
// for notifying a user, or group of users, // for notifying a user, or group of users,
// when their Build has completed. // when their Build has completed.
type Notification struct { type Notification struct {
Email *Email `yaml:"email,omitempty"` Email *email.Email `yaml:"email,omitempty"`
Webhook *Webhook `yaml:"webhook,omitempty"` Webhook *Webhook `yaml:"webhook,omitempty"`
Hipchat *Hipchat `yaml:"hipchat,omitempty"` Hipchat *Hipchat `yaml:"hipchat,omitempty"`
Irc *IRC `yaml:"irc,omitempty"` Irc *IRC `yaml:"irc,omitempty"`
Slack *Slack `yaml:"slack,omitempty"` Slack *Slack `yaml:"slack,omitempty"`
} }
func (n *Notification) Send(context *model.Request) error { func (n *Notification) Send(context *model.Request) error {
// send email notifications // send email notifications
if n.Webhook != nil { if n.Email != nil {
n.Webhook.Send(context) err := n.Email.Send(context)
if err != nil {
log.Println(err)
}
} }
// send email notifications // send webhook notifications
if n.Webhook != nil {
err := n.Webhook.Send(context)
if err != nil {
log.Println(err)
}
}
// send hipchat notifications
if n.Hipchat != nil { if n.Hipchat != nil {
n.Hipchat.Send(context) err := n.Hipchat.Send(context)
if err != nil {
log.Println(err)
}
} }
// send irc notifications // send irc notifications
if n.Irc != nil { if n.Irc != nil {
n.Irc.Send(context) err := n.Irc.Send(context)
if err != nil {
log.Println(err)
}
} }
// send slack notifications // send slack notifications
if n.Slack != nil { if n.Slack != nil {
n.Slack.Send(context) err := n.Slack.Send(context)
if err != nil {
log.Println(err)
}
} }
return nil return nil

View file

@ -1,9 +0,0 @@
package smtp
type SMTP struct {
Host string `json:"host"`
Port string `json:"port"`
From string `json:"from"`
Username string `json:"username"`
Password string `json:"password"`
}