Génération automatique de notes de version
Ceci est unDevOpsworkflow d'automatisation du domainecontenant 10 nœuds.Utilise principalement des nœuds comme Set, Code, FormTrigger, HttpRequest. Générer automatiquement les notes de version GitHub et envoyer une notification Slack
- •Peut nécessiter les informations d'identification d'authentification de l'API cible
Nœuds utilisés (10)
Catégorie
{
"id": "CK1X6HPPuntaDwNl",
"meta": {
"instanceId": "14e4c77104722ab186539dfea5182e419aecc83d85963fe13f6de862c875ebfa",
"templateCredsSetupCompleted": true
},
"name": "Auto‑Generate 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\": \"🚀 Features\", \"bug\": \"🐞 Bug Fixes\", \"performance\": \"⚡ Performance\", \"sdk\": \"📦 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": "Obtenir la dernière étiquette Git",
"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": {
"id": "sWK5QVSgNgKCkpaF",
"name": "GitHub account"
},
"httpHeaderAuth": {
"id": "Q6oCLdEppyzR0Uga",
"name": "Header Auth account 3"
}
},
"typeVersion": 4.2
},
{
"id": "a45ac6c8-8f50-49c8-97cd-24e57d3b9c24",
"name": "Obtenir la date de commit de la dernière étiquette",
"type": "n8n-nodes-base.httpRequest",
"position": [
640,
40
],
"parameters": {
"url": "={{$json[\"commit\"][\"url\"]}}",
"options": {}
},
"typeVersion": 4.2
},
{
"id": "51399899-3a7b-44d3-9067-64e474d0a00a",
"name": "Récupérer toutes les PR fusionnées depuis la dernière étiquette",
"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": "Ajusté : Grouper les PR et générer les notes de publication",
"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] : \"📋 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 = `## 📝 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## ✅ 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 Pré-publication",
"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": {
"id": "Q6oCLdEppyzR0Uga",
"name": "Header Auth account 3"
}
},
"typeVersion": 4.2
},
{
"id": "2190c525-95c9-49e8-84de-e13df0d826e5",
"name": "Envoyer un message à 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 Formulaire de saisie de publication",
"type": "n8n-nodes-base.formTrigger",
"position": [
-20,
40
],
"webhookId": "80253212-d5c6-4542-9dba-b9ec3f7cc48d",
"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": "Note autocollante",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
-60
],
"parameters": {
"width": 1860,
"height": 360,
"content": "## Auto‑Generate Release Notes for Any GitHub Repo → Slack"
},
"typeVersion": 1
},
{
"id": "fa9609ed-9ef4-43b7-b1e5-1b2245cdc657",
"name": "Note autocollante 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-100,
320
],
"parameters": {
"width": 1880,
"height": 1260,
"content": "#🚀 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⸻\n\n🧩 1. GitHub Release Input Form\n\t•\tPurpose: Collects user input for:\n\t•\towner: GitHub username/org\n\t•\trepo: Repository name\n\t•\tbranch: Target base branch\n\n⸻\n\n⚙️ 2. Config\n\t•\tPurpose:\n\t•\tExtracts user input from the form node.\n\t•\tDefines the label grouping map to classify PRs under sections like feature, bug, performance, etc.\n\n⸻\n\n🔖 3. Get Latest Git Tag\n\t•\tPurpose: Fetches the most recent semantic Git tag from the selected repository.\n\t•\tWhy: Used to determine what PRs were merged after the last release.\n\n⸻\n\n🕒 4. Get Commit Date of Latest Tag\n\t•\tPurpose: Retrieves the commit timestamp for the latest tag.\n\t•\tWhy: This timestamp is used to filter only the PRs merged after the last release.\n\n⸻\n\n📥 5. Fetch All Merged PRs Since Last Tag\n\t•\tPurpose: Queries GitHub’s Search API for pull requests:\n\t•\tThat are merged.\n\t•\tMerged after the latest tag’s commit date.\n\t•\tOn the selected base branch.\n\t•\tWhy: Ensures only new, relevant PRs are included in the release.\n\n⸻\n\n🧠 6. Adjusted: Group PRs & Generate Release Note\n\t•\tPurpose:\n\t•\tGroups the filtered PRs by label (using Config map).\n\t•\tFormats them into a clean Markdown release note.\n\t•\tAdds a ✅ QA Checklist section at the end.\n\n⸻\n\n🪄 7. GitHub Pre Release\n\t•\tPurpose:\n\t•\tCreates a draft GitHub release.\n\t•\tUses the latest tag and generated notes.\n\t•\tSets:\n\t•\t\"draft\": true\n\t•\t\"prerelease\": false\n\n⸻\n\n💬 8. Send Message to Slack\n\t•\tPurpose: Posts the release summary to a designated Slack channel.\n\t•\tIncludes: Tag name, categorized release notes, and optionally a link to the GitHub release."
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "e0e3b36d-59a8-4ec1-a1e5-5a19fb5063ed",
"connections": {
"74c1115a-e28b-478e-b4d5-d3c7e890b39c": {
"main": [
[
{
"node": "dc575c60-f1ad-439f-8176-0729c109f631",
"type": "main",
"index": 0
}
]
]
},
"dc575c60-f1ad-439f-8176-0729c109f631": {
"main": [
[
{
"node": "a45ac6c8-8f50-49c8-97cd-24e57d3b9c24",
"type": "main",
"index": 0
}
]
]
},
"589e2cf2-e5f5-4411-a0ba-a4f705d242f9": {
"main": [
[
{
"node": "2190c525-95c9-49e8-84de-e13df0d826e5",
"type": "main",
"index": 0
}
]
]
},
"6c385b76-cc8e-4cbd-b086-0e2c7e9f42bc": {
"main": [
[
{
"node": "74c1115a-e28b-478e-b4d5-d3c7e890b39c",
"type": "main",
"index": 0
}
]
]
},
"a45ac6c8-8f50-49c8-97cd-24e57d3b9c24": {
"main": [
[
{
"node": "51399899-3a7b-44d3-9067-64e474d0a00a",
"type": "main",
"index": 0
}
]
]
},
"51399899-3a7b-44d3-9067-64e474d0a00a": {
"main": [
[
{
"node": "ed1609f1-f1c0-4c15-adb5-b116af6e0a44",
"type": "main",
"index": 0
}
]
]
},
"ed1609f1-f1c0-4c15-adb5-b116af6e0a44": {
"main": [
[
{
"node": "589e2cf2-e5f5-4411-a0ba-a4f705d242f9",
"type": "main",
"index": 0
}
]
]
}
}
}Comment utiliser ce workflow ?
Copiez le code de configuration JSON ci-dessus, créez un nouveau workflow dans votre instance n8n et sélectionnez "Importer depuis le JSON", collez la configuration et modifiez les paramètres d'authentification selon vos besoins.
Dans quelles scénarios ce workflow est-il adapté ?
Intermédiaire - DevOps
Est-ce payant ?
Ce workflow est entièrement gratuit et peut être utilisé directement. Veuillez noter que les services tiers utilisés dans le workflow (comme l'API OpenAI) peuvent nécessiter un paiement de votre part.
Workflows recommandés
WeblineIndia
@weblineindiaA Leading Software Engineering, Consulting & Outsourcing Services Company in USA & India serving Clients Globally since 1999.
Partager ce workflow