From 8d43d2f29ce2a84169505c9ac0d9600f99cf10e0 Mon Sep 17 00:00:00 2001 From: Aleksey Dolgov Date: Mon, 30 Jun 2025 15:06:47 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=BE=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=B0=D0=BB=D0=B5=D1=80=D1=82=D0=BE=D0=B2=20=D0=B2=20telegram?= =?UTF-8?q?=20treads?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- services/tasks/alert.go | 228 +++++++++++++++++-------- services/tasks/templates/telegram.tmpl | 1 + util/config.go | 1 + 3 files changed, 159 insertions(+), 71 deletions(-) diff --git a/services/tasks/alert.go b/services/tasks/alert.go index ff30c67b5..d4eaa68ca 100644 --- a/services/tasks/alert.go +++ b/services/tasks/alert.go @@ -36,6 +36,7 @@ type alertTask struct { type alertChat struct { ID string + ThreadID string // ID темы (опционально) } func (t *TaskRunner) sendMailAlert() { @@ -110,78 +111,163 @@ func (t *TaskRunner) sendMailAlert() { } } -func (t *TaskRunner) sendTelegramAlert() { - if !util.Config.TelegramAlert || !t.alert { - return - } - - if t.Template.SuppressSuccessAlerts && t.Task.Status == task_logger.TaskSuccessStatus { - return - } +//func (t *TaskRunner) sendTelegramAlert() { +// if !util.Config.TelegramAlert || !t.alert { +// return +// } +// +// if t.Template.SuppressSuccessAlerts && t.Task.Status == task_logger.TaskSuccessStatus { +// return +// } +// +// chatID := util.Config.TelegramChat +// if t.alertChat != nil && *t.alertChat != "" { +// chatID = *t.alertChat +// } +// +// if chatID == "" { +// return +// } +// +// body := bytes.NewBufferString("") +// author, version := t.alertInfos() +// +// alert := Alert{ +// Name: t.Template.Name, +// Author: author, +// Color: t.alertColor("telegram"), +// Task: alertTask{ +// ID: strconv.Itoa(t.Task.ID), +// URL: t.taskLink(), +// Result: t.Task.Status.Format(), +// Version: version, +// Desc: t.Task.Message, +// }, +// Chat: alertChat{ +// ID: chatID, +// }, +// } +// +// tpl, err := template.ParseFS(templates, "templates/telegram.tmpl") +// +// if err != nil { +// t.Log("Can't parse telegram alert template!") +// panic(err) +// } +// +// if err := tpl.Execute(body, alert); err != nil { +// t.Log("Can't generate telegram alert template!") +// panic(err) +// } +// +// if body.Len() == 0 { +// t.Log("Buffer for telegram alert is empty") +// return +// } +// +// t.Log("Attempting to send telegram alert") +// +// resp, err := http.Post( +// fmt.Sprintf( +// "https://api.telegram.org/bot%s/sendMessage", +// util.Config.TelegramToken, +// ), +// "application/json", +// body, +// ) +// +// if err != nil { +// t.Log("Can't send telegram alert! Error: " + err.Error()) +// } else if resp.StatusCode != 200 { +// t.Log("Can't send telegram alert! Response code: " + strconv.Itoa(resp.StatusCode)) +// } +// +// t.Log("Sent successfully telegram alert") +//} - chatID := util.Config.TelegramChat - if t.alertChat != nil && *t.alertChat != "" { - chatID = *t.alertChat - } - - if chatID == "" { - return - } - - body := bytes.NewBufferString("") - author, version := t.alertInfos() - - alert := Alert{ - Name: t.Template.Name, - Author: author, - Color: t.alertColor("telegram"), - Task: alertTask{ - ID: strconv.Itoa(t.Task.ID), - URL: t.taskLink(), - Result: t.Task.Status.Format(), - Version: version, - Desc: t.Task.Message, - }, - Chat: alertChat{ - ID: chatID, - }, - } - - tpl, err := template.ParseFS(templates, "templates/telegram.tmpl") - - if err != nil { - t.Log("Can't parse telegram alert template!") - panic(err) - } - - if err := tpl.Execute(body, alert); err != nil { - t.Log("Can't generate telegram alert template!") - panic(err) - } - - if body.Len() == 0 { - t.Log("Buffer for telegram alert is empty") - return - } - - t.Log("Attempting to send telegram alert") - - resp, err := http.Post( - fmt.Sprintf( - "https://api.telegram.org/bot%s/sendMessage", - util.Config.TelegramToken, - ), - "application/json", - body, - ) - - if err != nil { - t.Log("Can't send telegram alert! Error: " + err.Error()) - } else if resp.StatusCode != 200 { - t.Log("Can't send telegram alert! Response code: " + strconv.Itoa(resp.StatusCode)) - } - - t.Log("Sent successfully telegram alert") +func (t *TaskRunner) sendTelegramAlert() { + if !util.Config.TelegramAlert || !t.alert { + return + } + + if t.Template.SuppressSuccessAlerts && t.Task.Status == task_logger.TaskSuccessStatus { + return + } + + chatID := util.Config.TelegramChat + threadID := util.Config.TelegramThreadID // Новый параметр конфига + + if t.alertChat != nil && *t.alertChat != "" { + chatID = *t.alertChat + } + + if chatID == "" { + return + } + + body := bytes.NewBufferString("") + author, version := t.alertInfos() + + alert := Alert{ + Name: t.Template.Name, + Author: author, + Color: t.alertColor("telegram"), + Task: alertTask{ + ID: strconv.Itoa(t.Task.ID), + URL: t.taskLink(), + Result: t.Task.Status.Format(), + Version: version, + Desc: t.Task.Message, + }, + Chat: alertChat{ + ID: chatID, + ThreadID: threadID, // Добавляем ID темы + }, + } + + tpl, err := template.ParseFS(templates, "templates/telegram.tmpl") + + if err != nil { + t.Log("Can't parse telegram alert template!") + panic(err) + } + + if err := tpl.Execute(body, alert); err != nil { + t.Log("Can't generate telegram alert template!") + panic(err) + } + + if body.Len() == 0 { + t.Log("Buffer for telegram alert is empty") + return + } + + t.Log("Attempting to send telegram alert") + + // Формируем базовый URL + apiUrl := fmt.Sprintf( + "https://api.telegram.org/bot%s/sendMessage", + util.Config.TelegramToken, + ) + + // Если указан threadID, добавляем его как параметр запроса + if threadID != "" { + apiUrl += fmt.Sprintf("?message_thread_id=%s", threadID) + } + + resp, err := http.Post( + apiUrl, + "application/json", + body, + ) + + if err != nil { + t.Log("Can't send telegram alert! Error: " + err.Error()) + } else if resp.StatusCode != 200 { + t.Log("Can't send telegram alert! Response code: " + strconv.Itoa(resp.StatusCode)) + } + + t.Log("Sent successfully telegram alert") } func (t *TaskRunner) sendSlackAlert() { diff --git a/services/tasks/templates/telegram.tmpl b/services/tasks/templates/telegram.tmpl index 33d50d901..bf565fa36 100644 --- a/services/tasks/templates/telegram.tmpl +++ b/services/tasks/templates/telegram.tmpl @@ -1,5 +1,6 @@ { "chat_id": "{{ .Chat.ID }}", + {{ if .Chat.ThreadID }}"message_thread_id": "{{ .Chat.ThreadID }}",{{ end }} "parse_mode": "HTML", "text": "{{ .Name }}\n#{{ .Task.ID }} {{ .Task.Result }} {{ .Task.Version }} - {{ .Task.Desc }}\nby {{ .Author }}\n{{ .Task.URL }}" } diff --git a/util/config.go b/util/config.go index 3fd55f1a4..bc6faac06 100644 --- a/util/config.go +++ b/util/config.go @@ -261,6 +261,7 @@ type ConfigType struct { TelegramAlert bool `json:"telegram_alert,omitempty" env:"SEMAPHORE_TELEGRAM_ALERT"` TelegramChat string `json:"telegram_chat,omitempty" env:"SEMAPHORE_TELEGRAM_CHAT"` TelegramToken string `json:"telegram_token,omitempty" env:"SEMAPHORE_TELEGRAM_TOKEN"` + TelegramThreadID string `json:"telegram_thread_id" env:"SEMAPHORE_TELEGRAM_THREAD_ID"` // Новый параметр SlackAlert bool `json:"slack_alert,omitempty" env:"SEMAPHORE_SLACK_ALERT"` SlackUrl string `json:"slack_url,omitempty" env:"SEMAPHORE_SLACK_URL"` RocketChatAlert bool `json:"rocketchat_alert,omitempty" env:"SEMAPHORE_ROCKETCHAT_ALERT"`