From 88752bc1593e766b7ee4e5d0cfcefcb40f4b8592 Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 16 Feb 2026 00:47:02 +0100 Subject: [PATCH] Exclude cancelled runs from failure-only email notifications (#36569) The default configuration of `failure-only` added in https://github.com/go-gitea/gitea/pull/34982 included sending mails for cancelled runs which is not what one would expect from a option named like that because a cancelled run is not a failure. This change makes it omit mails for cancelled runs: | Run Status | `failure-only` before | `failure-only` after | |------------|-----------------------|----------------------| | Success | no | no | | Failure | mail | mail | | Cancelled | mail | no | The first commit in this PR is the fix, and there are a few more refactor commits afterwards. --------- Co-authored-by: Claude Opus 4.6 --- models/user/user.go | 6 ++--- services/mailer/mail_workflow_run.go | 35 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/models/user/user.go b/models/user/user.go index 59a0b4e5d1..38042631de 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -496,10 +496,10 @@ func (u *User) ShortName(length int) string { return util.EllipsisDisplayString(u.Name, length) } -// IsMailable checks if a user is eligible -// to receive emails. +// IsMailable checks if a user is eligible to receive emails. +// System users like Ghost and Gitea Actions are excluded. func (u *User) IsMailable() bool { - return u.IsActive + return u.IsActive && !u.IsGiteaActions() && !u.IsGhost() } // IsUserExist checks if given username exist, diff --git a/services/mailer/mail_workflow_run.go b/services/mailer/mail_workflow_run.go index 3789102812..9efaa4182b 100644 --- a/services/mailer/mail_workflow_run.go +++ b/services/mailer/mail_workflow_run.go @@ -149,30 +149,31 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo return nil } -func MailActionsTrigger(ctx context.Context, sender *user_model.User, repo *repo_model.Repository, run *actions_model.ActionRun) error { +func MailActionsTrigger(ctx context.Context, recipient *user_model.User, repo *repo_model.Repository, run *actions_model.ActionRun) error { if setting.MailService == nil { return nil } if !run.Status.IsDone() || run.Status.IsSkipped() { return nil } - - recipients := make([]*user_model.User, 0) - - if !sender.IsGiteaActions() && !sender.IsGhost() && sender.IsMailable() { - notifyPref, err := user_model.GetUserSetting(ctx, sender.ID, - user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly) - if err != nil { - return err - } - if notifyPref == user_model.SettingEmailNotificationGiteaActionsAll || !run.Status.IsSuccess() && notifyPref != user_model.SettingEmailNotificationGiteaActionsDisabled { - recipients = append(recipients, sender) - } + if !recipient.IsMailable() { + return nil } - if len(recipients) > 0 { - log.Debug("MailActionsTrigger: Initiate email composition") - return composeAndSendActionsWorkflowRunStatusEmail(ctx, repo, run, sender, recipients) + notifyPref, err := user_model.GetUserSetting(ctx, recipient.ID, + user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly) + if err != nil { + return err } - return nil + // "disabled" never sends + if notifyPref == user_model.SettingEmailNotificationGiteaActionsDisabled { + return nil + } + // "failure-only" skips non-failure runs + if notifyPref != user_model.SettingEmailNotificationGiteaActionsAll && !run.Status.IsFailure() { + return nil + } + + log.Debug("MailActionsTrigger: Initiate email composition") + return composeAndSendActionsWorkflowRunStatusEmail(ctx, repo, run, recipient, []*user_model.User{recipient}) }