From 21fb2f8fe08522b0321f621c1e181e8be145f546 Mon Sep 17 00:00:00 2001 From: christopher-besch Date: Wed, 9 Apr 2025 15:55:13 +0200 Subject: [PATCH] feat: email on action run status change --- options/locale/locale_en-US.ini | 6 ++ services/mailer/mail_actions.go | 84 ++++++++++++++++++++++++++++ services/mailer/notify.go | 10 ++++ templates/mail/actions/now_done.tmpl | 32 +++++++++++ 4 files changed, 132 insertions(+) create mode 100644 services/mailer/mail_actions.go create mode 100644 templates/mail/actions/now_done.tmpl diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 48de439f6a..e4cf454cb7 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -576,6 +576,12 @@ team_invite.text_1 = %[1]s has invited you to join team %[2]s in organization %[ team_invite.text_2 = Please click the following link to join the team: team_invite.text_3 = Note: This invitation was intended for %[1]s. If you were not expecting this invitation, you can ignore this email. +actions.successful_run_after_failure_subject = Workflow %[1]s recovered in repository %[2]s +actions.not_successful_run_subject = Workflow %[1]s failed in repository %[2]s +actions.successful_run_after_failure = Workflow %[1]s recovered in repository %[2]s +actions.not_successful_run = Workflow %[1]s failed in repository %[2]s +actions.run_info = This Run's Status: %[1]s (just updated from %[2]s)
Previous Run's Status: %[3]s
Branch: %[4]s
Commit: %[5]s
Triggered because: %[6]s
Triggered by: %[7]s + [modal] yes = Yes no = No diff --git a/services/mailer/mail_actions.go b/services/mailer/mail_actions.go new file mode 100644 index 0000000000..7c63603a98 --- /dev/null +++ b/services/mailer/mail_actions.go @@ -0,0 +1,84 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later +package mailer + +import ( + "bytes" + + actions_model "forgejo.org/models/actions" + user_model "forgejo.org/models/user" + "forgejo.org/modules/base" + "forgejo.org/modules/setting" + "forgejo.org/modules/translation" +) + +const ( + tplActionNowDone base.TplName = "actions/now_done" +) + +// requires !run.Status.IsSuccess() or !lastRun.Status.IsSuccess() +func MailActionRun(run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) error { + if setting.MailService == nil { + // No mail service configured + return nil + } + + if run.TriggerUser.Email != "" && run.TriggerUser.EmailNotificationsPreference != user_model.EmailNotificationsDisabled { + if err := sendMailActionRun(run.TriggerUser, run, priorStatus, lastRun); err != nil { + return err + } + } + + if run.Repo.Owner.Email != "" && run.Repo.Owner.Email != run.TriggerUser.Email && run.Repo.Owner.EmailNotificationsPreference != user_model.EmailNotificationsDisabled { + if err := sendMailActionRun(run.Repo.Owner, run, priorStatus, lastRun); err != nil { + return err + } + } + + return nil +} + +func sendMailActionRun(to *user_model.User, run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) error { + var ( + locale = translation.NewLocale(to.Language) + content bytes.Buffer + ) + + var subject string + if run.Status.IsSuccess() { + subject = locale.TrString("mail.actions.successful_run_after_failure_subject", run.Title, run.Repo.FullName()) + } else { + subject = locale.TrString("mail.actions.not_successful_run", run.Title, run.Repo.FullName()) + } + + commitSHA := run.CommitSHA + if len(commitSHA) > 7 { + commitSHA = commitSHA[:7] + } + branch := run.PrettyRef() + + data := map[string]any{ + "locale": locale, + "Link": run.HTMLURL(), + "Subject": subject, + "Language": locale.Language(), + "RepoFullName": run.Repo.FullName(), + "Run": run, + "TriggerUserLink": run.TriggerUser.HTMLURL(), + "LastRun": lastRun, + "PriorStatus": priorStatus, + "CommitSHA": commitSHA, + "Branch": branch, + "IsSuccess": run.Status.IsSuccess(), + } + + if err := bodyTemplates.ExecuteTemplate(&content, string(tplActionNowDone), data); err != nil { + return err + } + + msg := NewMessage(to.EmailTo(), subject, content.String()) + msg.Info = subject + SendAsync(msg) + + return nil +} diff --git a/services/mailer/notify.go b/services/mailer/notify.go index 8acfa86fb6..ae7226fac3 100644 --- a/services/mailer/notify.go +++ b/services/mailer/notify.go @@ -7,6 +7,7 @@ import ( "context" "fmt" + actions_model "forgejo.org/models/actions" activities_model "forgejo.org/models/activities" issues_model "forgejo.org/models/issues" repo_model "forgejo.org/models/repo" @@ -208,3 +209,12 @@ func (m *mailNotifier) RepoPendingTransfer(ctx context.Context, doer, newOwner * func (m *mailNotifier) NewUserSignUp(ctx context.Context, newUser *user_model.User) { MailNewUser(ctx, newUser) } + +func (m *mailNotifier) ActionRunNowDone(ctx context.Context, run *actions_model.ActionRun, priorStatus actions_model.Status, lastRun *actions_model.ActionRun) { + if run.Status.IsSuccess() && lastRun.Status.IsSuccess() { + return + } + if err := MailActionRun(run, priorStatus, lastRun); err != nil { + log.Error("MailActionRunNowDone: %v", err) + } +} diff --git a/templates/mail/actions/now_done.tmpl b/templates/mail/actions/now_done.tmpl new file mode 100644 index 0000000000..f3065705df --- /dev/null +++ b/templates/mail/actions/now_done.tmpl @@ -0,0 +1,32 @@ + + + + + + + +{{$repo_link := HTMLFormat "%s" .Run.Repo.HTMLURL .RepoFullName}} +{{$action_run_link := HTMLFormat "%s" .Link .Run.Title}} +{{$trigger_user_link := HTMLFormat "@%s" .Run.TriggerUser.HTMLURL .Run.TriggerUser.Name}} + +

+ {{if .IsSuccess}} + {{.locale.Tr "mail.actions.successful_run_after_failure" $action_run_link $repo_link}} + {{else}} + {{.locale.Tr "mail.actions.not_successful_run" $action_run_link $repo_link}} + {{end}} + +
+ {{.locale.Tr "mail.actions.run_info" .Run.Status .PriorStatus .LastRun.Status .Branch .CommitSHA .Run.TriggerEvent $trigger_user_link}} +

+ + +