Files
awoooi/scripts/ci/notify-awoooi-cicd.sh
Your Name 170f927bc6
All checks were successful
Code Review / ai-code-review (push) Successful in 11s
fix(ci): build cicd notification payload without python
2026-05-19 14:03:23 +08:00

161 lines
4.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 2026-05-12 Codex: CI/CD 通知先走 AWOOI Alertmanager 入口,讓 TelegramGateway
# 鏡像出站訊息到 AwoooP呼叫端保留直接 Telegram fallback。
set -euo pipefail
API_BASE="${AWOOOI_API_URL:-http://192.168.0.125:32334}"
ALERTMANAGER_URL="${AWOOOI_ALERTMANAGER_URL:-${API_BASE%/}/api/v1/webhooks/alertmanager}"
JOB_NAME="${AWOOI_CICD_JOB_NAME:-${AWOOOI_CICD_JOB_NAME:-CI/CD Pipeline}}"
STATUS_RAW="${AWOOI_CICD_STATUS:-${AWOOOI_CICD_STATUS:-running}}"
STAGE="${AWOOI_CICD_STAGE:-${AWOOOI_CICD_STAGE:-ci}}"
COMMIT_SHA="${AWOOI_CICD_COMMIT_SHA:-${AWOOOI_CICD_COMMIT_SHA:-${GITHUB_SHA:-}}}"
TRIGGERED_BY="${AWOOI_CICD_TRIGGERED_BY:-${AWOOOI_CICD_TRIGGERED_BY:-${GITHUB_ACTOR:-CI}}}"
WORKFLOW_URL="${AWOOI_CICD_WORKFLOW_URL:-${AWOOOI_CICD_WORKFLOW_URL:-http://192.168.0.110:3001/wooo/awoooi/actions}}"
DURATION_SECONDS="${AWOOI_CICD_DURATION_SECONDS:-${AWOOOI_CICD_DURATION_SECONDS:-0}}"
SUMMARY="${AWOOI_CICD_SUMMARY:-${AWOOOI_CICD_SUMMARY:-}}"
payload_file="$(mktemp)"
trap 'rm -f "$payload_file"' EXIT
export JOB_NAME
export STATUS_RAW
export STAGE
export COMMIT_SHA
export TRIGGERED_BY
export WORKFLOW_URL
export DURATION_SECONDS
export SUMMARY
build_payload_with_python() {
python3 - <<'PY'
from __future__ import annotations
import datetime as dt
import json
import os
import re
status = (os.environ.get("STATUS_RAW") or "running").strip().lower()
if status not in {"running", "success", "failed", "pending"}:
status = "running"
severity = "info"
if status == "failed":
severity = "critical"
elif status == "pending":
severity = "warning"
stage = (os.environ.get("STAGE") or "ci").strip()[:40]
safe_stage = re.sub(r"[^A-Za-z0-9_]+", "_", stage).strip("_") or "ci"
alertname = f"CI_{safe_stage}_{status}"
payload = {
"version": "4",
"status": "firing",
"receiver": "awoooi-cicd",
"groupLabels": {"alertname": alertname},
"commonLabels": {"alertname": alertname, "severity": severity},
"commonAnnotations": {},
"externalURL": os.environ.get("WORKFLOW_URL", ""),
"alerts": [
{
"status": "firing",
"labels": {
"alertname": alertname,
"severity": severity,
"stage": stage,
"status": status,
"commit": os.environ.get("COMMIT_SHA", ""),
"triggered_by": os.environ.get("TRIGGERED_BY", "CI"),
"duration_seconds": os.environ.get("DURATION_SECONDS", "0"),
},
"annotations": {
"summary": os.environ.get("JOB_NAME", "CI/CD Pipeline"),
"description": os.environ.get("SUMMARY", ""),
"workflow_url": os.environ.get("WORKFLOW_URL", ""),
},
"startsAt": dt.datetime.now(dt.timezone.utc).isoformat().replace("+00:00", "Z"),
}
],
}
print(json.dumps(payload, ensure_ascii=False))
PY
}
build_payload_with_node() {
node <<'JS'
const statusCandidates = new Set(["running", "success", "failed", "pending"]);
let status = (process.env.STATUS_RAW || "running").trim().toLowerCase();
if (!statusCandidates.has(status)) {
status = "running";
}
let severity = "info";
if (status === "failed") {
severity = "critical";
} else if (status === "pending") {
severity = "warning";
}
const stage = (process.env.STAGE || "ci").trim().slice(0, 40);
const safeStage = stage.replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "ci";
const alertname = `CI_${safeStage}_${status}`;
const payload = {
version: "4",
status: "firing",
receiver: "awoooi-cicd",
groupLabels: { alertname },
commonLabels: { alertname, severity },
commonAnnotations: {},
externalURL: process.env.WORKFLOW_URL || "",
alerts: [
{
status: "firing",
labels: {
alertname,
severity,
stage,
status,
commit: process.env.COMMIT_SHA || "",
triggered_by: process.env.TRIGGERED_BY || "CI",
duration_seconds: process.env.DURATION_SECONDS || "0",
},
annotations: {
summary: process.env.JOB_NAME || "CI/CD Pipeline",
description: process.env.SUMMARY || "",
workflow_url: process.env.WORKFLOW_URL || "",
},
startsAt: new Date().toISOString(),
},
],
};
process.stdout.write(JSON.stringify(payload));
JS
}
if command -v python3 >/dev/null 2>&1; then
build_payload_with_python > "$payload_file"
elif command -v node >/dev/null 2>&1; then
build_payload_with_node > "$payload_file"
else
echo "python3 and node missing; cannot build Alertmanager JSON payload" >&2
exit 2
fi
if [ "${AWOOI_CICD_DRY_RUN:-${AWOOOI_CICD_DRY_RUN:-0}}" = "1" ]; then
cat "$payload_file"
exit 0
fi
curl -fsS \
--connect-timeout "${AWOOI_CICD_CONNECT_TIMEOUT:-5}" \
--max-time "${AWOOI_CICD_MAX_TIME:-12}" \
-H "Content-Type: application/json" \
--data-binary "@${payload_file}" \
"$ALERTMANAGER_URL" >/dev/null
echo "AwoooP-mirrored CI/CD notification sent via ${ALERTMANAGER_URL}"