N
n8n Store
Workflow Market
Automate SDK Version Drift Detection with GitHub, Notion, and Slack

Automate SDK Version Drift Detection with GitHub, Notion, and Slack

by rahul08•0 views

Description

Categories

šŸ”§ Engineering

Nodes Used

n8n-nodes-base.ifn8n-nodes-base.setn8n-nodes-base.coden8n-nodes-base.mergen8n-nodes-base.slackn8n-nodes-base.githubn8n-nodes-base.notionn8n-nodes-base.stickyNoten8n-nodes-base.stickyNoten8n-nodes-base.stickyNote
PriceFree
Views0
Last Updated11/28/2025
workflow.json
{
  "id": "L9nRhIlKBOKLFzmr",
  "meta": {
    "instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177",
    "templateCredsSetupCompleted": true
  },
  "name": "Automate SDK Version Drift Detection with GitHub, Notion, and Slack",
  "tags": [],
  "nodes": [
    {
      "id": "00c0c0f6-a22d-40e4-bb1a-aec22dc4b1ac",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1712,
        -80
      ],
      "parameters": {
        "color": 4,
        "width": 426,
        "height": 544,
        "content": "## šŸŽÆ SDK Release Tracker Workflow\n\n### Purpose\nAutomatically tracks SDK releases from GitHub and monitors if documentation (FAQs) in Notion are kept up-to-date. Sends Slack alerts when documentation is >30 days behind.\n\n### Flow Overview\n1. **Trigger**: GitHub repository event\n2. **Fetch**: Get all releases from repository\n3. **Transform**: Extract release metadata\n4. **Log**: Save to Google Sheets\n5. **Compare**: Match with Notion FAQ updates\n6. **Calculate**: Compute drift (days since last update)\n7. **Alert**: Send Slack notification if overdue\n\n### Requirements\n- GitHub OAuth2 credentials\n- Google Sheets OAuth2 credentials\n- Notion API credentials\n- Slack API credentials\n\n### Setup Note\nReplace the following with your own:\n- Google Sheet ID (2 locations)\n- Notion Database ID\n- Slack Channel ID"
      },
      "typeVersion": 1
    },
    {
      "id": "67181deb-538a-4dc1-bf0b-b7230615b6eb",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1264,
        -112
      ],
      "parameters": {
        "color": 5,
        "width": 311,
        "height": 288,
        "content": "## šŸ“Œ GitHub Trigger Setup\n\n### Configuration\n- **Event**: Repository events\n- **Monitors**: Any changes to the repository\n- **Triggers on**: Releases, tags, and repository updates\n\n### Setup Steps\n1. Connect your GitHub OAuth2 account\n2. Select target repository\n3. Choose \"repository\" event type\n\nāš ļø **Replace** repository with your own SDK repository"
      },
      "typeVersion": 1
    },
    {
      "id": "61146141-fa2e-46a4-b265-26c83668ea74",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -896,
        336
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 335,
        "content": "## šŸ“„ Fetch All Releases\n\n### What It Does\nRetrieves all published releases from the GitHub repository to process latest version information.\n\n### Configuration\n- **Resource**: Release\n- **Operation**: Get All\n- **Return All**: Yes (fetches complete release history)\n\n### Output\nRelease data including tag, name, date, and URL"
      },
      "typeVersion": 1
    },
    {
      "id": "c44c2b70-75d1-4a22-bb38-8466dff09b3d",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        -240
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 392,
        "content": "## šŸ”„ Transform Release Data\n\n### Purpose\nStructures raw GitHub release data into a clean format for logging and analysis.\n\n### Fields Extracted\n- SDK Name (from repository)\n- Release Tag (version number)\n- Release Title\n- Release Date (ISO format)\n- Release URL\n- Days Since Release (calculated)"
      },
      "typeVersion": 1
    },
    {
      "id": "9200c97d-f9de-4385-a4a9-8b5bfbc7ee41",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        -320
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 374,
        "content": "## šŸ“Š Log to Google Sheets\n\n### Purpose\nCreates a persistent record of all SDK releases for tracking and reporting.\n\n### Configuration\n- **Operation**: Append (adds new rows)\n- **Mapping**: Auto-map input data\n\nāš ļø **Replace** Sheet ID with your own tracking spreadsheet\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "37807e22-b3e5-4a44-9ef6-8708b0ac0dd2",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -432,
        400
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 346,
        "content": "## šŸ“š Fetch FAQ Data\n\n### Purpose\nRetrieves all FAQ/documentation pages from Notion to compare update dates with releases.\n\n### Configuration\n- **Resource**: Database Page\n- **Operation**: Get All\n- **Return All**: Yes\n\nāš ļø **Replace** Database ID with your Notion FAQ database\n"
      },
      "typeVersion": 1
    },
    {
      "id": "4b8d2255-a740-48df-bd11-301d12b5ea50",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        304
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 304,
        "content": "## šŸ”€ Merge Data Streams\n\n### Purpose\nCombines release data (from Sheets) with FAQ data (from Notion) for drift calculation.\n\n\n### Output\nCombined dataset ready for drift analysis"
      },
      "typeVersion": 1
    },
    {
      "id": "0bf5faa2-2f04-4287-b4b8-70e554d450ba",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -208
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 376,
        "content": "## 🧮 Calculate Documentation Drift\n\n### Purpose\nComputes how many days documentation lags behind SDK releases.\n\n### Logic\n1. For each SDK release:\n   - Get release date\n   - Find corresponding FAQ update date\n   - Calculate days between them\n\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "1bae2d99-fc88-4c53-af1a-5b51e54b2fb2",
      "name": "Sticky Note8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        240,
        336
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 288,
        "content": "## šŸ’¾ Update Drift Status\n\n### Purpose\nWrites calculated drift metrics back to Google Sheets for reporting.\n\n### Operation\nAppends drift analysis results as new rows\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "b365f027-1e5e-4d8b-872a-582cbff5a808",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        -128
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 264,
        "content": "## 🚦 Filter Overdue Items\n\n### Purpose\nIdentifies SDKs with documentation >30 days behind for alerting.\n\n### Condition\nOverdue Status = \"OVERDUE\"\n\n"
      },
      "typeVersion": 1
    },
    {
      "id": "16d3ce01-b42e-45ed-aa88-94c000fa539e",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        752,
        -160
      ],
      "parameters": {
        "color": 5,
        "width": 264,
        "height": 312,
        "content": "## šŸ”” Slack Alert\n\n### Purpose\nNotifies team about overdue documentation via Slack.\n\n### Message Format\n🚨 SDK Version Drift Alert\n\n**SDK Name** → X days since FAQ update\nLatest Release: YYYY-MM-DD\n"
      },
      "typeVersion": 1
    },
    {
      "id": "061226de-b13c-4ec9-87bc-5da25a8f7100",
      "name": "Github Trigger",
      "type": "n8n-nodes-base.githubTrigger",
      "position": [
        -1072,
        160
      ],
      "webhookId": "a9cdfd9a-0bb8-4d7d-96b2-2fc9985f48c7",
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "url",
          "value": "https://github.com/YOUR_ORG"
        },
        "events": [
          "repository"
        ],
        "options": {},
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_REPOSITORY_NAME",
          "cachedResultUrl": "https://github.com/YOUR_ORG/YOUR_REPOSITORY_NAME",
          "cachedResultName": "YOUR_REPOSITORY_NAME"
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "be490392-9de4-49a9-95fb-0e18834e2d29",
      "name": "GitHub Fetch Releases",
      "type": "n8n-nodes-base.github",
      "position": [
        -848,
        160
      ],
      "webhookId": "e56158f5-aca5-4a82-9811-a60e31f265e6",
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "url",
          "value": "={{ $json.body.repository.owner.html_url }}"
        },
        "resource": "release",
        "operation": "getAll",
        "returnAll": true,
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_REPOSITORY_NAME",
          "cachedResultUrl": "https://github.com/YOUR_ORG/YOUR_REPOSITORY_NAME",
          "cachedResultName": "YOUR_REPOSITORY_NAME"
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 1
    },
    {
      "id": "902bd84d-2495-4ff9-bf20-95f41e155a37",
      "name": "Edit Fields",
      "type": "n8n-nodes-base.set",
      "position": [
        -624,
        160
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "faa9557a-0057-42e4-a4bb-5b1b93a04992",
              "name": "SDK Name",
              "type": "string",
              "value": "={{ $('Github Trigger').item.json.body.repository.name }}"
            },
            {
              "id": "ad5f6a08-f03f-4f72-b70c-0577eb7573ef",
              "name": "Release Tag",
              "type": "string",
              "value": "={{ $json.tag_name }}"
            },
            {
              "id": "c50e0186-739a-4670-b28e-69ef1dcdc9d3",
              "name": "Release Title",
              "type": "string",
              "value": "={{ $json.name }}"
            },
            {
              "id": "0599a0bc-d822-43dd-92ec-cce8e83c3146",
              "name": "Release Date",
              "type": "string",
              "value": "={{ $json.published_at }}"
            },
            {
              "id": "55a19cd6-460f-4f31-896f-396c18b350b9",
              "name": "Release Url",
              "type": "string",
              "value": "={{ $json.html_url }}"
            },
            {
              "id": "28bf7364-aeef-4c2a-8056-15fa7aad2793",
              "name": "Days Since Release",
              "type": "string",
              "value": "={{ Math.floor((new Date() - new Date($json[\"published_at\"])) / (1000 * 60 * 60 * 24)) }}"
            },
            {
              "id": "fcc21b19-4a8d-467d-ba6f-37df419d7044",
              "name": "Last FAQ Update(Notion)",
              "type": "string",
              "value": ""
            },
            {
              "id": "6a345e0a-bece-440e-bef6-dc3a00ba6a87",
              "name": "Days Since FAQ Update",
              "type": "string",
              "value": ""
            },
            {
              "id": "9789540d-70b8-4cac-9028-09bb9ffc2dc4",
              "name": "Overdue Status",
              "type": "string",
              "value": "Pending"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e8605efa-5f22-450a-a195-e0f119f01865",
      "name": "Google Sheets Log Release Data",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -400,
        64
      ],
      "parameters": {
        "columns": {
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_GID",
          "cachedResultName": "SDK Release Tracker"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultName": "SDK Release Tracker"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "768fc3f6-59ba-4255-b500-8f7e47a22c62",
      "name": "Notion Fetch FAQ Data",
      "type": "n8n-nodes-base.notion",
      "position": [
        -400,
        256
      ],
      "parameters": {
        "options": {},
        "resource": "databasePage",
        "operation": "getAll",
        "returnAll": true,
        "databaseId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_NOTION_DATABASE_ID",
          "cachedResultName": "FAQ Database"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3f79013e-63b0-4722-bb78-91e636d87afa",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        -176,
        160
      ],
      "parameters": {},
      "typeVersion": 3
    },
    {
      "id": "ec6e182c-0184-49ef-a2c9-8c99bc64162f",
      "name": "Function Compute Drift",
      "type": "n8n-nodes-base.code",
      "position": [
        64,
        160
      ],
      "parameters": {
        "jsCode": "// SDK Release Drift Calculator\n// Compares release dates with FAQ update dates to identify documentation lag\n\nconst items = [];\nconst allItems = $input.all();\n\nfor (let i = 0; i < allItems.length; i++) {\n  const item = allItems[i].json;\n  \n  // Process SDK release data from Google Sheets\n  if (item[\"SDK Name\"]) {\n    const sdkName = item[\"SDK Name\"];\n    const releaseDate = new Date(item[\"Release Date\"]);\n    const releaseTag = item[\"Release Tag\"];\n    const releaseUrl = item[\"Release Url\"];\n    const daysSinceRelease = parseInt(item[\"Days Since Release\"]);\n    \n    // Calculate FAQ update drift\n    let faqUpdateDate;\n    let daysSinceFaqUpdate;\n    \n    if (item[\"Last FAQ Update(Notion)\"] && item[\"Last FAQ Update(Notion)\"] !== \"\") {\n      // FAQ has been updated - use that date\n      faqUpdateDate = new Date(item[\"Last FAQ Update(Notion)\"]);\n      daysSinceFaqUpdate = Math.floor((new Date() - faqUpdateDate) / (1000 * 60 * 60 * 24));\n    } else {\n      // No FAQ update recorded - use release date as baseline\n      faqUpdateDate = releaseDate;\n      daysSinceFaqUpdate = daysSinceRelease;\n    }\n    \n    // Determine if documentation is overdue (>30 days)\n    const OVERDUE_THRESHOLD = 30;\n    const isOverdue = daysSinceFaqUpdate > OVERDUE_THRESHOLD;\n    \n    items.push({\n      json: {\n        sdkName: sdkName,\n        latestRelease: releaseTag,\n        releaseDate: item[\"Release Date\"],\n        releaseUrl: releaseUrl,\n        daysSinceRelease: daysSinceRelease,\n        lastFaqUpdate: faqUpdateDate.toISOString(),\n        daysSinceFaqUpdate: daysSinceFaqUpdate,\n        isOverdue: isOverdue,\n        overdueStatus: isOverdue ? \"OVERDUE\" : \"OK\"\n      }\n    });\n  }\n}\n\nreturn items;"
      },
      "typeVersion": 2
    },
    {
      "id": "173af21d-e158-4a62-a463-9cf19f2207a7",
      "name": "Google Sheets Update Drift Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        288,
        160
      ],
      "parameters": {
        "columns": {
          "value": {
            "SDK Name": "={{ $json.sdkName }}",
            "Release Tag": "={{ $json.latestRelease }}",
            "Release Url": "={{ $json.releaseUrl }}",
            "Release Date": "={{ $json.releaseDate }}",
            "Overdue Status": "={{ $json.overdueStatus }}",
            "Days Since Release": "={{ $json.daysSinceRelease }}",
            "Days Since FAQ Update": "={{ $json.daysSinceFaqUpdate }}",
            "Last FAQ Update(Notion)": "={{ $json.lastFaqUpdate }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_GID",
          "cachedResultName": "SDK Release Tracker"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_GOOGLE_SHEET_ID",
          "cachedResultName": "SDK Release Tracker"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "f0631846-9832-4827-9469-7b19bab41931",
      "name": "Filter Overdue SDKs",
      "type": "n8n-nodes-base.if",
      "position": [
        512,
        160
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "107449cb-3d18-44d4-9eb0-dc12327ef42f",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json['Overdue Status'] }}",
              "rightValue": "OVERDUE"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "21d485f9-e81d-4999-bdbc-7a5bb05d8097",
      "name": "Slack Post Alerts",
      "type": "n8n-nodes-base.slack",
      "position": [
        736,
        160
      ],
      "webhookId": "394999a5-28f2-49e2-9c95-6f9032839311",
      "parameters": {
        "text": "=🚨 SDK Version Drift Alert\n\n*{{ $json['SDK Name'] }}* → {{ $json['Days Since FAQ Update'] }} days since last FAQ update.\n\nLatest Release: {{ $json['Release Date'].split('T')[0] }}\nRelease URL: {{ $json['Release Url'] }}\n\n_Please update documentation in Notion._",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SLACK_CHANNEL_ID",
          "cachedResultName": "sdk-alerts"
        },
        "otherOptions": {}
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "52c620de-ecbf-40c2-a349-f3259a95ed88",
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Function Compute Drift",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Edit Fields": {
      "main": [
        [
          {
            "node": "Google Sheets Log Release Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Notion Fetch FAQ Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Github Trigger": {
      "main": [
        [
          {
            "node": "GitHub Fetch Releases",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Overdue SDKs": {
      "main": [
        [
          {
            "node": "Slack Post Alerts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "GitHub Fetch Releases": {
      "main": [
        [
          {
            "node": "Edit Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notion Fetch FAQ Data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Function Compute Drift": {
      "main": [
        [
          {
            "node": "Google Sheets Update Drift Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets Log Release Data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Sheets Update Drift Status": {
      "main": [
        [
          {
            "node": "Filter Overdue SDKs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

ē›øå…³å·„ä½œęµ