Browse Source

hook: fix email not sent after push (#4430)

Turns out mail service was not initialized at all, also mail must
be sent in sync in hook mode before program exits.
pull/4649/merge
Unknwon 7 years ago
parent
commit
6bc11c4450
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
  1. 10
      cmd/hook.go
  2. 2
      gogs.go
  3. 3
      models/action.go
  4. 6
      models/comment.go
  5. 3
      models/issue_mail.go
  6. 12
      pkg/mailer/mail.go
  7. 21
      pkg/mailer/mailer.go
  8. 24
      pkg/setting/setting.go
  9. 17
      pkg/template/template.go
  10. 2
      templates/.VERSION

10
cmd/hook.go

@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"strings" "strings"
@ -22,7 +23,9 @@ import (
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/pkg/httplib" "github.com/gogits/gogs/pkg/httplib"
"github.com/gogits/gogs/pkg/mailer"
"github.com/gogits/gogs/pkg/setting" "github.com/gogits/gogs/pkg/setting"
"github.com/gogits/gogs/pkg/template"
http "github.com/gogits/gogs/routes/repo" http "github.com/gogits/gogs/routes/repo"
) )
@ -184,6 +187,13 @@ func runHookPostReceive(c *cli.Context) error {
} }
setup(c, "hooks/post-receive.log", true) setup(c, "hooks/post-receive.log", true)
// Post-receive hook does more than just gather Git information,
// so we need to setup additional services for email notifications.
setting.NewPostReceiveHookServices()
mailer.NewContext()
mailer.InitMailRender(path.Join(setting.StaticRootPath, "templates/mail"),
path.Join(setting.CustomPath, "templates/mail"), template.NewFuncMap())
isWiki := strings.Contains(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/") isWiki := strings.Contains(os.Getenv(http.ENV_REPO_CUSTOM_HOOKS_PATH), ".wiki.git/")
buf := bytes.NewBuffer(nil) buf := bytes.NewBuffer(nil)

2
gogs.go

@ -16,7 +16,7 @@ import (
"github.com/gogits/gogs/pkg/setting" "github.com/gogits/gogs/pkg/setting"
) )
const APP_VER = "0.11.28.0718" const APP_VER = "0.11.29.0727"
func init() { func init() {
setting.AppVer = APP_VER setting.AppVer = APP_VER

3
models/action.go

@ -379,8 +379,7 @@ func UpdateIssuesCommit(doer *User, repo *Repository, commits []*PushCommit) err
if ref[0] == '#' { if ref[0] == '#' {
ref = fmt.Sprintf("%s%s", repo.FullName(), ref) ref = fmt.Sprintf("%s%s", repo.FullName(), ref)
} else if !strings.Contains(ref, "/") { } else if !strings.Contains(ref, "/") {
// We don't support User#ID syntax yet // FIXME: We don't support User#ID syntax yet
// return ErrNotImplemented
continue continue
} }

6
models/comment.go

@ -188,7 +188,7 @@ func (cmt *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue)
issue.Content = fmt.Sprintf("Reopened #%d", issue.Index) issue.Content = fmt.Sprintf("Reopened #%d", issue.Index)
} }
if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil { if err = mailIssueCommentToParticipants(issue, cmt.Poster, mentions); err != nil {
log.Error(4, "mailIssueCommentToParticipants: %v", err) log.Error(2, "mailIssueCommentToParticipants: %v", err)
} }
return nil return nil
@ -290,10 +290,10 @@ func createComment(e *xorm.Session, opts *CreateCommentOptions) (_ *Comment, err
// Notify watchers for whatever action comes in, ignore if no action type. // Notify watchers for whatever action comes in, ignore if no action type.
if act.OpType > 0 { if act.OpType > 0 {
if err = notifyWatchers(e, act); err != nil { if err = notifyWatchers(e, act); err != nil {
log.Error(4, "notifyWatchers: %v", err) log.Error(2, "notifyWatchers: %v", err)
} }
if err = comment.mailParticipants(e, act.OpType, opts.Issue); err != nil { if err = comment.mailParticipants(e, act.OpType, opts.Issue); err != nil {
log.Error(4, "MailParticipants: %v", err) log.Error(2, "MailParticipants: %v", err)
} }
} }

3
models/issue_mail.go

@ -155,7 +155,6 @@ func mailIssueCommentToParticipants(issue *Issue, doer *User, mentions []string)
tos = append(tos, mentions[i]) tos = append(tos, mentions[i])
} }
mailer.SendIssueMentionMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), GetUserEmailsByNames(tos)) mailer.SendIssueMentionMail(NewMailerIssue(issue), NewMailerRepo(issue.Repo), NewMailerUser(doer), GetUserEmailsByNames(tos))
return nil return nil
} }
@ -168,7 +167,7 @@ func (issue *Issue) MailParticipants() (err error) {
} }
if err = mailIssueCommentToParticipants(issue, issue.Poster, mentions); err != nil { if err = mailIssueCommentToParticipants(issue, issue.Poster, mentions); err != nil {
log.Error(4, "mailIssueCommentToParticipants: %v", err) log.Error(2, "mailIssueCommentToParticipants: %v", err)
} }
return nil return nil

