feat: 发布成功/失败飞书&Lark 群卡片通知

- internal/lark:飞书自定义机器人交互卡片(wide_screen_mode + 彩色头部
  green/red/yellow + lark_md 字段区 + 查看构建详情按钮),支持签名加签
  (timestamp+sign HMAC-SHA256,密钥 enc:v1: 加密存储)
- 双引擎收口:原生模拟引擎与 Jenkins 真实引擎运行结束均推送卡片;
  应用/分支/构建(#N 或 runId)/状态/时间;Jenkins 构建附
  externalURL 按钮直达构建详情页
- Webhook 优先级:流水线「通知 Webhook」> 全局设置(需启用)
- 系统设置新增飞书通知配置区(启用开关/Webhook/签名密钥只写/
  发送测试卡片);POST /api/settings/test-lark
- E2E 已验证:本地模拟机器人收到完整卡片 JSON,测试卡片正常
This commit is contained in:
Logan.Li committed 2026-10-27 09:37:23 +08:00
1 parent 6e97b55015
commit d9d1dd5e99
10 files changed
+329 -9

No files matched your search

+16
View File
@@ -90,6 +90,7 @@ func GetSettings(c *gin.Context) {
database.DB.Create(&s)
}
s.LlmApiKeySet = s.LlmApiKey != ""
s.LarkSecretSet = s.LarkSecret != ""
c.JSON(http.StatusOK, s)
}
@@ -139,9 +140,24 @@ func UpdateSettings(c *gin.Context) {
}
updates["llm_api_key"] = enc
}
if v, ok := body["larkEnabled"].(bool); ok {
updates["lark_enabled"] = v
}
if v, ok := body["larkWebhook"].(string); ok {
updates["lark_webhook"] = v
}
if v, ok := body["larkSecret"].(string); ok && v != "" {
enc, err := crypto.EncryptField(v)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "签名密钥加密失败"})
return
}
updates["lark_secret"] = enc
}
database.DB.Model(&s).Updates(updates)
database.DB.First(&s, 1)
s.LlmApiKeySet = s.LlmApiKey != ""
s.LarkSecretSet = s.LarkSecret != ""
c.JSON(http.StatusOK, s)
}