Gitlab 代码审查模板
高级
这是一个AI Summarization, Multimodal AI领域的自动化工作流,包含 41 个节点。主要使用 If, Set, Code, Jira, Merge 等节点。 使用Gemini AI和JIRA上下文自动化GitLab合并请求代码审查
前置要求
- •HTTP Webhook 端点(n8n 会自动生成)
- •可能需要目标 API 的认证凭证
- •Google Gemini API Key
使用的节点 (41)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "Rwpn5OG2ql8rIOzH",
"meta": {
"instanceId": "ebde2b8e011b15f5db59a3b84e187c4795dbe1d4b2c695e9940aa4dbcd102f98",
"templateCredsSetupCompleted": true
},
"name": "Gitlab 代码审查模板",
"tags": [],
"nodes": [
{
"id": "c3fedf3c-ed52-49d7-b9d5-30050d4324f2",
"name": "需要审查",
"type": "n8n-nodes-base.if",
"position": [
-4256,
1260
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "617eb2c5-dd4b-4e28-b533-0c32ea6ca961",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.body.object_attributes.note }}",
"rightValue": "coro-bot-review"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d30412f1-f714-41cb-a867-3a45f202c378",
"name": "跳过文件更改",
"type": "n8n-nodes-base.if",
"position": [
-2016,
1408
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c6e1430b-84a7-47ce-8fe9-7b94da0f2d31",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.changes.renamed_file }}",
"rightValue": ""
},
{
"id": "bf6e9eb9-d72d-459c-a722-9614bab8842c",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.changes.deleted_file }}",
"rightValue": ""
},
{
"id": "03200577-a262-4f46-ad25-9c15b0c8146d",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.changes.diff }}",
"rightValue": "@@"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "17752d5e-75d2-43ff-8e1b-ff439e6329b8",
"name": "基础 LLM 链",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
-1344,
1104
],
"parameters": {
"text": "=First, consider the context from the associated JIRA ticket:\n------------\n{{ $json.jiraParentContext || $json.jiraContext || 'No JIRA context was provided.' }}\n------------\n\nFile path:{{ $('Skip File Changes').item.json.new_path }}\n\n```Original code\n {{ $json.originalCode }}\n```\nchange to\n```New code\n {{ $json.newCode }}\n```\nPlease review the code changes in this section:",
"messages": {
"messageValues": [
{
"message": "=You are an automated code review bot. Your primary goal is to identify high-value issues in code.\n\n**Instructions:**\n\n1. **Analysis Focus:** Concentrate only on business logic, correctness, security, and performance. Ignore style, naming, filenames, version bumps, and non-source files. Assume placeholders for yml files will be filled with correct values.\n2. **Output for Issues:** When you find an issue, begin your response with the prefix `🤖 **AI Review:** `. Follow it with a concise, actionable explanation. Prefer one-liners that are immediately actionable - what or where or why and how to fix.\n3. **Output for No Issues:** If your analysis finds **zero** issues worth reporting, your **ENTIRE** response must be the single keyword: `ALL_CLEAR`. Do not add any other text or explanation.\n4. ** Findings to ignore in yaml files:**\n - Ignore if a value for vaultSecretPath in a values file or a yaml contains a double slash (//)\n - Ignore errors where tag appears to be very or too specific\n\n**Important Rules:**\n\n* NEVER write praise, summaries, or conversational phrases like \"I have no findings.\"\n* If you find issues, start every comment with the `🤖 **AI Review:** ` prefix.\n* If you find no issues, don't output anything."
}
]
},
"promptType": "define"
},
"typeVersion": 1.5
},
{
"id": "483ec727-0b0b-46a7-9bd9-fbd52f2bb51a",
"name": "Google Gemini 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-1272,
1328
],
"parameters": {
"options": {
"topK": 1,
"temperature": 0
},
"modelName": "models/gemini-2.5-pro"
},
"credentials": {
"googlePalmApi": {
"id": "GeKFUmcR07GOvVpv",
"name": "Google Gemini(PaLM) Api account 2"
}
},
"typeVersion": 1
},
{
"id": "06884594-3ad3-4329-b357-21359eb13503",
"name": "提取 JIRA 问题ID",
"type": "n8n-nodes-base.code",
"position": [
-3584,
1304
],
"parameters": {
"jsCode": "// Get the MR description from the previous node's input\nconst description = $input.first().json.description\n// Regex to find a JIRA issue key (e.g., PROJ-123).\n// The \\b ensures it matches a whole word.\nconst jiraRegex = /\\b([A-Z]+-\\d+)\\b/;\nconst match = description.match(jiraRegex);\n\n// If a key is found, return it.\nif (match && match[0]) {\n // We name the output 'jiraIssueKey' for clarity.\n return [{\n json: {\n jiraIssueKey: match[0]\n }\n }];\n} else {\n // Return an empty array to stop this path if no key is found.\n return [];\n}"
},
"typeVersion": 2
},
{
"id": "24204fee-6c47-4026-a6a6-12ced75a49da",
"name": "获取 JIRA 问题",
"type": "n8n-nodes-base.jira",
"position": [
-3360,
1304
],
"parameters": {
"issueKey": "={{ $json.jiraIssueKey }}",
"operation": "get",
"additionalFields": {}
},
"credentials": {
"jiraSoftwareCloudApi": {
"id": "T58uHg2XK8A2NA7s",
"name": "Jira SW Cloud account"
}
},
"typeVersion": 1
},
{
"id": "7b1da623-5452-4783-ba8f-77896d3c8ea9",
"name": "格式化 JIRA 上下文",
"type": "n8n-nodes-base.set",
"position": [
-2688,
1452
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "59f4091a-0260-4f24-aa8d-c211f7c243e2",
"name": "jiraContext",
"type": "string",
"value": "=JIRA Ticket Context: \nTitle: {{ $json.fields.summary }} \nType: {{ $json.fields.issuetype.name }} \nDescription: {{ $json.fields.description }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "2ac7ced8-60b5-4fab-902f-bd1360e41a3a",
"name": "提取 MR 详情",
"type": "n8n-nodes-base.set",
"position": [
-3808,
1356
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "59f4091a-0260-4f24-aa8d-c211f7c243e2",
"name": "projectId",
"type": "string",
"value": "={{ $json.body.project_id }}"
},
{
"id": "cc5bdd4b-812f-461d-b3a9-059994176291",
"name": "iid",
"type": "string",
"value": "={{ $json.body.merge_request.iid }}"
},
{
"id": "7afeacf0-888f-4e75-be3c-d024cd223e3b",
"name": "description",
"type": "string",
"value": "={{ $json.body.merge_request.description }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9aeed83e-1f0b-461a-8e2b-75efb7be5ca5",
"name": "如果是 JIRA 子任务",
"type": "n8n-nodes-base.if",
"position": [
-3136,
1260
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "5338bc5b-9f30-4b66-b6a2-5b85dc012765",
"operator": {
"type": "object",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.fields.parent }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "bf6f14f1-b684-4100-9085-f97399c8911f",
"name": "获取 JIRA 父问题",
"type": "n8n-nodes-base.jira",
"position": [
-2912,
1260
],
"parameters": {
"issueKey": "={{ $json.fields.parent.key }}",
"operation": "get",
"additionalFields": {}
},
"credentials": {
"jiraSoftwareCloudApi": {
"id": "T58uHg2XK8A2NA7s",
"name": "Jira SW Cloud account"
}
},
"typeVersion": 1
},
{
"id": "5e547d2f-c978-42bc-acb2-25c194308154",
"name": "格式化 JIRA 父上下文",
"type": "n8n-nodes-base.set",
"position": [
-2688,
1260
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "59f4091a-0260-4f24-aa8d-c211f7c243e2",
"name": "jiraParentContext",
"type": "string",
"value": "=JIRA Parent Ticket Context: \nTitle: {{ $json.fields.summary }} \nType: {{ $json.fields.issuetype.name }} \nDescription: {{ $json.fields.description }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "d5e3ffd7-03d0-4b54-ab34-67fe43830531",
"name": "合并",
"type": "n8n-nodes-base.merge",
"position": [
-2464,
1392
],
"parameters": {
"mode": "combine",
"options": {
"includeUnpaired": true
},
"combineBy": "combineByPosition",
"numberInputs": 3
},
"typeVersion": 3.2
},
{
"id": "a49bf76b-1a4b-4aba-b392-419ddc07e110",
"name": "获取 MR 变更",
"type": "n8n-nodes-base.httpRequest",
"position": [
-2688,
1644
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.projectId }}/merge_requests/{{ $json.iid }}/changes",
"options": {},
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "8a3beea4-640b-4ddc-a801-719ace2643d0",
"name": "准备代码变更",
"type": "n8n-nodes-base.code",
"position": [
-1568,
1408
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nvar diff = $input.item.json.gitDiff\n\nlet lines = diff.trimEnd().split('\\n');\n\nlet originalCode = '';\nlet newCode = '';\n\nlines.forEach(line => {\n console.log(line)\n if (line.startsWith('-')) {\n originalCode += line + \"\\n\";\n } else if (line.startsWith('+')) {\n newCode += line + \"\\n\";\n } else {\n originalCode += line + \"\\n\";\n newCode += line + \"\\n\";\n }\n});\n\nreturn { ...$json, originalCode, newCode };\n\n"
},
"typeVersion": 2
},
{
"id": "057832e9-fa3b-4fe5-a561-78b69e60c813",
"name": "错误触发器",
"type": "n8n-nodes-base.errorTrigger",
"position": [
352,
1692
],
"parameters": {},
"executeOnce": false,
"retryOnFail": false,
"typeVersion": 1,
"alwaysOutputData": false
},
{
"id": "aeba4982-b0fc-4d97-a06b-35b559135361",
"name": "聚合",
"type": "n8n-nodes-base.aggregate",
"position": [
-768,
1408
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "8ff7eb74-fbcc-4d4f-8b53-50ed4d543a82",
"name": "合并 LLM 输出与输入",
"type": "n8n-nodes-base.merge",
"position": [
-992,
1408
],
"parameters": {
"mode": "combine",
"options": {},
"combineBy": "combineByPosition"
},
"typeVersion": 3.2
},
{
"id": "39f6aa6b-3296-47e6-b71d-59bcc7efd34c",
"name": "过滤不相关字段",
"type": "n8n-nodes-base.set",
"position": [
-1280,
1504
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "f40092dc-5c3a-4882-b33c-29e8c50f90a6",
"name": "iid",
"type": "string",
"value": "={{$json.iid}}"
},
{
"id": "38bd9645-0f83-4b66-9850-403e675a360d",
"name": "project_id",
"type": "string",
"value": "={{$json.project_id}}"
},
{
"id": "6b432472-ad72-4eaf-977d-9b2c80cbe2bf",
"name": "diff_refs",
"type": "object",
"value": "={{$json.diff_refs}}"
},
{
"id": "d24732f4-3f12-4b77-8df1-f34edb0d7f4d",
"name": "lastNewLine",
"type": "string",
"value": "={{ $json.lastNewLine }}"
},
{
"id": "4baecc19-56b2-472e-a015-bfc2e36727ce",
"name": "lastOldLine",
"type": "string",
"value": "={{ $json.lastOldLine }}"
},
{
"id": "12489e32-3521-4fd1-af78-dcaaba028ee1",
"name": "new_path",
"type": "string",
"value": "={{ $json.changes.new_path }}"
},
{
"id": "602b5de5-aeab-43bf-8ccb-2fce3853278c",
"name": "old_path",
"type": "string",
"value": "={{ $json.changes.old_path }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "ebe94dfb-7395-4788-896d-14c3d5380c18",
"name": "发现任何问题?",
"type": "n8n-nodes-base.if",
"position": [
-320,
1408
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "70dd215a-813b-4bcf-9fa6-db4581ccad77",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.noIssuesFound }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "21e1a59a-3af6-45ba-83d8-73260736b92a",
"name": "分离变更",
"type": "n8n-nodes-base.splitOut",
"position": [
-2240,
1408
],
"parameters": {
"include": "selectedOtherFields",
"options": {
"includeBinary": true
},
"fieldToSplitOut": "changes",
"fieldsToInclude": "jiraParentContext, jiraContext,iid,project_id,diff_refs"
},
"typeVersion": 1
},
{
"id": "43acb79d-02c5-406b-9ae0-288e365518fa",
"name": "准备请求",
"type": "n8n-nodes-base.splitOut",
"position": [
-96,
1428
],
"parameters": {
"include": "selectedOtherFields",
"options": {
"includeBinary": true
},
"fieldToSplitOut": "commentsToPost",
"fieldsToInclude": "iid,project_id,diff_refs"
},
"typeVersion": 1
},
{
"id": "95e75bb0-94c4-492d-af8f-e6d79f442d92",
"name": "准备无位置请求",
"type": "n8n-nodes-base.code",
"position": [
128,
1428
],
"parameters": {
"jsCode": "const item = $input.first().json;\n\n// Reference the nested 'commentsToPost' object\nconst postData = item.commentsToPost;\n\n// Create the nested position object\nconst position = {\n position_type: 'text',\n old_path: postData.old_path,\n new_path: postData.new_path,\n base_sha: postData.diff_refs.base_sha,\n start_sha: postData.diff_refs.start_sha,\n head_sha: postData.diff_refs.head_sha,\n};\n\n// Conditionally add the line numbers to the nested position object\nif (postData.lastNewLine !== null && postData.lastNewLine !== '') {\n position.new_line = parseInt(postData.lastNewLine, 10);\n}\nif (postData.lastOldLine !== null && postData.lastOldLine !== '') {\n position.old_line = parseInt(postData.lastOldLine, 10);\n}\n\n// Build the final request body with the nested 'position' key\nconst requestBody = {\n body: postData.text,\n position: position,\n};\n\n// Attach the final body for the next node\nitem.requestBody = requestBody;\n\nreturn item;"
},
"typeVersion": 2
},
{
"id": "4e2ab9f1-0b12-4a25-8f2c-981500889660",
"name": "设置工作流执行信息",
"type": "n8n-nodes-base.code",
"position": [
576,
1500
],
"parameters": {
"jsCode": "const item = $input.first().json;\n\n// Reference the nested 'commentsToPost' object\nconst postData = item.commentsToPost;\n\n// Build the final request body with the nested 'position' key\nconst requestBody = {\n body: postData.text,\n};\n\n// Attach the final body for the next node\nitem.requestBody = requestBody;\n\nreturn item;"
},
"typeVersion": 2
},
{
"id": "975691b1-9667-4913-aa56-bc177e202dae",
"name": "发布审查开始",
"type": "n8n-nodes-base.code",
"position": [
-4032,
1260
],
"parameters": {
"jsCode": "// initialize staticData object\nconst workflowStaticData = $getWorkflowStaticData('global');\nconst executionId = $execution.id\nconst projectId = $input.first().json[\"body\"][\"project_id\"]\nconst mrId = $input.first().json[\"body\"][\"merge_request\"][\"iid\"]\n\nworkflowStaticData[executionId] = {\"projectId\":projectId, \"mrId\": mrId}\n\nreturn $input.all();"
},
"typeVersion": 2
},
{
"id": "a24362b0-e288-47af-9756-eff4acde1682",
"name": "监听 Gitlab 评论",
"type": "n8n-nodes-base.httpRequest",
"position": [
-3808,
1164
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.body.project_id }}/merge_requests/{{ $json.body.merge_request.iid }}/notes",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "body",
"value": "🤖 AI code review initiated. This may take up to 30 minutes for large merge requests. I'll post my findings as comments on the relevant files."
}
]
},
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "81762b68-7a5d-4f03-8479-c209d2696970",
"name": "解析差异",
"type": "n8n-nodes-base.webhook",
"position": [
-4480,
1260
],
"webhookId": "REPLACE_WITH_UNIQUE_ID",
"parameters": {
"path": "REPLACE_WITH_UNIQUE_PATH",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2
},
{
"id": "7ed4ec35-2b23-4b97-ba7d-f434ff54b93c",
"name": "发布未发现问题",
"type": "n8n-nodes-base.code",
"position": [
-1792,
1408
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const parseLastDiff = (gitDiff) => {\n gitDiff = gitDiff.replace(/\\n\\\\ No newline at end of file/, '')\n \n const diffList = gitDiff.trimEnd().split('\\n').reverse();\n const lastLineFirstChar = diffList?.[0]?.[0];\n const lastDiff =\n diffList.find((item) => {\n return /^@@ \\-\\d+,\\d+ \\+\\d+,\\d+ @@/g.test(item);\n }) || '';\n\n const [lastOldLineCount, lastNewLineCount] = lastDiff\n .replace(/@@ \\-(\\d+),(\\d+) \\+(\\d+),(\\d+) @@.*/g, ($0, $1, $2, $3, $4) => {\n return `${+$1 + +$2},${+$3 + +$4}`;\n })\n .split(',');\n \n if (!/^\\d+$/.test(lastOldLineCount) || !/^\\d+$/.test(lastNewLineCount)) {\n return {\n lastOldLine: -1,\n lastNewLine: -1,\n gitDiff,\n };\n }\n\n\n const lastOldLine = lastLineFirstChar === '+' ? null : (parseInt(lastOldLineCount) || 0) - 1;\n const lastNewLine = lastLineFirstChar === '-' ? null : (parseInt(lastNewLineCount) || 0) - 1;\n\n return {\n lastOldLine,\n lastNewLine,\n gitDiff,\n };\n};\n\nconst extra = parseLastDiff($json.changes.diff);\nreturn { ...$json, ...extra };"
},
"typeVersion": 2
},
{
"id": "601bc26b-1349-499c-a4eb-f08e3a064503",
"name": "发布发生错误",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
1212
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.projectId }}/merge_requests/{{ $json.mrId }}/notes",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "body",
"value": "=🤖 AI review complete. No significant issues were found. LGTM!"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "aa200c64-05c9-4437-8f18-980642e4ec6c",
"name": "获取包含错误的静态上下文",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
1692
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.projectId }}/merge_requests/{{ $json.mrId }}/notes",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"bodyParameters": {
"parameters": [
{
"name": "body",
"value": "=🤖 An error occurred during the code review: {{ $json.error }}. Please trigger the review again."
}
]
},
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "e108c8b4-e8bb-4c43-aa01-0aa2cb70e83c",
"name": "获取静态上下文",
"type": "n8n-nodes-base.code",
"position": [
576,
1692
],
"parameters": {
"jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\nconst executionId = $input.first().json.execution.id;\nconst errorMessage = $input.first().json.execution.error.message;\n\nreturn {...workflowStaticData[executionId], error: errorMessage};"
},
"typeVersion": 2
},
{
"id": "1afcd3cf-8d54-4e11-8518-a82f246023ec",
"name": "清理静态上下文",
"type": "n8n-nodes-base.code",
"position": [
576,
1212
],
"parameters": {
"jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\nconst executionId = $execution.id;\nreturn workflowStaticData[executionId];"
},
"typeVersion": 2
},
{
"id": "21c6891d-1a57-4c4b-b7c4-41d84b20b744",
"name": "处理评论",
"type": "n8n-nodes-base.code",
"position": [
1024,
1504
],
"parameters": {
"jsCode": "const workflowStaticData = $getWorkflowStaticData('global');\nconst executionId = $execution.id;\ndelete workflowStaticData[executionId];\nreturn [];"
},
"typeVersion": 2
},
{
"id": "1d97e536-a1c5-4520-a078-fb06baa377c4",
"name": "发布 Gitlab MR 评论",
"type": "n8n-nodes-base.code",
"position": [
-544,
1408
],
"parameters": {
"jsCode": "const allItems = $input.first().json.data;\n\n// Filter for items that have actual review text\nconst commentsToPost = allItems.filter(item => {\n const text = item.text || '';\n const isNotEmpty = text.trim() !== '';\n const isNotClear = !text.includes('ALL_CLEAR');\n const isNotNoFindings = !text.toLowerCase().includes('no findings');\n const isNotNoIssues = !text.toLowerCase().includes('no issues found');\n return isNotEmpty && isNotClear && isNotNoFindings && isNotNoIssues;\n});\n\nreturn [{\n json: {\n commentsToPost: commentsToPost,\n noIssuesFound: commentsToPost.length === 0\n }\n}];"
},
"typeVersion": 2
},
{
"id": "db40d370-1216-4f36-9d87-86f26524e4cd",
"name": "试试看!",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
352,
1428
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.commentsToPost.project_id }}/merge_requests/{{ $json.commentsToPost.iid }}/discussions",
"method": "POST",
"options": {},
"jsonBody": "={{ $json.requestBody }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"retryOnFail": false,
"typeVersion": 4.2
},
{
"id": "eca87aa8-3d57-4513-a2d0-98d8cfcd1174",
"name": "### ⭐️ 试试看!",
"type": "n8n-nodes-base.stickyNote",
"position": [
-5264,
1072
],
"parameters": {
"color": 6,
"width": 640,
"height": 288,
"content": "步骤 1:监听和捕获"
},
"typeVersion": 1
},
{
"id": "9bf7c660-9b1d-430c-95e9-37e89aae852d",
"name": "### 🟢 步骤 1:监听和捕获",
"type": "n8n-nodes-base.stickyNote",
"position": [
-4480,
1488
],
"parameters": {
"color": 2,
"width": 600,
"height": 232,
"content": "步骤 2:准备和审查"
},
"typeVersion": 1
},
{
"id": "f2e6745f-cb17-4d0c-a5c9-c3031759100a",
"name": "### 🟣 步骤 2:准备和审查",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2432,
960
],
"parameters": {
"color": 4,
"width": 600,
"height": 280,
"content": "步骤 3:发布和回退"
},
"typeVersion": 1
},
{
"id": "1bd4a994-6826-4b49-87a8-9214508b94c8",
"name": "### 🟠 步骤 3:发布和回退",
"type": "n8n-nodes-base.stickyNote",
"position": [
1232,
1456
],
"parameters": {
"color": 5,
"width": 600,
"height": 184,
"content": "静态上下文和错误处理"
},
"typeVersion": 1
},
{
"id": "2d50734d-8c63-4a52-8459-2719710ca2a6",
"name": "### 🔵 静态上下文和错误处理",
"type": "n8n-nodes-base.stickyNote",
"position": [
-96,
1904
],
"parameters": {
"width": 600,
"height": 216,
"content": "需要帮助和自定义"
},
"typeVersion": 1
},
{
"id": "223b57bd-6ea3-4e32-ad29-9fec88550b1b",
"name": "### 🟡 需要帮助和自定义",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1504,
1744
],
"parameters": {
"color": 7,
"width": 600,
"height": 168,
"content": "发布无位置 Gitlab MR 评论"
},
"typeVersion": 1
},
{
"id": "917539f7-c7a2-48a4-9227-93287eeeded9",
"name": "Post Gitlab MR Comments WIthout Position",
"type": "n8n-nodes-base.httpRequest",
"position": [
800,
1500
],
"parameters": {
"url": "=https://gitlab.com/api/v4/projects/{{ $json.commentsToPost.project_id }}/merge_requests/{{ $json.commentsToPost.iid }}/discussions",
"method": "POST",
"options": {},
"jsonBody": "={{ $json.requestBody }}",
"sendBody": true,
"sendHeaders": true,
"specifyBody": "json",
"headerParameters": {
"parameters": [
{
"name": "PRIVATE-TOKEN",
"value": "={{$env.GITLAB_TOKEN}}"
}
]
}
},
"retryOnFail": false,
"typeVersion": 4.2
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "0798cf1c-bb7b-4765-bf7e-7dead605266f",
"connections": {
"Merge": {
"main": [
[
{
"node": "Split Out Changes",
"type": "main",
"index": 0
}
]
]
},
"Aggregate": {
"main": [
[
{
"node": "Process Comments",
"type": "main",
"index": 0
}
]
]
},
"Parse Diff": {
"main": [
[
{
"node": "Prepare Code Changes",
"type": "main",
"index": 0
}
]
]
},
"Need Review": {
"main": [
[
{
"node": "Set workflow execution information",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Get Static Context Including Error",
"type": "main",
"index": 0
}
]
]
},
"Get JIRA issue": {
"main": [
[
{
"node": "Format JIRA Context",
"type": "main",
"index": 0
},
{
"node": "If JIRA Subtask",
"type": "main",
"index": 0
}
]
]
},
"Get MR Changes": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 2
}
]
]
},
"Basic LLM Chain": {
"main": [
[
{
"node": "Merge LLM Output with Input",
"type": "main",
"index": 0
}
]
]
},
"If JIRA Subtask": {
"main": [
[
{
"node": "Get JIRA Parent Issue",
"type": "main",
"index": 0
}
]
]
},
"Prepare Request": {
"main": [
[
{
"node": "Post Gitlab MR Comments",
"type": "main",
"index": 0
}
]
]
},
"Process Comments": {
"main": [
[
{
"node": "Any Issues Found?",
"type": "main",
"index": 0
}
]
]
},
"Any Issues Found?": {
"main": [
[
{
"node": "Get Static Context",
"type": "main",
"index": 0
}
],
[
{
"node": "Split Out Comments",
"type": "main",
"index": 0
}
]
]
},
"Skip File Changes": {
"main": [
[
{
"node": "Parse Diff",
"type": "main",
"index": 0
}
]
]
},
"Split Out Changes": {
"main": [
[
{
"node": "Skip File Changes",
"type": "main",
"index": 0
}
]
]
},
"Extract MR Details": {
"main": [
[
{
"node": "Get MR Changes",
"type": "main",
"index": 0
},
{
"node": "Extract the JIRA Issue ID",
"type": "main",
"index": 0
}
]
]
},
"Get Static Context": {
"main": [
[
{
"node": "Post No Issues Found",
"type": "main",
"index": 0
}
]
]
},
"Split Out Comments": {
"main": [
[
{
"node": "Prepare Request",
"type": "main",
"index": 0
}
]
]
},
"Format JIRA Context": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Post Error Occurred": {
"main": [
[
{
"node": "Cleanup Static Context",
"type": "main",
"index": 0
}
]
]
},
"Post No Issues Found": {
"main": [
[
{
"node": "Cleanup Static Context",
"type": "main",
"index": 0
}
]
]
},
"Prepare Code Changes": {
"main": [
[
{
"node": "Basic LLM Chain",
"type": "main",
"index": 0
},
{
"node": "Filter Irrelevant Fields",
"type": "main",
"index": 0
}
]
]
},
"Get JIRA Parent Issue": {
"main": [
[
{
"node": "Format JIRA Parent Context",
"type": "main",
"index": 0
}
]
]
},
"Post Gitlab MR Comments": {
"main": [
[
{
"node": "Cleanup Static Context",
"type": "main",
"index": 0
}
],
[
{
"node": "Prepare Request Without Position",
"type": "main",
"index": 0
}
]
]
},
"Filter Irrelevant Fields": {
"main": [
[
{
"node": "Merge LLM Output with Input",
"type": "main",
"index": 1
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "Basic LLM Chain",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Extract the JIRA Issue ID": {
"main": [
[
{
"node": "Get JIRA issue",
"type": "main",
"index": 0
}
]
]
},
"Format JIRA Parent Context": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Listen For Gitlab Comments": {
"main": [
[
{
"node": "Need Review",
"type": "main",
"index": 0
}
]
]
},
"Merge LLM Output with Input": {
"main": [
[
{
"node": "Aggregate",
"type": "main",
"index": 0
}
]
]
},
"Prepare Request Without Position": {
"main": [
[
{
"node": "Post Gitlab MR Comments WIthout Position",
"type": "main",
"index": 0
}
]
]
},
"Get Static Context Including Error": {
"main": [
[
{
"node": "Post Error Occurred",
"type": "main",
"index": 0
}
]
]
},
"Set workflow execution information": {
"main": [
[
{
"node": "Post Review Started",
"type": "main",
"index": 0
},
{
"node": "Extract MR Details",
"type": "main",
"index": 0
}
]
]
},
"Post Gitlab MR Comments WIthout Position": {
"main": [
[
{
"node": "Cleanup Static Context",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - AI 摘要总结, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
每日 WhatsApp 群组智能分析:GPT-4.1 分析与语音消息转录
If
Set
Code
+20
52 节点Daniel Lianes
杂项
基于AI的会议研究与每日议程(Google日历、Attio CRM和Slack)
基于AI的会议研究与每日议程:使用Google日历、Attio CRM和Slack
If
Set
Code
+15
30 节点Harry Siggins
AI 摘要总结
01 使用AI媒体买家分析Facebook广告表现并将洞察发送到Google Sheets
使用Gemini AI分析Facebook广告并将洞察发送到Google Sheets
If
Set
Code
+13
34 节点JJ Tham
市场调研
选题捕手模板
使用Gemini分析Reddit、YouTube和X生成内容策略报告
If
Set
Code
+14
34 节点Sheryl
市场调研
WordPress SEO发布器
集成Anthropic AI、Google Docs和媒体自动化的WordPress SEO发布器
Set
Code
Merge
+12
41 节点Cong Nguyen
内容创作
竞争对手内容差距分析器:自动化网站主题映射
使用Gemini AI、Apify和Google Sheets分析竞争对手内容差距
If
Set
Code
+10
30 节点Mychel Garzon
杂项