GitHub-Fork-Repository-Statistiken
Experte
Dies ist ein Engineering-Bereich Automatisierungsworkflow mit 19 Nodes. Hauptsächlich werden If, Code, Merge, Filter, Github und andere Nodes verwendet. GitHub-Fork-Status-Monitor
Voraussetzungen
- •GitHub Personal Access Token
- •Telegram Bot Token
- •Möglicherweise sind Ziel-API-Anmeldedaten erforderlich
Verwendete Nodes (19)
Kategorie
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
"id": "BnXe0TTG2ep3jJvY",
"meta": {
"instanceId": "ade7753ab8e61ecd17667d748d0e70dc7e52ae3b447190f062e3dc18fc407d44",
"templateCredsSetupCompleted": true
},
"name": "github-forked-repo-stats",
"tags": [
{
"id": "ByjgsuAI1ZOmR1Cv",
"name": "github",
"createdAt": "2025-06-10T19:03:59.044Z",
"updatedAt": "2025-06-10T19:03:59.044Z"
}
],
"nodes": [
{
"id": "d27cc197-fa61-421b-8422-8c4e5f716efe",
"name": "Bei Klick auf 'Workflow ausführen'",
"type": "n8n-nodes-base.manualTrigger",
"position": [
380,
-260
],
"parameters": {},
"typeVersion": 1
},
{
"id": "5d55b266-a8b8-450f-903c-b04f47a1d708",
"name": "Über Elemente iterieren",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1160,
-80
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "c160d1cf-67a0-4e5a-9a0d-f6c78ad18154",
"name": "Repository-Details abrufen",
"type": "n8n-nodes-base.github",
"position": [
1380,
-80
],
"webhookId": "2e042451-77f6-447f-b798-f4d8d2c43788",
"parameters": {
"owner": {
"__rl": true,
"mode": "name",
"value": "={{ $json.owner.login }}"
},
"resource": "repository",
"operation": "get",
"repository": {
"__rl": true,
"mode": "url",
"value": "={{ $json.html_url }}"
}
},
"credentials": {
"githubApi": {
"id": "qdeIXe3PnQJwdyiy",
"name": "GitHub account"
}
},
"typeVersion": 1.1
},
{
"id": "7580ab52-4cfc-490f-9f3e-021bba782db4",
"name": "Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
1740,
-480
],
"webhookId": "62a8eb02-eb84-426e-92e2-bb8e65f00ad5",
"parameters": {
"text": "={{ $json.telegramMessage }}",
"chatId": "6083752603",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"id": "Apigm5Vud7RfQEmI",
"name": "telegram-chintupintu-bot"
}
},
"typeVersion": 1.2
},
{
"id": "f0170087-277f-4f32-bc45-305dd56211df",
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-40,
-40
],
"webhookId": "1dcc5ea0-8ab9-42a2-bdc0-06976ea88ed1",
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"id": "Apigm5Vud7RfQEmI",
"name": "telegram-chintupintu-bot"
}
},
"typeVersion": 1.2
},
{
"id": "f22d2c47-5d0a-4574-8293-e7ddc9a326ac",
"name": "Upstream-URL vorbereiten",
"type": "n8n-nodes-base.code",
"position": [
1600,
-80
],
"parameters": {
"jsCode": "const items = [];\n\nconsole.log(`Code Node (Prepare Upstream URL): Received ${$input.all().length} input items.`);\n\nfor (const item of $input.all()) {\n const forkRepo = item.json;\n\n console.log(`Processing repo: ${forkRepo.full_name || 'N/A'}`);\n\n if (forkRepo && forkRepo.fork && forkRepo.parent) {\n const upstreamRepo = forkRepo.parent;\n\n const upstreamOwner = upstreamRepo.owner.login;\n const upstreamName = upstreamRepo.name;\n const upstreamDefaultBranch = upstreamRepo.default_branch;\n\n const forkOwner = forkRepo.owner.login;\n const forkName = forkRepo.name;\n const forkDefaultBranch = forkRepo.default_branch;\n\n const compareUrl = `https://api.github.com/repos/${upstreamOwner}/${upstreamName}/compare/${upstreamDefaultBranch}...${forkOwner}:${forkDefaultBranch}`;\n\n const newItem = {\n json: {\n // This is the URL the HTTP Request node will use\n compareApiUrl: compareUrl,\n\n // <<<< CRITICAL: Embed ALL original data here in a nested object >>>>\n // This relies on the HTTP Request node passing this nested object through\n original_repo_data: {\n repoName: forkRepo.full_name,\n upstreamUrl: upstreamRepo.html_url,\n forkDefaultBranch: forkDefaultBranch,\n upstreamDefaultBranch: upstreamDefaultBranch,\n upstreamRepoName: upstreamName,\n upstreamOwner: upstreamOwner,\n }\n // <<<< END CRITICAL >>>>\n }\n };\n\n items.push(newItem);\n console.log(`--> Prepared item for: ${forkRepo.full_name}. Compare URL: ${compareUrl}`);\n\n } else {\n let skipReason = \"Not a fork or missing parent\";\n if (forkRepo) {\n if (!forkRepo.fork) skipReason = \"Not marked as a fork\";\n if (!forkRepo.parent) skipReason = \"Missing parent (upstream) repository\";\n }\n console.log(`Skipping repo: ${forkRepo.full_name || 'N/A'} - Reason: ${skipReason}`);\n }\n}\n\nconsole.log(`Code Node (Prepare Upstream URL): Returning ${items.length} items.`);\n\nreturn items;"
},
"typeVersion": 2
},
{
"id": "52d91917-e7d0-4a5a-b73b-d7c6f4041603",
"name": "Compare Branches API Aufruf",
"type": "n8n-nodes-base.httpRequest",
"position": [
1820,
-80
],
"parameters": {
"url": "={{ $json.compareApiUrl }}",
"options": {},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"headerParameters": {
"parameters": [
{
"name": "Accept",
"value": "application/vnd.github.v3+json"
}
]
}
},
"credentials": {
"httpHeaderAuth": {
"id": "y5bKE9liUU2yNx4X",
"name": "github-api-pat"
}
},
"typeVersion": 4.2
},
{
"id": "f08f4f87-d7a6-49d4-99a2-04790a98b58d",
"name": "Vergleichsergebnis verarbeiten",
"type": "n8n-nodes-base.code",
"position": [
2040,
-80
],
"parameters": {
"jsCode": "const items = [];\n\nconsole.log(`Code Node (Process Combined Result): Received ${$input.all().length} input items.`);\n\nfor (const item of $input.all()) {\n // Original repo data is picked up from 2 nodes earlier\n const originalRepoData = $('Prepare Upstream URL').first().json.original_repo_data\n\n // API response data is now in item.json\n const apiResponse = item.json;\n console.log(\"apiResponse\",apiResponse);\n\n\n // Debugging: Check if data is available\n if (typeof apiResponse.behind_by === 'undefined' || typeof apiResponse.ahead_by === 'undefined') {\n console.error(`ERROR: Missing or malformed data after merge! Original:`, originalRepoData, `API:`, apiResponse);\n // Push an error item or skip\n items.push({\n json: {\n repoName: originalRepoData?.repoName || 'N/A', // Use optional chaining for safety\n status: \"ERROR_PROCESSING_MERGE\",\n commitsBehind: -1,\n commitsAhead: -1\n }\n });\n continue;\n }\n\n const commitsBehind = apiResponse.behind_by;\n const commitsAhead = apiResponse.ahead_by;\n const status = commitsBehind > 0 ? \"BEHIND\" : (commitsAhead > 0 ? \"AHEAD\" : \"UP-TO-DATE\");\n\n\n\n const processedItem = {\n json: {\n repoName: originalRepoData.repoName,\n upstreamUrl: originalRepoData.upstreamUrl,\n forkDefaultBranch: originalRepoData.forkDefaultBranch,\n upstreamDefaultBranch: originalRepoData.upstreamDefaultBranch,\n upstreamRepoName: originalRepoData.upstreamRepoName,\n upstreamOwner: originalRepoData.upstreamOwner,\n status: status,\n commitsBehind: commitsBehind,\n commitsAhead: commitsAhead\n }\n };\n items.push(processedItem);\n console.log(`--> Processed ${processedItem.json.repoName}: Status=${processedItem.json.status}, Behind=${processedItem.json.commitsBehind}, Ahead=${processedItem.json.commitsAhead}`);\n}\nconsole.log(`Code Node (Process Combined Result): Returning ${items.length} items.`);\nreturn items;"
},
"typeVersion": 2
},
{
"id": "19d0624b-1773-41db-8a37-bbee490b7f50",
"name": "Ergebnisse zusammenführen",
"type": "n8n-nodes-base.merge",
"position": [
2260,
0
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "5f4fd86e-9c37-4bb3-a55f-2db724ed9bd4",
"name": "Für Telegram formatieren",
"type": "n8n-nodes-base.code",
"position": [
1520,
-480
],
"parameters": {
"jsCode": "const items = $input.all();\nlet telegramMessage = `*GitHub Fork Status Report - ${new Date().toLocaleDateString()}*\\n\\n`;\n\n// Initialize counters for summary\nlet reposBehind = 0;\nlet reposAhead = 0;\nlet reposUpToDate = 0;\n\n// ... (previous code)\n\n// Build the table header\ntelegramMessage += `| Ahead | Behind | Repository |\\n`;\ntelegramMessage += `|------------|------------|-----------------------|\\n`;\n\n// Populate table rows\nfor (const item of items) {\n const data = item.json;\n const repoName = data.repoName;\n const commitsAhead = data.commitsAhead;\n const commitsBehind = data.commitsBehind;\n\n // Update counters for summary\n if (commitsBehind > 0) {\n reposBehind++;\n } else if (commitsAhead > 0) {\n reposAhead++;\n } else {\n reposUpToDate++;\n continue;\n }\n\n // --- CRITICAL FIX START ---\n // Ensure you use BACKTICKS ( ` ) for the string literal\n // And standard JavaScript template literal syntax ${variableName}\n\n // Escape characters in the repo name for Markdown if necessary, but usually not for links like this\n // For general text: `repoName.replace(/[-_.*[\\]()~`>#+\\-=|{}.!]/g, '\\\\$&')`\n // But for links, usually the raw name is fine within `[]`\n const escapedRepoName = repoName.replace(/_/g, '\\\\_').replace(/\\*/g, '\\\\*').replace(/\\[/g, '\\\\[').replace(/\\]/g, '\\\\]').replace(/\\(/g, '\\\\(').replace(/\\)/g, '\\\\)').replace(/~/g, '\\\\~').replace(/`/g, '\\\\`').replace(/>/g, '\\\\>').replace(/#/g, '\\\\#').replace(/\\+/g, '\\\\+').replace(/-/g, '\\\\-').replace(/=/g, '\\\\=').replace(/\\|/g, '\\\\|').replace(/{/g, '\\\\{').replace(/}/g, '\\\\}').replace(/\\./g, '\\\\.').replace(/!/g, '\\\\!');\n\n\n // Use [text](url) format for Telegram MarkdownV2 links\n const repoLink = `[${escapedRepoName}](https://github.com/${repoName})`; // Changed from <url|text>\n // --- CRITICAL FIX END ---\n // Format commitsAhead and commitsBehind to be 4 characters wide, right-aligned\n const formattedAhead = String(commitsAhead).padStart(5, '0');\n const formattedBehind = String(commitsBehind).padStart(5, '0');\n telegramMessage += `| ${formattedAhead} | ${formattedBehind} | ${repoLink} |\\n`;\n}\n\n// ... (rest of the code)\n\n\nreturn [{ json: { telegramMessage: telegramMessage } }];"
},
"typeVersion": 2
},
{
"id": "ea7c4abd-2748-4e9e-8e44-eefb60757db6",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
180,
-40
],
"parameters": {
"jsCode": "// Loop over input items and add a new field called 'myNewField' to the JSON of each one\nfor (const item of $input.all()) {\n item.json.repos = processCommand(item.json.message.text);\n}\n\nreturn $input.all();\n\nfunction processCommand(input) {\n const parts = input.trim().split(\" \"); // Split by space and remove extra spaces\n const command = parts[0];\n const number = parseInt(parts[1], 10); // Convert second part to an integer\n\n let repos = 0;\n\n if (command === \"/forkcheck\") {\n if (Number.isInteger(number) && number > 0) {\n repos = number;\n } else {\n repos = 1000; // Default value if blank or 0\n }\n console.log(`Repos set to: ${repos}`);\n } else {\n console.log(\"Invalid command.\");\n }\nreturn repos;\n}\n\n"
},
"typeVersion": 2
},
{
"id": "d9aebe90-f406-4152-bf15-dc73aeacdb6d",
"name": "Wenn",
"type": "n8n-nodes-base.if",
"position": [
380,
-40
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ae98c5c9-a1df-4458-862f-32555165bae1",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ $json.repos }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2.2
},
{
"id": "d926e485-2d76-4c10-a231-5d5e4cc6b1ae",
"name": "Notizzettel",
"type": "n8n-nodes-base.stickyNote",
"position": [
-200,
-400
],
"parameters": {
"width": 800,
"height": 640,
"content": "## Triggers - *Set your triggers here*\n\n\n\n## Default\n- Manual\n- Telegram bot with command /forkcheck\n\n## Usage\n- /forkcheck = 1000 repositoriesmax\n- /forkcheck n = n repositories\n- any other command is rejected\n"
},
"typeVersion": 1
},
{
"id": "53fde103-cbeb-4932-9027-f779c93b441c",
"name": "Notizzettel1",
"type": "n8n-nodes-base.stickyNote",
"position": [
620,
-400
],
"parameters": {
"color": 5,
"width": 420,
"height": 640,
"content": "## Filter repositories\n\nSelect only forked repositories\nRequired argument: Count to select repositories"
},
"typeVersion": 1
},
{
"id": "45b0716e-993f-478a-af4f-ead51f5132c5",
"name": "Notizzettel2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1060,
-260
],
"parameters": {
"width": 1360,
"height": 500,
"content": "## Processing logic"
},
"typeVersion": 1
},
{
"id": "b7349c8b-d4cb-4636-a788-673dfc4fff1a",
"name": "Repositories abrufen",
"type": "n8n-nodes-base.github",
"position": [
660,
-80
],
"webhookId": "0ae11593-7d12-4b7d-ae1a-41b65bb6b34d",
"parameters": {
"limit": "={{ $json.repos }}",
"owner": {
"__rl": true,
"mode": "list",
"value": "mk-in",
"cachedResultUrl": "https://github.com/mk-in",
"cachedResultName": "mk-in"
},
"resource": "user"
},
"credentials": {
"githubApi": {
"id": "qdeIXe3PnQJwdyiy",
"name": "GitHub account"
}
},
"typeVersion": 1.1
},
{
"id": "c85f5822-2b50-4f1d-b479-47ff8c4ef6e6",
"name": "Notizzettel3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1060,
-580
],
"parameters": {
"color": 3,
"width": 1360,
"height": 300,
"content": "## Summarize and send"
},
"typeVersion": 1
},
{
"id": "e5c4395c-8598-4da5-87a5-f8e5395ada44",
"name": "Notizzettel4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-200,
-580
],
"parameters": {
"width": 1240,
"content": "## GitHub Fork Status Monitor\n\nThis workflow helps you keep an eye on your GitHub forks, notifying you when they fall behind or pull ahead of their upstream repositories."
},
"typeVersion": 1
},
{
"id": "bd807482-d2c7-4cb8-aab6-854e816ab25a",
"name": "Nur geforkte Repositories filtern",
"type": "n8n-nodes-base.filter",
"position": [
880,
-80
],
"parameters": {
"options": {
"ignoreCase": false
},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "651ce98d-bf86-474a-b376-05fb5233fbee",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.fork }}",
"rightValue": "true"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
}
],
"active": true,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "a9ced36c-710d-4306-a51d-50b419cf8c86",
"connections": {
"d9aebe90-f406-4152-bf15-dc73aeacdb6d": {
"main": [
[
{
"node": "b7349c8b-d4cb-4636-a788-673dfc4fff1a",
"type": "main",
"index": 0
}
]
]
},
"ea7c4abd-2748-4e9e-8e44-eefb60757db6": {
"main": [
[
{
"node": "d9aebe90-f406-4152-bf15-dc73aeacdb6d",
"type": "main",
"index": 0
}
]
]
},
"b7349c8b-d4cb-4636-a788-673dfc4fff1a": {
"main": [
[
{
"node": "bd807482-d2c7-4cb8-aab6-854e816ab25a",
"type": "main",
"index": 0
}
]
]
},
"19d0624b-1773-41db-8a37-bbee490b7f50": {
"main": [
[
{
"node": "5d55b266-a8b8-450f-903c-b04f47a1d708",
"type": "main",
"index": 0
}
]
]
},
"5d55b266-a8b8-450f-903c-b04f47a1d708": {
"main": [
[
{
"node": "5f4fd86e-9c37-4bb3-a55f-2db724ed9bd4",
"type": "main",
"index": 0
}
],
[
{
"node": "c160d1cf-67a0-4e5a-9a0d-f6c78ad18154",
"type": "main",
"index": 0
}
]
]
},
"f0170087-277f-4f32-bc45-305dd56211df": {
"main": [
[
{
"node": "ea7c4abd-2748-4e9e-8e44-eefb60757db6",
"type": "main",
"index": 0
}
]
]
},
"c160d1cf-67a0-4e5a-9a0d-f6c78ad18154": {
"main": [
[
{
"node": "f22d2c47-5d0a-4574-8293-e7ddc9a326ac",
"type": "main",
"index": 0
}
]
]
},
"5f4fd86e-9c37-4bb3-a55f-2db724ed9bd4": {
"main": [
[
{
"node": "7580ab52-4cfc-490f-9f3e-021bba782db4",
"type": "main",
"index": 0
}
]
]
},
"f22d2c47-5d0a-4574-8293-e7ddc9a326ac": {
"main": [
[
{
"node": "52d91917-e7d0-4a5a-b73b-d7c6f4041603",
"type": "main",
"index": 0
}
]
]
},
"52d91917-e7d0-4a5a-b73b-d7c6f4041603": {
"main": [
[
{
"node": "f08f4f87-d7a6-49d4-99a2-04790a98b58d",
"type": "main",
"index": 0
}
]
]
},
"f08f4f87-d7a6-49d4-99a2-04790a98b58d": {
"main": [
[
{
"node": "19d0624b-1773-41db-8a37-bbee490b7f50",
"type": "main",
"index": 0
}
]
]
},
"bd807482-d2c7-4cb8-aab6-854e816ab25a": {
"main": [
[
{
"node": "5d55b266-a8b8-450f-903c-b04f47a1d708",
"type": "main",
"index": 0
}
]
]
},
"d27cc197-fa61-421b-8422-8c4e5f716efe": {
"main": [
[
{
"node": "b7349c8b-d4cb-4636-a788-673dfc4fff1a",
"type": "main",
"index": 0
}
]
]
}
}
}Häufig gestellte Fragen
Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Experte - Engineering
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Backup des Squarespace-Code-Injections auf Github
Backup von Squarespace-Code-Injection in GitHub
If
Set
Code
+
If
Set
Code
17 Nodesbangank36
Engineering
API-Architektur-Explorer
API-Architektur-Extraktor
If
Set
Code
+
If
Set
Code
88 NodesPolina Medvedieva
Engineering
Versteckte Website-API-Endpunkte mit regulären Ausdrücken und KI finden
Entdeckung verborgener Website-API-Endpunkte mit regulären Ausdrücken und KI
If
Set
Html
+
If
Set
Html
58 NodesYulia
Engineering
Mehrstufige Beziehungsdaten aus Airtable abrufen
Mehrstufige Hierarchie-Datensätze aus Airtable abrufen
If
Set
Code
+
If
Set
Code
38 Nodesdigi-stud.io
Engineering
AI Candidate Screening Pipeline_ LinkedIn to Telegram with Gemini & Apify
If
Set
Code
+
If
Set
Code
55 NodesDean Pike
Personalwesen
Lead-Generierung und E-Mail-Arbeitsabläufe
Automatisierung der B2B-Lead-Generierung und E-Mail-Marketing mit Google Maps, SendGrid und KI
If
Set
Code
+
If
Set
Code
141 NodesEzema Kingsley Chibuzo
Lead-Generierung
Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes19
Kategorie1
Node-Typen11
Autor
Manish
@manishExterne Links
Auf n8n.io ansehen →
Diesen Workflow teilen