12
pkg/mailer/mail.go

@ -94,7 +94,7 @@ func SendUserMail(c *macaron.Context, u User, tpl, code, subject, info string) {
msg := NewMessage([]string{u.Email()}, subject, body) msg := NewMessage([]string{u.Email()}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, %s", u.ID(), info) msg.Info = fmt.Sprintf("UID: %d, %s", u.ID(), info)
SendAsync(msg) Send(msg)
} }
func SendActivateAccountMail(c *macaron.Context, u User) { func SendActivateAccountMail(c *macaron.Context, u User) {
@ -122,7 +122,7 @@ func SendActivateEmailMail(c *macaron.Context, u User, email string) {
msg := NewMessage([]string{email}, c.Tr("mail.activate_email"), body) msg := NewMessage([]string{email}, c.Tr("mail.activate_email"), body)
msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID()) msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID())
SendAsync(msg) Send(msg)
} }
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account. // SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
@ -139,7 +139,7 @@ func SendRegisterNotifyMail(c *macaron.Context, u User) {
msg := NewMessage([]string{u.Email()}, c.Tr("mail.register_notify"), body) msg := NewMessage([]string{u.Email()}, c.Tr("mail.register_notify"), body)
msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID()) msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID())
SendAsync(msg) Send(msg)
} }
// SendCollaboratorMail sends mail notification to new collaborator. // SendCollaboratorMail sends mail notification to new collaborator.
@ -160,7 +160,7 @@ func SendCollaboratorMail(u, doer User, repo Repository) {
msg := NewMessage([]string{u.Email()}, subject, body) msg := NewMessage([]string{u.Email()}, subject, body)
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID()) msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID())
SendAsync(msg) Send(msg)
} }
func composeTplData(subject, body, link string) map[string]interface{} { func composeTplData(subject, body, link string) map[string]interface{} {
@ -192,7 +192,7 @@ func SendIssueCommentMail(issue Issue, repo Repository, doer User, tos []string)
return return
} }
SendAsync(composeIssueMessage(issue, repo, doer, MAIL_ISSUE_COMMENT, tos, "issue comment")) Send(composeIssueMessage(issue, repo, doer, MAIL_ISSUE_COMMENT, tos, "issue comment"))
} }
// SendIssueMentionMail composes and sends issue mention emails to target receivers. // SendIssueMentionMail composes and sends issue mention emails to target receivers.
@ -200,5 +200,5 @@ func SendIssueMentionMail(issue Issue, repo Repository, doer User, tos []string)
if len(tos) == 0 { if len(tos) == 0 {
return return
} }
SendAsync(composeIssueMessage(issue, repo, doer, MAIL_ISSUE_MENTION, tos, "issue mention")) Send(composeIssueMessage(issue, repo, doer, MAIL_ISSUE_MENTION, tos, "issue mention"))
} }

21
pkg/mailer/mailer.go

