#!/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}"