From 3401b76c44926295a752983d30cd00f7a506efaa Mon Sep 17 00:00:00 2001 From: Michel Roegl-Brunner <73236783+michelroegl-brunner@users.noreply.github.com> Date: Tue, 25 Feb 2025 12:27:31 +0200 Subject: [PATCH] Updated Changelog Workflow (#2632) --- .github/autolabeler-config.json | 2 +- .github/changelog-pr-config.json | 21 +++++-- .github/workflows/autolabeler.yml | 43 +++++++++------ .github/workflows/changelog-pr.yml | 89 +++++++++++++++++++----------- 4 files changed, 99 insertions(+), 56 deletions(-) diff --git a/.github/autolabeler-config.json b/.github/autolabeler-config.json index 399004ee1..43c272f87 100644 --- a/.github/autolabeler-config.json +++ b/.github/autolabeler-config.json @@ -67,5 +67,5 @@ "includeGlobs": ["misc/build.func", "misc/install.func", "ct/create_lxc.sh"], "excludeGlobs": [] } - ] + ] } diff --git a/.github/changelog-pr-config.json b/.github/changelog-pr-config.json index 56401f4fc..558f32fe1 100644 --- a/.github/changelog-pr-config.json +++ b/.github/changelog-pr-config.json @@ -7,14 +7,27 @@ "title": "🆕 New Scripts", "labels": ["new script"] }, - { - "title": "🐞 Bug Fixes", - "labels": ["bugfix"] - }, { "title": "✨ New Features", "labels": ["feature"] }, + { + "title": "🚀 Updated Scripts", + "labels": ["update script"], + "subCategories": [ + { + "title": "🐞 Bug Fixes", + "labels": ["bugfix"], + "notes" : [] + }, + { + "title": "General Updates", + "labels": ["general"], + "notes" : [] + } + ] + }, + { "title": "🌐 Website", "labels": ["website"] diff --git a/.github/workflows/autolabeler.yml b/.github/workflows/autolabeler.yml index 4e0a04348..0051d787d 100644 --- a/.github/workflows/autolabeler.yml +++ b/.github/workflows/autolabeler.yml @@ -32,8 +32,8 @@ jobs: const autolabelerConfig = JSON.parse(fileContent); const prNumber = context.payload.pull_request.number; - const prBody = context.payload.pull_request.body; - + const prBody = context.payload.pull_request.body.toLowerCase(); + let labelsToAdd = new Set(); const prListFilesResponse = await github.rest.pulls.listFiles({ @@ -42,14 +42,35 @@ jobs: pull_number: prNumber, }); const prFiles = prListFilesResponse.data; + + const templateLabelMappings = { + "🐞 **bug fix**": "bugfix", + "✨ **new feature**": "feature", + "💥 **breaking change**": "breaking change", + "🆕 **new script**": "new script" + }; + + for (const [checkbox, label] of Object.entries(templateLabelMappings)) { + const escapedCheckbox = checkbox.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); + const regex = new RegExp(`- \\[(x|X)\\]\\s*.*${escapedCheckbox}`, "i"); + const match = prBody.match(regex); + if (match) { + console.log(`Match: ${match}`); + labelsToAdd.add(label); + } + } + if (labelsToAdd.size === 0) { + labelsToAdd.add("general"); + } + // Apply labels based on file changes for (const [label, rules] of Object.entries(autolabelerConfig)) { const shouldAddLabel = prFiles.some((prFile) => { return rules.some((rule) => { const isFileStatusMatch = rule.fileStatus ? rule.fileStatus === prFile.status : true; const isIncludeGlobMatch = rule.includeGlobs.some((glob) => minimatch(prFile.filename, glob)); const isExcludeGlobMatch = rule.excludeGlobs.some((glob) => minimatch(prFile.filename, glob)); - + return isFileStatusMatch && isIncludeGlobMatch && !isExcludeGlobMatch; }); }); @@ -58,21 +79,7 @@ jobs: labelsToAdd.add(label); } } - - const templateLabelMappings = { - "🐞 bug fix": "bugfix", - "✨ new feature": "feature", - "💥 breaking change": "breaking change", - "🆕 new script": "new script" - }; - - for (const [checkbox, label] of Object.entries(templateLabelMappings)) { - const regex = new RegExp(`- \\[x\\] ${checkbox}`, "i"); // Match only checked checkboxes - if (regex.test(prBody)) { - labelsToAdd.add(label); - } - } - + console.log(`Labels to add: ${Array.from(labelsToAdd).join(", ")}`); if (labelsToAdd.size > 0) { diff --git a/.github/workflows/changelog-pr.yml b/.github/workflows/changelog-pr.yml index 58bfd8a4a..5ca3b9bd7 100644 --- a/.github/workflows/changelog-pr.yml +++ b/.github/workflows/changelog-pr.yml @@ -30,7 +30,6 @@ jobs: - name: Get latest dates in changelog run: | - # Extrahiere die neuesten zwei Daten aus dem Changelog DATES=$(grep -E '^## [0-9]{4}-[0-9]{2}-[0-9]{2}' CHANGELOG.md | head -n 2 | awk '{print $2}') LATEST_DATE=$(echo "$DATES" | sed -n '1p') @@ -55,7 +54,15 @@ jobs: const configPath = path.resolve(process.env.CONFIG_PATH); const fileContent = await fs.readFile(configPath, 'utf-8'); const changelogConfig = JSON.parse(fileContent); - const categorizedPRs = changelogConfig.map(obj => ({ ...obj, notes: [] })); + + const categorizedPRs = changelogConfig.map(obj => ({ + ...obj, + notes: [], + subCategories: obj.subCategories ?? (obj.labels.includes("update script") ? [ + { title: "🐞 Bug Fixes", labels: ["bugfix"] }, + { title: "✨ Feature Updates", labels: ["feature"] } + ] : []) + })); const latestDateInChangelog = new Date(process.env.LATEST_DATE); latestDateInChangelog.setUTCHours(23, 59, 59, 999); @@ -70,40 +77,36 @@ jobs: per_page: 100, }); - pulls.filter(pr => - pr.merged_at && - new Date(pr.merged_at) > latestDateInChangelog && - !pr.labels.some(label => ["invalid", "wontdo", process.env.AUTOMATED_PR_LABEL].includes(label.name.toLowerCase())) + pulls.filter(pr => + pr.merged_at && + new Date(pr.merged_at) > latestDateInChangelog && + !pr.labels.some(label => + ["invalid", "wontdo", process.env.AUTOMATED_PR_LABEL].includes(label.name.toLowerCase()) + ) ).forEach(pr => { + const prLabels = pr.labels.map(label => label.name.toLowerCase()); const prNote = `- ${pr.title} [@${pr.user.login}](https://github.com/${pr.user.login}) ([#${pr.number}](${pr.html_url}))`; - let isCategorized = false; + const updateScriptsCategory = categorizedPRs.find(category => + category.labels.some(label => prLabels.includes(label)) + ); - for (const { labels, notes } of categorizedPRs) { - // If no labels are specified (e.g., "Unlabelled"), assign to this category - if (labels.length === 0 && prLabels.length === 0) { - notes.push(prNote); - isCategorized = true; - break; - } + if (updateScriptsCategory) { + + const subCategory = updateScriptsCategory.subCategories.find(sub => + sub.labels.some(label => prLabels.includes(label)) + ); - // If labels are specified, check if PR has ALL required labels - if (labels.length > 0 && labels.every(label => prLabels.includes(label.toLowerCase()))) { - notes.push(prNote); - isCategorized = true; - break; - } - } - - // If PR is not categorized, assign it to the "Unlabelled" category - if (!isCategorized) { - const unlabelledCategory = categorizedPRs.find(cat => cat.title === "❔ Unlabelled"); - if (unlabelledCategory) { - unlabelledCategory.notes.push(prNote); + if (subCategory) { + subCategory.notes.push(prNote); + } else { + updateScriptsCategory.notes.push(prNote); } } }); + + console.log(JSON.stringify(categorizedPRs, null, 2)); return categorizedPRs; @@ -119,13 +122,33 @@ jobs: const changelogPath = path.resolve('CHANGELOG.md'); const categorizedPRs = ${{ steps.get-categorized-prs.outputs.result }}; - let newReleaseNotes = `## ${today}\n\n### Changes\n\n`; - for (const { title, notes } of categorizedPRs) { - if (notes.length > 0) { - newReleaseNotes += `### ${title}\n\n${notes.join("\n")}\n\n`; - } - } + console.log(JSON.stringify(categorizedPRs, null, 2)); + let newReleaseNotes = `## ${today}\n\n### Changes\n\n`; + for (const { title, notes, subCategories } of categorizedPRs) { + const hasSubcategories = subCategories && subCategories.length > 0; + const hasMainNotes = notes.length > 0; + const hasSubNotes = hasSubcategories && subCategories.some(sub => sub.notes && sub.notes.length > 0); + + + if (hasMainNotes || hasSubNotes) { + newReleaseNotes += `### ${title}\n\n`; + } + + if (hasMainNotes) { + newReleaseNotes += `${notes.join("\n")}\n\n`; + } + + if (hasSubcategories) { + for (const { title: subTitle, notes: subNotes } of subCategories) { + if (subNotes && subNotes.length > 0) { + newReleaseNotes += ` #### ${subTitle}\n\n`; + newReleaseNotes += ` ${subNotes.join("\n ")}\n\n`; + } + } + } + } + const changelogContent = await fs.readFile(changelogPath, 'utf-8'); const changelogIncludesTodaysReleaseNotes = changelogContent.includes(`\n## ${today}`);