@ -24,6 +24,7 @@ import (
type Message struct { type Message struct {
Info string // Message information for log purpose. Info string // Message information for log purpose.
*gomail.Message *gomail.Message
confirmChan chan struct{}
} }
// NewMessageFrom creates new mail message object with custom From header. // NewMessageFrom creates new mail message object with custom From header.
@ -48,9 +49,9 @@ func NewMessageFrom(to []string, from, subject, htmlBody string) *Message {
} }
} }
msg.SetBody(contentType, body) msg.SetBody(contentType, body)
return &Message{ return &Message{
Message: msg, Message: msg,
confirmChan: make(chan struct{}),
} }
} }
@ -204,12 +205,14 @@ func processMailQueue() {
} else { } else {
log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info) log.Trace("E-mails sent %s: %s", msg.GetHeader("To"), msg.Info)
} }
msg.confirmChan <- struct{}{}
} }
} }
} }
var mailQueue chan *Message var mailQueue chan *Message
// NewContext initializes settings for mailer.
func NewContext() { func NewContext() {
// Need to check if mailQueue is nil because in during reinstall (user had installed // Need to check if mailQueue is nil because in during reinstall (user had installed
// before but swithed install lock off), this function will be called again // before but swithed install lock off), this function will be called again
@ -222,8 +225,18 @@ func NewContext() {
go processMailQueue() go processMailQueue()
} }
func SendAsync(msg *Message) { // Send puts new message object into mail queue.
// It returns without confirmation (mail processed asynchronously) in normal cases,
// but waits/blocks under hook mode to make sure mail has been sent.
func Send(msg *Message) {
mailQueue <- msg
if setting.HookMode {
<-msg.confirmChan
return
}
go func() { go func() {
mailQueue <- msg <-msg.confirmChan
}() }()
} }

24
pkg/setting/setting.go

@ -832,9 +832,10 @@ var (
MailService *Mailer MailService *Mailer
) )
// newMailService initializes mail service options from configuration.
// No non-error log will be printed in hook mode.
func newMailService() { func newMailService() {
sec := Cfg.Section("mailer") sec := Cfg.Section("mailer")
// Check mailer setting.
if !sec.Key("ENABLED").MustBool() { if !sec.Key("ENABLED").MustBool() {
return return
} }
@ -863,6 +864,9 @@ func newMailService() {
MailService.FromEmail = parsed.Address MailService.FromEmail = parsed.Address
} }
if HookMode {
return
}
log.Info("Mail Service Enabled") log.Info("Mail Service Enabled")
} }
@ -877,6 +881,8 @@ func newRegisterMailService() {
log.Info("Register Mail Service Enabled") log.Info("Register Mail Service Enabled")
} }
// newNotifyMailService initializes notification email service options from configuration.
// No non-error log will be printed in hook mode.
func newNotifyMailService() { func newNotifyMailService() {
if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() {
return return
@ -885,6 +891,10 @@ func newNotifyMailService() {
return return
} }
Service.EnableNotifyMail = true Service.EnableNotifyMail = true
if HookMode {
return
}
log.Info("Notify Mail Service Enabled") log.Info("Notify Mail Service Enabled")
} }
@ -901,3 +911,15 @@ func NewServices() {
newRegisterMailService() newRegisterMailService()
newNotifyMailService() newNotifyMailService()
} }
// HookMode indicates whether program starts as Git server-side hook callback.
var HookMode bool
// NewPostReceiveHookServices initializes all services that are needed by
// Git server-side post-receive hook callback.
func NewPostReceiveHookServices() {
HookMode = true
newService()
newMailService()
newNotifyMailService()
}

17
pkg/template/template.go

@ -22,11 +22,12 @@ import (
"gopkg.in/editorconfig/editorconfig-core-go.v1" "gopkg.in/editorconfig/editorconfig-core-go.v1"
"github.com/gogits/gogs/models" "github.com/gogits/gogs/models"
"github.com/gogits/gogs/pkg/tool"
"github.com/gogits/gogs/pkg/markup" "github.com/gogits/gogs/pkg/markup"
"github.com/gogits/gogs/pkg/setting" "github.com/gogits/gogs/pkg/setting"
"github.com/gogits/gogs/pkg/tool"
) )
// TODO: only initialize map once and save to a local variable to reduce copies.
func NewFuncMap() []template.FuncMap { func NewFuncMap() []template.FuncMap {
return []template.FuncMap{map[string]interface{}{ return []template.FuncMap{map[string]interface{}{
"GoVer": func() string { "GoVer": func() string {
@ -91,13 +92,13 @@ func NewFuncMap() []template.FuncMap {
} }
return str[start:end] return str[start:end]
}, },
"Join": strings.Join, "Join": strings.Join,
"EllipsisString": tool.EllipsisString, "EllipsisString": tool.EllipsisString,
"DiffTypeToStr": DiffTypeToStr, "DiffTypeToStr": DiffTypeToStr,
"DiffLineTypeToStr": DiffLineTypeToStr, "DiffLineTypeToStr": DiffLineTypeToStr,
"Sha1": Sha1, "Sha1": Sha1,
"ShortSHA1": tool.ShortSHA1, "ShortSHA1": tool.ShortSHA1,
"MD5": tool.MD5, "MD5": tool.MD5,
"ActionContent2Commits": ActionContent2Commits, "ActionContent2Commits": ActionContent2Commits,
"EscapePound": EscapePound, "EscapePound": EscapePound,
"RenderCommitMessage": RenderCommitMessage, "RenderCommitMessage": RenderCommitMessage,

2
templates/.VERSION

@ -1 +1 @@
0.11.28.0718 0.11.29.0727
Loading…
Cancel
Save