{ "name": "CI/CD Pipeline 通知", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "gitlab-webhook", "options": {} }, "id": "webhook-trigger", "name": "GitLab Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 1.1, "position": [0, 0], "webhookId": "gitlab-pipeline-webhook" }, { "parameters": { "jsCode": "// 解析 GitLab Pipeline Webhook\nconst data = $input.first().json;\nconst body = data.body || data;\n\n// 確認是 Pipeline 事件\nif (body.object_kind !== 'pipeline') {\n return [{ json: { skip: true, reason: 'Not a pipeline event' } }];\n}\n\nconst pipeline = body.object_attributes || {};\nconst project = body.project || {};\nconst user = body.user || {};\nconst commit = body.commit || {};\n\nconst status = pipeline.status || 'unknown';\n\n// 只處理最終狀態\nif (!['success', 'failed', 'canceled'].includes(status)) {\n return [{ json: { skip: true, reason: 'Skipping status: ' + status } }];\n}\n\nconst statusEmoji = {\n 'success': '✅',\n 'failed': '❌',\n 'canceled': '🚫'\n};\n\nconst duration = pipeline.duration || 0;\nconst minutes = Math.floor(duration / 60);\nconst seconds = duration % 60;\n\nconst emoji = statusEmoji[status] || '❓';\nconst projectName = project.name || project.path_with_namespace || 'Unknown';\nconst branch = pipeline.ref || 'N/A';\nconst pipelineId = pipeline.id || 'N/A';\nconst pipelineUrl = project.web_url ? project.web_url + '/-/pipelines/' + pipeline.id : 'N/A';\nconst commitMsg = commit.message ? commit.message.split('\\n')[0].substring(0, 50) : (pipeline.sha ? pipeline.sha.substring(0, 8) : 'N/A');\nconst author = (commit.author && commit.author.name) || user.name || user.username || 'Unknown';\nconst durationStr = minutes + 'm ' + seconds + 's';\n\n// 組合訊息文字\nconst text = emoji + ' *CI/CD Pipeline ' + status.toUpperCase() + '*\\n\\n' +\n '📦 專案: ' + projectName + '\\n' +\n '🌿 分支: ' + branch + '\\n' +\n '🆔 Pipeline: #' + pipelineId + '\\n' +\n '💬 Commit: ' + commitMsg + '\\n' +\n '👤 作者: ' + author + '\\n' +\n '⏱️ 耗時: ' + durationStr + '\\n\\n' +\n '🔗 [查看詳情](' + pipelineUrl + ')';\n\nreturn [{\n json: {\n skip: false,\n telegramBody: {\n chat_id: '5619078117',\n text: text,\n parse_mode: 'Markdown',\n disable_web_page_preview: true\n }\n }\n}];" }, "id": "code-parse", "name": "解析 Pipeline 事件", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [220, 0] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "condition-1", "leftValue": "={{ $json.skip }}", "rightValue": false, "operator": { "type": "boolean", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "id": "if-pipeline", "name": "是 Pipeline 事件?", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [440, 0] }, { "parameters": { "method": "POST", "url": "https://api.telegram.org/bot8075645931:AAH-EGKMo8ZC4QJs-Nc1_0s92xHrGdQvdpg/sendMessage", "sendBody": true, "specifyBody": "json", "jsonBody": "={{ JSON.stringify($json.telegramBody) }}", "options": {} }, "id": "telegram-notify", "name": "發送 Telegram 通知", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.1, "position": [660, -100] }, { "parameters": {}, "id": "no-op", "name": "忽略非 Pipeline 事件", "type": "n8n-nodes-base.noOp", "typeVersion": 1, "position": [660, 100] } ], "connections": { "GitLab Webhook": { "main": [ [ { "node": "解析 Pipeline 事件", "type": "main", "index": 0 } ] ] }, "解析 Pipeline 事件": { "main": [ [ { "node": "是 Pipeline 事件?", "type": "main", "index": 0 } ] ] }, "是 Pipeline 事件?": { "main": [ [ { "node": "發送 Telegram 通知", "type": "main", "index": 0 } ], [ { "node": "忽略非 Pipeline 事件", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" } }