{ "updatedAt": "2025-11-23T08:57:23.000Z", "createdAt": "2025-11-23T08:34:12.767Z", "id": "fsaojBpJsioS4FYe", "name": "Gitea n8n backup", "active": true, "isArchived": false, "nodes": [ { "parameters": { "values": { "string": [ { "name": "repo.url", "value": "https://gitea.prinz-pilaw.de" }, { "name": "repo.name", "value": "n8n-workspace" }, { "name": "repo.owner", "value": "gitea" } ] }, "options": {} }, "id": "b6997dbf-2f79-4c4f-a6cf-6dbb76c547cd", "name": "Globals", "type": "n8n-nodes-base.set", "position": [ 464, 96 ], "typeVersion": 1 }, { "parameters": { "filters": {}, "requestOptions": {} }, "id": "d6b7dbc9-8f6c-4922-a725-6f5e2cbf5e50", "name": "n8n", "type": "n8n-nodes-base.n8n", "position": [ 704, 96 ], "typeVersion": 1, "credentials": { "n8nApi": { "id": "MzXVd9Km6bhxsIq5", "name": "n8n-workspace-backup" } } }, { "parameters": { "rule": { "interval": [ {} ] } }, "id": "312ab6a1-64e1-4b63-b94b-87619a7eb184", "name": "Schedule Trigger", "type": "n8n-nodes-base.scheduleTrigger", "position": [ 240, 96 ], "typeVersion": 1.2 }, { "parameters": { "content": "Workflow changes committed to the repository", "height": 80 }, "id": "5a6a4dd1-d86b-43f2-80df-4b430615f4e9", "name": "Sticky Note", "type": "n8n-nodes-base.stickyNote", "position": [ 2480, 160 ], "typeVersion": 1 }, { "parameters": { "content": "Check if there are any changes in the workflow", "height": 80 }, "id": "f342c5df-d6a3-4997-a94e-f6affd4e929f", "name": "Sticky Note1", "type": "n8n-nodes-base.stickyNote", "position": [ 2112, 32 ], "typeVersion": 1 }, { "parameters": { "content": "Create a new file for the workflow", "height": 80 }, "id": "0f93a72a-faf6-4177-bffa-7d4088c0bce7", "name": "Sticky Note2", "type": "n8n-nodes-base.stickyNote", "position": [ 1664, 432 ], "typeVersion": 1 }, { "parameters": { "content": "Check if file exists in the repository", "height": 80 }, "id": "4f89f7e1-90c6-4b2a-b928-5839ba0e03e3", "name": "Sticky Note3", "type": "n8n-nodes-base.stickyNote", "position": [ 1152, 64 ], "typeVersion": 1 }, { "parameters": { "content": "Get all workflows", "height": 80 }, "id": "2939ebe5-a9ce-4103-b44e-336ae2ac5903", "name": "Sticky Note5", "type": "n8n-nodes-base.stickyNote", "position": [ 640, 32 ], "typeVersion": 1 }, { "parameters": { "content": "Set variables", "height": 80 }, "id": "1fa6cc74-f22d-4106-84dc-36478abb400d", "name": "Sticky Note6", "type": "n8n-nodes-base.stickyNote", "position": [ 352, 32 ], "typeVersion": 1 }, { "parameters": { "assignments": { "assignments": [ { "id": "0a6b769a-c66d-4784-92c7-a70caa28e1ba", "name": "item", "type": "object", "value": "={{ $node[\"ForEach\"].json }}" } ] }, "options": {} }, "id": "b22a1647-7c9f-4dc2-9f9c-44461dece4fc", "name": "SetDataUpdateNode", "type": "n8n-nodes-base.set", "position": [ 1776, 96 ], "typeVersion": 3.4 }, { "parameters": { "assignments": { "assignments": [ { "id": "0a6b769a-c66d-4784-92c7-a70caa28e1ba", "name": "item", "type": "object", "value": "={{ $node[\"ForEach\"].json }}" } ] }, "options": {} }, "id": "65a08a09-ee06-4e99-addb-4e94bf32caf2", "name": "SetDataCreateNode", "type": "n8n-nodes-base.set", "position": [ 1072, 496 ], "typeVersion": 3.4 }, { "parameters": { "jsCode": "const results = [];\n\n// Wir iterieren über alle Items (besser als input_dict[0] im Python-Code)\nfor (const item of $input.all()) {\n \n // Zugriff auf die Daten: entspricht input_dict[0].get('json').get('item')\n const innerData = item.json.item;\n\n if (innerData) {\n // Schritt 1: JSON schön formatieren (Pretty Print)\n const jsonString = JSON.stringify(innerData, null, 4);\n\n // Schritt 2 & 3: String in Base64 umwandeln\n // Buffer ist in Node.js/n8n Standard\n const base64String = Buffer.from(jsonString, 'utf8').toString('base64');\n\n // Schritt 5: Rückgabeobjekt erstellen\n results.push({\n json: {\n item: base64String\n }\n });\n }\n}\n\nreturn results;" }, "id": "2d99bcb9-7de7-4db0-a2e3-976754d9034d", "name": "Base64EncodeUpdate", "type": "n8n-nodes-base.code", "position": [ 2000, 96 ], "typeVersion": 2 }, { "parameters": { "jsCode": "// Wir erstellen ein Array für die Ergebnisse\nconst results = [];\n\n// Wir iterieren über alle eingehenden Items (n8n Best Practice)\n// Der Python Code hat nur das erste Item [0] genommen, was oft ein Fehler ist.\nfor (const item of $input.all()) {\n\n // \"item.json.item\" entspricht dem Pfad aus deinem Python-Code:\n // inner_data = input_dict[0].get('json').get('item')\n const innerData = item.json.item;\n\n if (innerData) {\n // Schritt 1: JSON \"pretty print\" (Formatieren)\n const jsonString = JSON.stringify(innerData, null, 4);\n\n // Schritt 2 & 3: String zu Base64 encodieren\n // Buffer ist nativ in Node.js verfügbar\n const base64String = Buffer.from(jsonString, 'utf8').toString('base64');\n\n // Schritt 4: Ergebnis zum Array hinzufügen\n results.push({\n json: {\n item: base64String\n }\n });\n } else {\n // Fallback, falls \"item\" leer ist\n results.push({\n json: {\n item: null,\n error: \"Keine Daten im Feld 'item' gefunden\"\n }\n });\n }\n}\n\nreturn results;" }, "id": "6ff133d8-17bf-4872-92d4-6d9e734a04d5", "name": "Base64EncodeCreate", "type": "n8n-nodes-base.code", "position": [ 1376, 496 ], "typeVersion": 2 }, { "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "combinator": "or", "conditions": [ { "id": "16a9182d-059d-4774-ba95-654fb4293fdb", "operator": { "type": "object", "operation": "notExists", "singleValue": true }, "leftValue": "={{ $json.error }}", "rightValue": 404 } ] }, "options": { "ignoreCase": false } }, "id": "c05cef97-1733-4676-9944-24c9bd8ddeca", "name": "Exist", "type": "n8n-nodes-base.if", "position": [ 1504, 112 ], "executeOnce": false, "typeVersion": 2.2, "alwaysOutputData": false }, { "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "combinator": "and", "conditions": [ { "id": "e0c66624-429a-4f1f-bf7b-1cc1b32bad7b", "operator": { "type": "string", "operation": "notEquals" }, "leftValue": "={{ $json.item }}", "rightValue": "={{ $('GetGitea').item.json.content }}" } ] }, "options": {} }, "id": "000af828-3eaf-4b9d-b212-4c69aa1976bc", "name": "Changed", "type": "n8n-nodes-base.if", "position": [ 2224, 96 ], "typeVersion": 2.2 }, { "parameters": { "method": "PUT", "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ $('Globals').item.json.repo.owner }}/{{ $('Globals').item.json.repo.name }}/contents/{{ encodeURIComponent($('GetGitea').item.json.name) }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "bodyParameters": { "parameters": [ { "name": "content", "value": "={{ $('Base64EncodeUpdate').item.json.item }}" }, { "name": "sha", "value": "={{ $('GetGitea').item.json.sha }}" } ] }, "options": {} }, "id": "f79dd651-3891-4e9b-b2e8-be5bfa1fe7eb", "name": "PutGitea", "type": "n8n-nodes-base.httpRequest", "position": [ 2560, 224 ], "typeVersion": 4.2, "credentials": { "httpHeaderAuth": { "id": "NEnkbkj4tAvlTLD8", "name": "Header Auth account" } } }, { "parameters": { "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ encodeURIComponent($('Globals').item.json.repo.owner) }}/{{ encodeURIComponent($('Globals').item.json.repo.name) }}/contents/{{ encodeURIComponent($json.name) }}.json", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "options": {} }, "id": "4424b8ad-143a-4d3d-b99d-dcee4f02a710", "name": "GetGitea", "type": "n8n-nodes-base.httpRequest", "position": [ 1232, 112 ], "typeVersion": 4.2, "credentials": { "httpHeaderAuth": { "id": "NEnkbkj4tAvlTLD8", "name": "Header Auth account" } }, "onError": "continueRegularOutput" }, { "parameters": { "method": "POST", "url": "={{ $('Globals').item.json.repo.url }}/api/v1/repos/{{ $('Globals').item.json.repo.owner }}/{{ $('Globals').item.json.repo.name }}/contents/{{ encodeURIComponent($('ForEach').item.json.name) }}.json", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "bodyParameters": { "parameters": [ { "name": "content", "value": "={{ $json.item }}" } ] }, "options": {} }, "id": "fc17d602-92e1-411b-8ba4-00f62046fd2b", "name": "PostGitea", "type": "n8n-nodes-base.httpRequest", "position": [ 1776, 496 ], "typeVersion": 4.2, "credentials": { "httpHeaderAuth": { "id": "NEnkbkj4tAvlTLD8", "name": "Header Auth account" } } }, { "parameters": { "options": {} }, "id": "ef790cca-0082-408f-bed3-5abf0496082c", "name": "ForEach", "type": "n8n-nodes-base.splitInBatches", "position": [ 912, 96 ], "executeOnce": false, "typeVersion": 3 }, { "parameters": { "content": "### **📌 Setup Guide for Backup Workflows to Git Repository on Gitea**\n\n#### **🔧 1. Configure Global Variables**\nGo to the **Globals** node and update the following:\n- **`repo.url`** → `https://your-gitea-instance.com` *(Replace with your actual Gitea URL)*\n- **`repo.name`** → `workflows` *(Repository name where backups will be stored)*\n- **`repo.owner`** → `octoleo` *(Gitea account that owns the repository)*\n\n📌 **These settings define where workflows will be backed up.**\n\n---\n\n#### **🔑 2. Set Up Gitea Authentication**\n1️⃣ **In Gitea:**\n- Generate a **Personal Access Token** under **Settings → Applications → Generate Token**\n- Ensure the token has **repo read/write permissions**\n\n2️⃣ **In the Credentials Manager:**\n- Create a new **Gitea Token** credential\n- Set the **Name** as `Authorization`\n- Set the **Value** as:\n```\nBearer YOUR_TOKEN_HERE\n```\n📌 **Ensure there is a space after `Bearer` before the token!**\n\n---\n\n#### **🔗 3. Connect Gitea Credentials to Git Nodes**\n- Open each of these **three Git nodes**:\n- **GetGitea** → Retrieves existing repository data\n- **PutGitea** → Updates workflows\n- **PostGitea** → Adds new workflows\n\n- Assign the **Gitea Token** credential to each node.\n\n📌 **These nodes handle pushing your workflows to Gitea.**\n\n---\n\n#### **🌐 4. Set Up API Credentials for Workflow Retrieval**\n- Locate the API request node that **fetches workflows**.\n- Add your **API authentication credentials** (Token or Basic Auth).\n\n📌 **This ensures the workflow can fetch all available workflows from your system.**\n\n---\n\n#### **🛠️ 5. Test & Activate the Workflow**\n✅ **Run the workflow manually** → Check that workflows are being backed up correctly.\n✅ **Review the Gitea repository** → Ensure the files are updated.\n✅ **Enable the scheduled trigger** → Automates backups at defined intervals.\n\n📌 **The workflow automatically checks for changes before committing updates!**\n\n---\n\n### **🚀 Done! Your Workflows Are Now Backed Up Securely!**\n💬 Have issues? **Reach out on the forum for help!**", "height": 1620, "width": 560 }, "id": "5b242ecc-275e-4d70-861b-64d4b3fcdc82", "name": "Sticky Note4", "type": "n8n-nodes-base.stickyNote", "position": [ 240, 304 ], "typeVersion": 1 } ], "connections": { "n8n": { "main": [ [ { "node": "ForEach", "type": "main", "index": 0 } ] ] }, "Exist": { "main": [ [ { "node": "SetDataUpdateNode", "type": "main", "index": 0 } ], [ { "node": "SetDataCreateNode", "type": "main", "index": 0 } ] ] }, "Changed": { "main": [ [ { "node": "PutGitea", "type": "main", "index": 0 } ], [ { "node": "ForEach", "type": "main", "index": 0 } ] ] }, "ForEach": { "main": [ [], [ { "node": "GetGitea", "type": "main", "index": 0 } ] ] }, "Globals": { "main": [ [ { "node": "n8n", "type": "main", "index": 0 } ] ] }, "GetGitea": { "main": [ [ { "node": "Exist", "type": "main", "index": 0 } ] ] }, "PutGitea": { "main": [ [ { "node": "ForEach", "type": "main", "index": 0 } ] ] }, "PostGitea": { "main": [ [ { "node": "ForEach", "type": "main", "index": 0 } ] ] }, "Schedule Trigger": { "main": [ [ { "node": "Globals", "type": "main", "index": 0 } ] ] }, "SetDataCreateNode": { "main": [ [ { "node": "Base64EncodeCreate", "type": "main", "index": 0 } ] ] }, "SetDataUpdateNode": { "main": [ [ { "node": "Base64EncodeUpdate", "type": "main", "index": 0 } ] ] }, "Base64EncodeCreate": { "main": [ [ { "node": "PostGitea", "type": "main", "index": 0 } ] ] }, "Base64EncodeUpdate": { "main": [ [ { "node": "Changed", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1" }, "staticData": { "node:Schedule Trigger": { "recurrenceRules": [] } }, "meta": { "templateCredsSetupCompleted": true }, "pinData": {}, "versionId": "fd25c766-ce51-4dea-ac87-7d4d1e1f1319", "triggerCount": 1, "shared": [ { "updatedAt": "2025-11-23T08:34:14.534Z", "createdAt": "2025-11-23T08:34:14.534Z", "role": "workflow:owner", "workflowId": "fsaojBpJsioS4FYe", "projectId": "S4tmpzSj6JlGFOze" } ], "tags": [] }