diff --git a/debian/drone/etc/default/drone b/debian/drone/etc/default/drone index f5684925..1da550f3 100644 --- a/debian/drone/etc/default/drone +++ b/debian/drone/etc/default/drone @@ -7,4 +7,42 @@ # -port=":8080": # -workers="4": # -#DRONED_OPTS="--port=:80" \ No newline at end of file +#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= \ No newline at end of file diff --git a/debian/drone/etc/init/drone.conf b/debian/drone/etc/init/drone.conf index 5885ec77..1e332ad8 100644 --- a/debian/drone/etc/init/drone.conf +++ b/debian/drone/etc/init/drone.conf @@ -4,9 +4,10 @@ chdir /var/lib/drone console log script - DRONED_OPTS="--port=:80" - if [ -f /etc/default/$UPSTART_JOB ]; then - . /etc/default/$UPSTART_JOB - fi - /usr/local/bin/droned $DRONED_OPTS + set -a + DRONED_OPTS="--port=:80" + if [ -f /etc/default/$UPSTART_JOB ]; then + . /etc/default/$UPSTART_JOB + fi + /usr/local/bin/droned $DRONED_OPTS end script \ No newline at end of file diff --git a/plugin/notify/email.go b/plugin/notify/email.go deleted file mode 100644 index ea90986b..00000000 --- a/plugin/notify/email.go +++ /dev/null @@ -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 -} diff --git a/plugin/notify/email/email.go b/plugin/notify/email/email.go new file mode 100644 index 00000000..60acc070 --- /dev/null +++ b/plugin/notify/email/email.go @@ -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)) +} diff --git a/plugin/notify/email/template.go b/plugin/notify/email/template.go new file mode 100644 index 00000000..54a27b3b --- /dev/null +++ b/plugin/notify/email/template.go @@ -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(` +

Build was Successful

+

Repository : {{.Repo.Owner}}/{{.Repo.Name}}

+

Commit : {{.Commit.ShaShort}}

+

Author : {{.Commit.Author}}

+

Branch : {{.Commit.Branch}}

+

Message:

+

{{ .Commit.Message }}

+`)) + +// default failure email template +var failureTemplate = template.Must(template.New("_").Parse(` +

Build Failed

+

Repository : {{.Repo.Owner}}/{{.Repo.Name}}

+

Commit : {{.Commit.ShaShort}}

+

Author : {{.Commit.Author}}

+

Branch : {{.Commit.Branch}}

+

Message:

+

{{ .Commit.Message }}

+`)) diff --git a/plugin/notify/notification.go b/plugin/notify/notification.go index 52362470..b7609540 100644 --- a/plugin/notify/notification.go +++ b/plugin/notify/notification.go @@ -1,6 +1,9 @@ package notify import ( + "log" + + "github.com/drone/drone/plugin/notify/email" "github.com/drone/drone/shared/model" ) @@ -12,32 +15,52 @@ type Sender interface { // for notifying a user, or group of users, // when their Build has completed. type Notification struct { - Email *Email `yaml:"email,omitempty"` - Webhook *Webhook `yaml:"webhook,omitempty"` - Hipchat *Hipchat `yaml:"hipchat,omitempty"` - Irc *IRC `yaml:"irc,omitempty"` - Slack *Slack `yaml:"slack,omitempty"` + Email *email.Email `yaml:"email,omitempty"` + Webhook *Webhook `yaml:"webhook,omitempty"` + Hipchat *Hipchat `yaml:"hipchat,omitempty"` + Irc *IRC `yaml:"irc,omitempty"` + Slack *Slack `yaml:"slack,omitempty"` } func (n *Notification) Send(context *model.Request) error { // send email notifications - if n.Webhook != nil { - n.Webhook.Send(context) + if n.Email != nil { + 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 { - n.Hipchat.Send(context) + err := n.Hipchat.Send(context) + if err != nil { + log.Println(err) + } } // send irc notifications if n.Irc != nil { - n.Irc.Send(context) + err := n.Irc.Send(context) + if err != nil { + log.Println(err) + } } // send slack notifications if n.Slack != nil { - n.Slack.Send(context) + err := n.Slack.Send(context) + if err != nil { + log.Println(err) + } } return nil diff --git a/plugin/smtp/smtp.go b/plugin/smtp/smtp.go deleted file mode 100644 index 707e6091..00000000 --- a/plugin/smtp/smtp.go +++ /dev/null @@ -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"` -}