8
n8n 中文网amn8n.com

客户感知工作流备份 (n8n + GitLab)

高级

这是一个DevOps, Multimodal AI领域的自动化工作流,包含 24 个节点。主要使用 If, N8n, Set, Code, Merge 等节点。 在GitLab中版本控制n8n工作流,支持客户标签组织

前置要求
  • GitLab Personal Access Token
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
  "id": "lqAMFCGhYpl6i0Kg",
  "meta": {
    "instanceId": "349b88c12bdc8f9e6e74ffcb3e46eb3d44a721bf354e94b04baaf67413d41cbb",
    "templateCredsSetupCompleted": true
  },
  "name": "客户感知工作流备份 (n8n + GitLab)",
  "tags": [
    {
      "id": "U9GFvr98FHfV6LSA",
      "name": "backup-workflows",
      "createdAt": "2025-08-20T16:32:01.267Z",
      "updatedAt": "2025-08-21T19:09:58.119Z"
    }
  ],
  "nodes": [
    {
      "id": "2aaa2725-24b6-46bb-9f9e-153049095183",
      "name": "当点击\"执行工作流\"时",
      "type": "n8n-nodes-base.manualTrigger",
      "notes": "Manual trigger for testing the workflow execution.",
      "position": [
        -1136,
        -128
      ],
      "parameters": {},
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "a6a535bb-a39c-43e7-8121-16187772dacd",
      "name": "定时触发器",
      "type": "n8n-nodes-base.scheduleTrigger",
      "notes": "Runs the workflow daily at 03:00 (server time).",
      "position": [
        -1120,
        64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 3
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 1.2
    },
    {
      "id": "da551fd3-0e10-47f8-8325-5ca0b7bd375d",
      "name": "准备 UI 兼容导出的工作流 JSON",
      "type": "n8n-nodes-base.code",
      "notes": "Cleans and normalizes workflow JSON to match n8n export format (only required fields).",
      "position": [
        1056,
        32
      ],
      "parameters": {
        "jsCode": "// ---------------------------------------------------------------------------\n// n8n Code Node - Prepare Workflow JSON for UI-Compatible Export\n// ---------------------------------------------------------------------------\n//\n// GOAL: Produce an output *identical* to the workflow JSON downloaded from\n// the n8n UI → Same fields, same structure, same order.\n// ---------------------------------------------------------------------------\n\nreturn $input.all().map(item => {\n    const w = item.json;\n\n    // Keep exactly the fields that appear in a native n8n export\n    // And ensure they are in the correct order\n    const cleaned = {\n        name: w.name,                        // Workflow name\n        nodes: w.nodes || [],               // Workflow nodes\n        pinData: w.pinData || {},           // Pinned node data (empty if not set)\n        connections: w.connections || {},   // Workflow connections\n        active: w.active ?? false,          // Default false like exported UI\n        settings: w.settings || {},         // Workflow-level settings\n        versionId: w.versionId || \"\",       // Keep version ID if present\n        meta: w.meta || {},                 // Additional meta info\n        id: w.id,                           // Workflow unique ID\n        tags: w.tags || []                  // Array of tags\n    };\n\n    // Return the cleaned JSON, ready for export or GitLab storage\n    return {\n        json: cleaned\n    };\n});"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "092317f4-3c1e-4c9b-af35-fdeabc9e578f",
      "name": "清理和规范化工作流名称",
      "type": "n8n-nodes-base.code",
      "notes": "Cleans and normalizes workflow name: applies customer tag (uppercase) or removes it if missing.",
      "position": [
        800,
        32
      ],
      "parameters": {
        "jsCode": "// ---------------------------------------------------------------------------\n// n8n Code Node - Clean & Normalize Workflow Name\n// ---------------------------------------------------------------------------\n//\n// GOAL: Standardize workflow names by properly formatting [customer] tags.\n//\n// - Detects any existing [customer] tags in the name.\n// - If a customer value exists → Normalize to `[customer : NAME]`.\n// - If the tag exists but is empty → Remove it completely.\n// - If no tag is present → Leave the name unchanged.\n//\n// Output structure matches the original item, only the `name` is updated.\n// ---------------------------------------------------------------------------\n\nreturn $input.all().map(item => {\n    const w = item.json;\n\n    // Regex to match patterns like:\n    // [customerXYZ], [customer: XYZ], [customer : xyz], [customer xyz]\n    // Also matches empty tags: [customer], [customer:], [customer : ]\n    const customerTag = /\\[customer\\s*:?\\s*([^\\]\\r\\n]*)\\]/i;\n\n    let name = String(w.name || \"\").trim();\n    const match = name.match(customerTag);\n\n    if (match) {\n        // Extract raw customer value from the tag\n        const rawCustomer = match[1] ? match[1].trim() : \"\";\n\n        if (rawCustomer) {\n            // Normalize customer name to uppercase\n            const customerName = rawCustomer.toUpperCase();\n\n            // Remove the original tag completely\n            name = name.replace(customerTag, \"\").trim();\n\n            // Rebuild the name with the normalized format\n            name = `[customer : ${customerName}] ${name}`;\n        } else {\n            // If tag exists but has no value → remove it entirely\n            name = name.replace(customerTag, \"\").trim();\n        }\n    }\n\n    // Return the updated workflow JSON (only name is modified)\n    return {\n        json: {\n            ...w,\n            name\n        }\n    };\n});"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "4bed4024-392c-4027-907c-0f534dea3466",
      "name": "便签",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -640
      ],
      "parameters": {
        "width": 912,
        "height": 912,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "91eb911b-8a50-4db7-b987-c79ee6cc6e67",
      "name": "便签 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -240,
        -640
      ],
      "parameters": {
        "color": 4,
        "width": 806,
        "height": 912,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "33a61637-4c62-4349-8a55-115ca7b5adbc",
      "name": "便签 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1264,
        -640
      ],
      "parameters": {
        "color": 6,
        "width": 934,
        "height": 912,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "a8d0f8cc-70c5-4713-bb03-8d219feedbae",
      "name": "便签6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1664,
        -1648
      ],
      "parameters": {
        "color": 4,
        "width": 896,
        "height": 1920,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "a0718c04-0981-472d-86f1-d96412dc4b79",
      "name": "从 n8n 获取工作流",
      "type": "n8n-nodes-base.n8n",
      "notes": "Fetches only workflows tagged \"backup-workflows\" via n8n API.",
      "position": [
        112,
        -32
      ],
      "parameters": {
        "filters": {
          "tags": "={{ $json.tag_backup }}"
        },
        "requestOptions": {}
      },
      "credentials": {
        "n8nApi": {
          "id": "NKNI2VBN5i19fFpj",
          "name": "n8n-api-ainexusone"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "79f360ed-86cc-40fe-a105-b3ef23120e97",
      "name": "从 GitLab 获取现有文件",
      "type": "n8n-nodes-base.gitlab",
      "notes": "Fetches the existing workflow backup file from GitLab.",
      "onError": "continueErrorOutput",
      "position": [
        1824,
        -32
      ],
      "parameters": {
        "owner": "={{ $('Set Global GitLab Variables').item.json.gitlab_owner }}",
        "filePath": "={{ $json.gitlab_file_path }}",
        "resource": "file",
        "operation": "get",
        "repository": "={{ $('Set Global GitLab Variables').item.json.gitlab_project }}",
        "asBinaryProperty": false,
        "additionalParameters": {
          "reference": "={{ $('Set Global GitLab Variables').item.json.gitlab_branch }}"
        }
      },
      "credentials": {
        "gitlabApi": {
          "id": "3xJQUM2wS07heXvB",
          "name": "GitLab account"
        }
      },
      "executeOnce": false,
      "notesInFlow": true,
      "retryOnFail": false,
      "typeVersion": 1,
      "alwaysOutputData": false
    },
    {
      "id": "15cd412a-dd8f-4b71-ab54-849a6a535af8",
      "name": "在 GitLab 中更新现有文件",
      "type": "n8n-nodes-base.gitlab",
      "notes": "Updates the existing workflow backup file in GitLab with the latest JSON export.",
      "position": [
        2320,
        -208
      ],
      "parameters": {
        "owner": "={{ $('Set Global GitLab Variables').item.json.gitlab_owner }}",
        "branch": "={{ $(\"Set Global GitLab Variables\").item.json.gitlab_branch }}",
        "filePath": "={{ $json.file_path || $(\"Prepare GitLab File Path\").item.json.gitlab_file_path }}",
        "resource": "file",
        "operation": "edit",
        "repository": "={{ $('Set Global GitLab Variables').item.json.gitlab_project }}",
        "fileContent": "={{ JSON.stringify($(\"Prepare Workflow JSON for UI-Compatible Export\").item.json, null, 2) }}",
        "commitMessage": "={{ \"Update backup for workflow: \" \n    + $(\"Clean & Normalize Workflow Name\").item.json.name \n    + \" (\" \n    + ($json.file_path || $(\"Prepare GitLab File Path\").item.json.gitlab_file_path) \n    + \")\" \n}}"
      },
      "credentials": {
        "gitlabApi": {
          "id": "3xJQUM2wS07heXvB",
          "name": "GitLab account"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "da9f550c-bd0f-4bc2-b221-cab11a8d7be6",
      "name": "在 GitLab 中创建新文件",
      "type": "n8n-nodes-base.gitlab",
      "notes": "Creates a new workflow backup file in GitLab if it does not already exist.",
      "position": [
        2096,
        64
      ],
      "parameters": {
        "owner": "={{ $('Set Global GitLab Variables').item.json.gitlab_owner }}",
        "branch": "={{ $('Set Global GitLab Variables').item.json.gitlab_branch }}",
        "filePath": "={{ $json.gitlab_file_path }}",
        "resource": "file",
        "repository": "={{ $('Set Global GitLab Variables').item.json.gitlab_project }}",
        "fileContent": "={{ JSON.stringify($(\"Prepare Workflow JSON for UI-Compatible Export\").item.json, null, 2) }}",
        "commitMessage": "={{ \"Add backup for workflow: \" \n   + $(\"Clean & Normalize Workflow Name\").item.json.name \n   + \" (\" \n   + ($json.gitlab_file_path || $(\"Prepare GitLab File Path\").item.json.gitlab_file_path) \n   + \")\" }}"
      },
      "credentials": {
        "gitlabApi": {
          "id": "3xJQUM2wS07heXvB",
          "name": "GitLab account"
        }
      },
      "notesInFlow": true,
      "typeVersion": 1
    },
    {
      "id": "5ddc1294-9b87-42d8-93b8-f5e695dbf8bb",
      "name": "规范化备份输出",
      "type": "n8n-nodes-base.set",
      "notes": "Normalizes backup output: adds GitLab path, branch, owner, project, execution type & timestamp.",
      "position": [
        3392,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "46c0d9f1-dfe1-4ada-b7e5-0148badac474",
              "name": "status",
              "type": "string",
              "value": "={{ $json.status }}"
            },
            {
              "id": "5810a928-6341-4600-8d8a-147c7b003c79",
              "name": "workflow_name",
              "type": "string",
              "value": "={{ $(\"Prepare Workflow JSON for UI-Compatible Export\").item.json.name }}"
            },
            {
              "id": "d25b1d07-589c-4b02-ae3e-90d3e292dec8",
              "name": "file_path",
              "type": "string",
              "value": "={{ $(\"Prepare GitLab File Path\").item.json.gitlab_file_path }}"
            },
            {
              "id": "226b5ec1-c8e1-43e9-b621-44e8e87328da",
              "name": "branch",
              "type": "string",
              "value": "={{ $(\"Set Global GitLab Variables\").item.json.gitlab_branch }}"
            },
            {
              "id": "596584fb-4c78-4863-909c-728409de7e48",
              "name": "gitlab_owner",
              "type": "string",
              "value": "={{ $(\"Set Global GitLab Variables\").item.json.gitlab_owner }}"
            },
            {
              "id": "c8db01a0-5ca5-4bff-be3f-fe9fe0f5fc7b",
              "name": "gitlab_project",
              "type": "string",
              "value": "={{ $(\"Set Global GitLab Variables\").item.json.gitlab_project }}"
            },
            {
              "id": "c8d1166c-c5b0-44a3-9740-6ae0c5b077b8",
              "name": "execution_type",
              "type": "string",
              "value": "={{ $(\"Set Global GitLab Variables\").item.json.execution_type }}"
            },
            {
              "id": "5ef4679e-0125-419b-b154-b2562198c616",
              "name": "execution_time",
              "type": "string",
              "value": "={{ $now }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "9939f6ff-8915-47f3-8a87-6ff204fd2c0d",
      "name": "设置全局 GitLab 变量",
      "type": "n8n-nodes-base.set",
      "notes": "Defines global GitLab variables (owner, project, branch, paths, tags, execution type) for reuse across the workflow.",
      "position": [
        -640,
        -32
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "d3a64cab-d823-4bfb-9ff8-3f00f1bd0942",
              "name": "gitlab_owner",
              "type": "string",
              "value": "n8n-ainexusone"
            },
            {
              "id": "c13bd008-2829-4950-862e-94394bd818d6",
              "name": "gitlab_project",
              "type": "string",
              "value": "n8n_workflow_backups"
            },
            {
              "id": "2c58ec25-1e33-406c-821a-62eff539f2db",
              "name": "gitlab_workflow_path",
              "type": "string",
              "value": "workflow_definitions"
            },
            {
              "id": "1517ca87-dba2-4411-af85-8d2c91e7aa42",
              "name": "gitlab_branch",
              "type": "string",
              "value": "main"
            },
            {
              "id": "39a0387d-8195-4c49-9831-c87f77758cdd",
              "name": "tag_backup",
              "type": "string",
              "value": "backup-workflows"
            },
            {
              "id": "3357bb93-0e45-4a8d-aced-ebe5b7e93ef8",
              "name": "execution_type",
              "type": "string",
              "value": "={{ ( $('Schedule Trigger').isExecuted) ? 'Scheduled' : 'Manual' }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "2ea3ccb3-8123-4f49-82be-c4b90e0c5f20",
      "name": "准备 GitLab 文件路径",
      "type": "n8n-nodes-base.code",
      "notes": "Builds a normalized GitLab file path for the workflow backup (workflowId + .json)",
      "position": [
        1312,
        32
      ],
      "parameters": {
        "jsCode": "// ---------------------------------------------------------------------------\n// n8n Code Node - Prepare GitLab File Path (Dedicated Node)\n// ---------------------------------------------------------------------------\n//\n// GOAL: Generate the GitLab storage path for each workflow without polluting\n//       the workflow JSON that will be versioned. File name is fixed on ID\n//       to avoid duplication when the workflow name changes.\n// ---------------------------------------------------------------------------\n\nreturn $input.all().map(item => {\n    const w = item.json; // Current workflow data\n\n    // --------------------------------------------------------\n    // Helper: normalize accents & slugify safely\n    // --------------------------------------------------------\n    const toSlug = (s) => String(s || '')\n        .normalize('NFKD')                // decompose accented characters\n        .replace(/[\\u0300-\\u036f]/g, '')  // remove diacritics\n        .toLowerCase()\n        .replace(/[^a-z0-9]+/g, '-')      // replace invalid chars with hyphens\n        .replace(/^-+|-+$/g, '');         // trim hyphens at start/end\n\n    // --------------------------------------------------------\n    // 1. Extract and normalize the customer slug if tag exists\n    // --------------------------------------------------------\n    const customerTag = /\\[customer\\s*:?\\s*([^\\]\\r\\n]*)\\]/i;\n    const match = (w.name || '').match(customerTag);\n\n    let customerSlug = \"unassigned\"; // Default if no [customer: ...] tag is found\n    if (match && match[1].trim()) {\n        customerSlug = toSlug(match[1].trim()) || \"unassigned\";\n    }\n\n    // --------------------------------------------------------\n    // 2. Build the GitLab storage path (ID-based, rename-proof)\n    // --------------------------------------------------------\n    const basePath = $('Set Global GitLab Variables').item.json.gitlab_workflow_path; // From declared variables\n    const filePath = `${basePath}/${customerSlug}/${w.id}.json`;\n\n    // --------------------------------------------------------\n    // 3. Return ONLY the GitLab file path\n    // --------------------------------------------------------\n    return {\n        json: {\n            gitlab_file_path: filePath\n        }\n    };\n});"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "9f4fd524-5c9b-4ba6-bef2-a6da86f64c7d",
      "name": "将工作流与 GitLab 版本比较",
      "type": "n8n-nodes-base.if",
      "notes": "Compares exported workflow JSON with the GitLab version to detect changes.",
      "position": [
        2096,
        -128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "2e7b9fc6-cf3e-4f3c-b8be-a55221f5d1f4",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ JSON.stringify($(\"Prepare Workflow JSON for UI-Compatible Export\").item.json) }}",
              "rightValue": "={{ JSON.stringify(JSON.parse($json.content.base64Decode().trim())) }}"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 2.2
    },
    {
      "id": "71fc8901-e3ea-4540-9384-51525834964b",
      "name": "便签7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2656,
        -1648
      ],
      "parameters": {
        "color": 5,
        "width": 1280,
        "height": 1920,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "fcc49db9-286c-4f06-8e4e-dc1f11a0488c",
      "name": "便签1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1264,
        -1648
      ],
      "parameters": {
        "color": 3,
        "width": 1328,
        "height": 912,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "178c79f8-345e-4d33-a8aa-4eb31da592b7",
      "name": "便签 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        64,
        -1648
      ],
      "parameters": {
        "color": 3,
        "width": 1504,
        "height": 912,
        "content": ""
      },
      "typeVersion": 1
    },
    {
      "id": "75b2037f-bad5-4988-9f82-73665e4ae0eb",
      "name": "标记为已创建",
      "type": "n8n-nodes-base.set",
      "notes": "Tags workflow as \"created\" (new file added in GitLab).",
      "position": [
        2928,
        64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8e6cb925-589a-4daa-bf5c-73a51092ae9e",
              "name": "status",
              "type": "string",
              "value": "created"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e995304e-5611-4905-9a33-b6fdd70d3655",
      "name": "标记为已更新",
      "type": "n8n-nodes-base.set",
      "notes": "Tags workflow as \"updated\" after backup comparison.",
      "position": [
        2928,
        -96
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8e6cb925-589a-4daa-bf5c-73a51092ae9e",
              "name": "status",
              "type": "string",
              "value": "updated"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "69533d20-2a48-4cb4-810d-e65c2a4aa71c",
      "name": "标记为未更改",
      "type": "n8n-nodes-base.set",
      "notes": "Tags workflow as \"unchanged\" (no differences found).",
      "position": [
        2768,
        -16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8e6cb925-589a-4daa-bf5c-73a51092ae9e",
              "name": "status",
              "type": "string",
              "value": "unchanged"
            }
          ]
        }
      },
      "notesInFlow": true,
      "typeVersion": 3.4
    },
    {
      "id": "7af2d653-0358-4b5a-847c-8b1851aa2721",
      "name": "总结备份结果",
      "type": "n8n-nodes-base.code",
      "notes": "Summarizes backup results: counts created/updated/unchanged workflows and adds execution metadata.",
      "position": [
        3712,
        -16
      ],
      "parameters": {
        "jsCode": "// n8n Code Node — Summarize Backup Results\n// ----------------------------------------\n\nconst items = $input.all();\n\n// Init counters\nlet recap = {\n  created: 0,\n  updated: 0,\n  unchanged: 0,\n  total: items.length,\n};\n\nfor (const item of items) {\n  const status = item.json.status;\n  if (status && recap.hasOwnProperty(status)) {\n    recap[status]++;\n  }\n}\n\n// Build output\nreturn [\n  {\n    json: {\n      execution_type: items[0]?.json.execution_type || \"unknown\",\n      execution_time: items[0]?.json.execution_time || new Date().toISOString(),\n      recap,\n    },\n  },\n];"
      },
      "notesInFlow": true,
      "typeVersion": 2
    },
    {
      "id": "90c21f27-3af6-416f-978e-2ff38c300c7a",
      "name": "合并",
      "type": "n8n-nodes-base.merge",
      "notes": "Merges outputs from \"Mark as Updated/Unchanged/Created\" into a single stream.\n",
      "position": [
        3168,
        -32
      ],
      "parameters": {
        "numberInputs": 3
      },
      "notesInFlow": true,
      "typeVersion": 3.2
    }
  ],
  "active": true,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "74c2b09d-c638-48fd-9db7-a9fcfc28d309",
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Normalize Backup Output",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Created": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 2
          }
        ]
      ]
    },
    "Mark as Updated": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Set Global GitLab Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark as Unchanged": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Normalize Backup Output": {
      "main": [
        [
          {
            "node": "Summarize Backup Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Workflows from n8n": {
      "main": [
        [
          {
            "node": "Clean & Normalize Workflow Name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare GitLab File Path": {
      "main": [
        [
          {
            "node": "Fetch Existing File from GitLab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create New File in GitLab": {
      "main": [
        [
          {
            "node": "Mark as Created",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Global GitLab Variables": {
      "main": [
        [
          {
            "node": "Fetch Workflows from n8n",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Existing File in GitLab": {
      "main": [
        [
          {
            "node": "Mark as Updated",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Clean & Normalize Workflow Name": {
      "main": [
        [
          {
            "node": "Prepare Workflow JSON for UI-Compatible Export",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Existing File from GitLab": {
      "main": [
        [
          {
            "node": "Compare Workflow with GitLab Version",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create New File in GitLab",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compare Workflow with GitLab Version": {
      "main": [
        [
          {
            "node": "Update Existing File in GitLab",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark as Unchanged",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When clicking ‘Execute workflow’": {
      "main": [
        [
          {
            "node": "Set Global GitLab Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Workflow JSON for UI-Compatible Export": {
      "main": [
        [
          {
            "node": "Prepare GitLab File Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
常见问题

如何使用这个工作流?

复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。

这个工作流适合什么场景?

高级 - 开发运维, 多模态 AI

需要付费吗?

本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量24
分类2
节点类型9
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Omar Kennouche | AI Nexus One

Omar Kennouche | AI Nexus One

@kennouche-omar

Automation & AI consultant. I design practical n8n workflows connecting APIs, business tools and AI—focused on saving time, reducing errors and enabling growth.

外部链接
在 n8n.io 查看

分享此工作流