Build and Deploy Server / build (push) Failing after 2s
- loadWishes使用safeInitRibbons/safeInitDanmaku,防止初始化出错导致页面崩溃 - getCurrentTree确保返回带type字段的有效树对象 - 添加错误处理,避免未定义错误
215 lines
5.7 KiB
Bash
215 lines
5.7 KiB
Bash
#!/bin/bash
|
||
# 部署通知脚本 - 支持 Telegram 和 Discord
|
||
# 使用方法: ./notify.sh <status> <title> <message> [color]
|
||
# status: success 或 failure
|
||
# title: 通知标题
|
||
# message: 通知内容
|
||
# color: Discord 消息颜色(可选,默认根据 status 自动选择)
|
||
|
||
set -e
|
||
|
||
STATUS="$1"
|
||
TITLE="$2"
|
||
MESSAGE="$3"
|
||
COLOR="${4:-}"
|
||
|
||
# 根据状态设置默认值
|
||
if [ "$STATUS" = "success" ]; then
|
||
EMOJI="✅"
|
||
DEFAULT_COLOR="3066993" # 绿色
|
||
STATUS_TEXT="成功"
|
||
elif [ "$STATUS" = "failure" ]; then
|
||
EMOJI="❌"
|
||
DEFAULT_COLOR="15158332" # 红色
|
||
STATUS_TEXT="失败"
|
||
else
|
||
EMOJI="ℹ️"
|
||
DEFAULT_COLOR="3447003" # 蓝色
|
||
STATUS_TEXT="通知"
|
||
fi
|
||
|
||
COLOR="${COLOR:-$DEFAULT_COLOR}"
|
||
|
||
# 校验 COLOR 必须是数字
|
||
if ! [[ "$COLOR" =~ ^[0-9]+$ ]]; then
|
||
echo "⚠️ 非法 COLOR 值: $COLOR,使用默认颜色 $DEFAULT_COLOR"
|
||
COLOR="$DEFAULT_COLOR"
|
||
fi
|
||
|
||
# 获取 Git 信息
|
||
REPO="${GITEA_REPO:-unknown}"
|
||
BRANCH="${GITEA_REF_NAME:-unknown}"
|
||
COMMIT_SHA="${GITEA_SHA:-unknown}"
|
||
COMMIT_SHORT="${COMMIT_SHA:0:7}"
|
||
AUTHOR="${GITEA_ACTOR:-unknown}"
|
||
WORKFLOW="${GITEA_WORKFLOW:-unknown}"
|
||
RUN_NUMBER="${GITEA_RUN_NUMBER:-unknown}"
|
||
RUN_URL="${GITEA_SERVER_URL:-}/${GITEA_REPO}/actions/runs/${GITEA_RUN_ID:-}"
|
||
|
||
# HTML 转义函数(用于 Telegram)
|
||
html_escape() {
|
||
local s="$1"
|
||
s="${s//&/&}"
|
||
s="${s//</<}"
|
||
s="${s//>/>}"
|
||
s="${s//\"/"}"
|
||
printf '%s' "$s"
|
||
}
|
||
|
||
# ==================== Telegram 通知 ====================
|
||
send_telegram() {
|
||
if [ -z "$TELEGRAM_BOT_TOKEN" ] || [ -z "$TELEGRAM_CHAT_ID" ]; then
|
||
echo "⚠️ Telegram 配置缺失,跳过通知"
|
||
return 0
|
||
fi
|
||
|
||
# 转义所有用户可控的变量
|
||
local escaped_title escaped_message escaped_repo escaped_branch escaped_author escaped_workflow escaped_run_url
|
||
escaped_title=$(html_escape "$TITLE")
|
||
escaped_message=$(html_escape "$MESSAGE")
|
||
escaped_repo=$(html_escape "$REPO")
|
||
escaped_branch=$(html_escape "$BRANCH")
|
||
escaped_author=$(html_escape "$AUTHOR")
|
||
escaped_workflow=$(html_escape "$WORKFLOW")
|
||
escaped_run_url=$(html_escape "$RUN_URL")
|
||
|
||
local tg_message="${EMOJI} <b>${escaped_title}</b>
|
||
|
||
<b>状态:</b> ${STATUS_TEXT}
|
||
<b>仓库:</b> ${escaped_repo}
|
||
<b>分支:</b> ${escaped_branch}
|
||
<b>提交:</b> <code>${COMMIT_SHORT}</code>
|
||
<b>作者:</b> ${escaped_author}
|
||
<b>工作流:</b> ${escaped_workflow} #${RUN_NUMBER}
|
||
|
||
${escaped_message}
|
||
|
||
<a href=\"${escaped_run_url}\">查看详情</a>"
|
||
|
||
echo "📤 发送 Telegram 通知..."
|
||
|
||
local response
|
||
response=$(curl -sS --connect-timeout 5 --max-time 15 -X POST \
|
||
"https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
|
||
-d "chat_id=${TELEGRAM_CHAT_ID}" \
|
||
--data-urlencode "text=${tg_message}" \
|
||
-d "parse_mode=HTML" \
|
||
-d "disable_web_page_preview=true" 2>&1) || {
|
||
echo "❌ Telegram 请求失败: $response"
|
||
return 1
|
||
}
|
||
|
||
if echo "$response" | grep -q '"ok":true'; then
|
||
echo "✅ Telegram 通知发送成功"
|
||
else
|
||
echo "❌ Telegram 通知发送失败: $response"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# ==================== Discord 通知 ====================
|
||
send_discord() {
|
||
if [ -z "$DISCORD_WEBHOOK_URL" ]; then
|
||
echo "⚠️ Discord Webhook 配置缺失,跳过通知"
|
||
return 0
|
||
fi
|
||
|
||
echo "📤 发送 Discord 通知..."
|
||
|
||
# 使用 python3 构建 JSON,防止注入
|
||
local discord_payload
|
||
discord_payload=$(python3 -c "
|
||
import json
|
||
import sys
|
||
|
||
payload = {
|
||
'embeds': [{
|
||
'title': sys.argv[1],
|
||
'description': sys.argv[2],
|
||
'color': int(sys.argv[3]),
|
||
'fields': [
|
||
{'name': '状态', 'value': sys.argv[4], 'inline': True},
|
||
{'name': '仓库', 'value': sys.argv[5], 'inline': True},
|
||
{'name': '分支', 'value': sys.argv[6], 'inline': True},
|
||
{'name': '提交', 'value': sys.argv[7], 'inline': True},
|
||
{'name': '作者', 'value': sys.argv[8], 'inline': True},
|
||
{'name': '工作流', 'value': sys.argv[9], 'inline': True}
|
||
],
|
||
'footer': {'text': 'Gitea Actions'},
|
||
'timestamp': sys.argv[10],
|
||
'url': sys.argv[11]
|
||
}]
|
||
}
|
||
print(json.dumps(payload, ensure_ascii=False))
|
||
" \
|
||
"${EMOJI} ${TITLE}" \
|
||
"${MESSAGE}" \
|
||
"${COLOR}" \
|
||
"${STATUS_TEXT}" \
|
||
"${REPO}" \
|
||
"${BRANCH}" \
|
||
"\`${COMMIT_SHORT}\`" \
|
||
"${AUTHOR}" \
|
||
"${WORKFLOW} #${RUN_NUMBER}" \
|
||
"$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||
"${RUN_URL}"
|
||
)
|
||
|
||
local http_code response_body
|
||
response_body=$(mktemp)
|
||
http_code=$(curl -sS -o "$response_body" -w "%{http_code}" \
|
||
--connect-timeout 5 --max-time 15 -X POST \
|
||
"$DISCORD_WEBHOOK_URL" \
|
||
-H "Content-Type: application/json" \
|
||
-d "$discord_payload" 2>&1) || {
|
||
echo "❌ Discord 请求失败: $http_code"
|
||
rm -f "$response_body"
|
||
return 1
|
||
}
|
||
|
||
if [ "$http_code" = "204" ] || [ "$http_code" = "200" ]; then
|
||
echo "✅ Discord 通知发送成功 (HTTP $http_code)"
|
||
rm -f "$response_body"
|
||
else
|
||
echo "❌ Discord 通知发送失败 (HTTP $http_code): $(cat "$response_body")"
|
||
rm -f "$response_body"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# ==================== 主流程 ====================
|
||
main() {
|
||
echo "🔔 开始发送部署通知..."
|
||
echo "状态: $STATUS"
|
||
echo "标题: $TITLE"
|
||
echo "消息: $MESSAGE"
|
||
echo ""
|
||
|
||
local failed=0
|
||
|
||
# 发送 Telegram 通知
|
||
if ! send_telegram; then
|
||
failed=$((failed + 1))
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# 发送 Discord 通知
|
||
if ! send_discord; then
|
||
failed=$((failed + 1))
|
||
fi
|
||
|
||
echo ""
|
||
if [ $failed -eq 0 ]; then
|
||
echo "✅ 所有通知发送完成"
|
||
elif [ $failed -ge 2 ]; then
|
||
echo "❌ 所有通知渠道均发送失败"
|
||
exit 1 # 全部失败时退出非 0,让 CI 可见
|
||
else
|
||
echo "⚠️ 部分通知发送失败 ($failed 个)"
|
||
# 部分失败不退出,避免影响主流程
|
||
fi
|
||
}
|
||
|
||
main
|