This workflow corresponds to n8n.io template #6763 — we link there as the canonical source.
This workflow follows the Form Trigger → HTTP Request recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "CK1X6HPPuntaDwNl",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Auto\u2011Generate Release Notes",
"tags": [],
"nodes": [
{
"id": "74c1115a-e28b-478e-b4d5-d3c7e890b39c",
"name": "Config",
"type": "n8n-nodes-base.set",
"position": [
200,
40
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "8b87d9c7-3a18-42a9-9ec1-8568fea2908a",
"name": "repoOwner",
"type": "string",
"value": "={{ $json['Repository Owner'] }}"
},
{
"id": "5cac0fee-0aa9-4a4f-a610-8fc3b8682039",
"name": "repoName",
"type": "string",
"value": "={{ $json['Repository Name'] }}"
},
{
"id": "ce2d2b21-55c8-4913-863f-c686e0a51610",
"name": "defaultBranch",
"type": "string",
"value": "={{ $json['Branch Name'] }}"
},
{
"id": "3445fa18-848c-4df5-b5d0-458f978d7cf1",
"name": "=labelMap",
"type": "string",
"value": "{ \"Feature\": \"\ud83d\ude80 Features\", \"bug\": \"\ud83d\udc1e Bug Fixes\", \"performance\": \"\u26a1 Performance\", \"sdk\": \"\ud83d\udce6 SDK / Dependency\" }"
},
{
"id": "29753009-bf1f-40d0-adb9-2ae8135c2eed",
"name": "=qaChecklist",
"type": "string",
"value": "[ \"[ ] App boots successfully\", \"[ ] No crash on startup\", \"[ ] All features tested\", \"[ ] No broken UI on devices\" ]"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "dc575c60-f1ad-439f-8176-0729c109f631",
"name": "Get Latest Git Tag",
"type": "n8n-nodes-base.httpRequest",
"position": [
420,
40
],
"parameters": {
"url": "=https://api.github.com/repos/{{$json[\"repoOwner\"]}}/{{$json[\"repoName\"]}}/tags",
"options": {},
"authentication": "predefinedCredentialType",
"nodeCredentialType": "githubApi"
},
"credentials": {
"githubApi": {
"name": "<your credential>"
},
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "a45ac6c8-8f50-49c8-97cd-24e57d3b9c24",
"name": "Get Commit Date of Latest Tag",
"type": "n8n-nodes-base.httpRequest",
"position": [
640,
40
],
"parameters": {
"url": "={{$json[\"commit\"][\"url\"]}}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "51399899-3a7b-44d3-9067-64e474d0a00a",
"name": "Fetch All Merged PRs Since Last Tag",
"type": "n8n-nodes-base.httpRequest",
"position": [
860,
40
],
"parameters": {
"url": "=https://api.github.com/search/issues?q=is:pr+is:merged+repo:{{ $('Config').first().json.repoOwner }}/{{ $('Config').first().json.repoName }}+base:{{ $('Config').first().json.defaultBranch }}+merged:>={{ $json.commit.author.date }}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "ed1609f1-f1c0-4c15-adb5-b116af6e0a44",
"name": "Adjusted: Group PRs & Generate Release Notes",
"type": "n8n-nodes-base.code",
"position": [
1080,
40
],
"parameters": {
"jsCode": "// SAFELY access config node data\nconst configNode = $('Config').first();\nif (!configNode) {\n throw new Error(\"Missing 'Config' node or it's not accessible.\");\n}\n\nconst labelMap = configNode.labelMap|| {};\nconst qaChecklist = configNode.qaChecklist || [];\n\nconsole.log(\"Your message\", labelMap);\nconsole.log(\"Your message\", qaChecklist);\n\n// Access PR list from previous node\nconst prNode = $('Fetch All Merged PRs Since Last Tag').first(); // <-- Replace with your actual PR-fetch node name\nif (!prNode || !prNode.json || !Array.isArray(prNode.json.items)) {\n throw new Error(\"Pull request data not found or improperly formatted.\");\n}\n\nconst prItems = prNode.json.items;\n\n/** @type {Record<string, string[]>} */\nconst grouped = {};\n\n// Loop through each PR\nfor (const pr of prItems) {\n const labels = pr.labels?.map(l => l.name) || [];\n const matchedKey = labels.find(l => labelMap[l]);\n const groupTitle = matchedKey ? labelMap[matchedKey] : \"\ud83d\udccb Others\";\n\n if (!grouped[groupTitle]) {\n grouped[groupTitle] = [];\n }\n\n grouped[groupTitle].push(`- ${pr.title} (#${pr.number})`);\n}\n\n// Build Markdown content\nlet markdown = `## \ud83d\udcdd Release Notes\\n`;\n\nfor (const group in grouped) {\n markdown += `\\n### ${group}\\n`;\n markdown += grouped[group].join(\"\\n\") + \"\\n\";\n}\n\nmarkdown += `\\n## \u2705 QA Checklist\\n`;\nmarkdown += qaChecklist.map(item => `[ ] ${item}`).join(\"\\n\");\n\nreturn [\n {\n json: {\n release_notes: markdown,\n },\n },\n];"
},
"typeVersion": 2
},
{
"id": "589e2cf2-e5f5-4411-a0ba-a4f705d242f9",
"name": "Github Pre Release",
"type": "n8n-nodes-base.httpRequest",
"position": [
1300,
40
],
"parameters": {
"url": "=https://api.github.com/repos/{{ $('Config').first().json.repoOwner }}/{{ $('Config').first().json.repoName }}/releases",
"method": "POST",
"options": {},
"sendBody": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "tag_name",
"value": "={{ $('Get Latest Git Tag').first().json.name }}"
},
{
"name": "name",
"value": "={{ $('Get Latest Git Tag').first().json.name }}"
},
{
"name": "body",
"value": "={{ $json.release_notes }}"
},
{
"name": "draft",
"value": "={{ true }}"
},
{
"name": "prerelease",
"value": "={{ false }}"
}
]
},
"genericAuthType": "httpHeaderAuth"
},
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "2190c525-95c9-49e8-84de-e13df0d826e5",
"name": " Send message to slack",
"type": "n8n-nodes-base.httpRequest",
"position": [
1520,
40
],
"parameters": {
"url": "",
"method": "POST",
"options": {},
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "={{ $('Adjusted: Group PRs & Generate Release Notes').item.json.release_notes }} {{ $json.html_url }}"
}
]
}
},
"typeVersion": 4.2
},
{
"id": "6c385b76-cc8e-4cbd-b086-0e2c7e9f42bc",
"name": "GitHub Release Input Form",
"type": "n8n-nodes-base.formTrigger",
"position": [
-20,
40
],
"parameters": {
"options": {},
"formTitle": "GitHub Release Input Form",
"formFields": {
"values": [
{
"fieldLabel": "Repository Name",
"placeholder": "Enter name of the repository",
"requiredField": true
},
{
"fieldLabel": "Repository Owner",
"placeholder": "Enter username of github",
"requiredField": true
},
{
"fieldLabel": "Branch Name",
"placeholder": "Enter branch name ",
"requiredField": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "bd0ad833-757e-4619-b31a-7abfef910fe7",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
-60
],
"parameters": {
"width": 1860,
"height": 360,
"content": "## Auto\u2011Generate Release Notes for Any GitHub Repo \u2192 Slack"
},
"typeVersion": 1
},
{
"id": "fa9609ed-9ef4-43b7-b1e5-1b2245cdc657",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
320
],
"parameters": {
"width": 1880,
"height": 1260,
"content": "#\ud83d\ude80 GitHub Automated Release Workflow (n8n)\n\nThis workflow auto-generates release notes from merged pull requests and creates a draft GitHub release, notifying via Slack. Below are the descriptions for each node involved:\n\n\u2e3b\n\n\ud83e\udde9 1. GitHub Release Input Form\n\t\u2022\tPurpose: Collects user input for:\n\t\u2022\towner: GitHub username/org\n\t\u2022\trepo: Repository name\n\t\u2022\tbranch: Target base branch\n\n\u2e3b\n\n\u2699\ufe0f 2. Config\n\t\u2022\tPurpose:\n\t\u2022\tExtracts user input from the form node.\n\t\u2022\tDefines the label grouping map to classify PRs under sections like feature, bug, performance, etc.\n\n\u2e3b\n\n\ud83d\udd16 3. Get Latest Git Tag\n\t\u2022\tPurpose: Fetches the most recent semantic Git tag from the selected repository.\n\t\u2022\tWhy: Used to determine what PRs were merged after the last release.\n\n\u2e3b\n\n\ud83d\udd52 4. Get Commit Date of Latest Tag\n\t\u2022\tPurpose: Retrieves the commit timestamp for the latest tag.\n\t\u2022\tWhy: This timestamp is used to filter only the PRs merged after the last release.\n\n\u2e3b\n\n\ud83d\udce5 5. Fetch All Merged PRs Since Last Tag\n\t\u2022\tPurpose: Queries GitHub\u2019s Search API for pull requests:\n\t\u2022\tThat are merged.\n\t\u2022\tMerged after the latest tag\u2019s commit date.\n\t\u2022\tOn the selected base branch.\n\t\u2022\tWhy: Ensures only new, relevant PRs are included in the release.\n\n\u2e3b\n\n\ud83e\udde0 6. Adjusted: Group PRs & Generate Release Note\n\t\u2022\tPurpose:\n\t\u2022\tGroups the filtered PRs by label (using Config map).\n\t\u2022\tFormats them into a clean Markdown release note.\n\t\u2022\tAdds a \u2705 QA Checklist section at the end.\n\n\u2e3b\n\n\ud83e\ude84 7. GitHub Pre Release\n\t\u2022\tPurpose:\n\t\u2022\tCreates a draft GitHub release.\n\t\u2022\tUses the latest tag and generated notes.\n\t\u2022\tSets:\n\t\u2022\t\"draft\": true\n\t\u2022\t\"prerelease\": false\n\n\u2e3b\n\n\ud83d\udcac 8. Send Message to Slack\n\t\u2022\tPurpose: Posts the release summary to a designated Slack channel.\n\t\u2022\tIncludes: Tag name, categorized release notes, and optionally a link to the GitHub release."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "e0e3b36d-59a8-4ec1-a1e5-5a19fb5063ed",
"connections": {
"Config": {
"main": [
[
{
"node": "Get Latest Git Tag",
"type": "main",
"index": 0
}
]
]
},
"Get Latest Git Tag": {
"main": [
[
{
"node": "Get Commit Date of Latest Tag",
"type": "main",
"index": 0
}
]
]
},
"Github Pre Release": {
"main": [
[
{
"node": " Send message to slack",
"type": "main",
"index": 0
}
]
]
},
"GitHub Release Input Form": {
"main": [
[
{
"node": "Config",
"type": "main",
"index": 0
}
]
]
},
"Get Commit Date of Latest Tag": {
"main": [
[
{
"node": "Fetch All Merged PRs Since Last Tag",
"type": "main",
"index": 0
}
]
]
},
"Fetch All Merged PRs Since Last Tag": {
"main": [
[
{
"node": "Adjusted: Group PRs & Generate Release Notes",
"type": "main",
"index": 0
}
]
]
},
"Adjusted: Group PRs & Generate Release Notes": {
"main": [
[
{
"node": "Github Pre Release",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
githubApihttpHeaderAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This n8n workflow automates the process of: Generating structured GitHub release notes from merged pull requests since the last tag. Creating a draft GitHub release using the latest tag and PR info. Sending a formatted summary to a Slack channel.
Source: https://n8n.io/workflows/6763/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This n8n workflow automates the process of scraping Google Play Store reviews, analyzing app performance, and sending alerts for low-rated applications. It integrates with Bright Data for web scraping
Weather Bot - Main Handler. Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 65 nodes.
This n8n workflow provides automated monitoring of Public Key Infrastructure (PKI) components including CA certificates, Certificate Revocation Lists (CRLs), and associated web services. It extracts c
Track all n8n workflow failures with automatic error capture, severity classification, duplicate detection, Slack alerting, performance metrics, and log retention.
Stay ahead of payment disputes with this automated n8n workflow that integrates Stripe, Slack, and ClickUp. Perfect for finance teams, payment ops specialists, and SaaS businesses, this template fetch