mirror of
				https://github.com/community-scripts/ProxmoxVE.git
				synced 2025-11-04 10:22:50 +00:00 
			
		
		
		
	Updated Changelog Workflow (#2632)
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							599a518cc3
						
					
				
				
					commit
					3401b76c44
				
			
							
								
								
									
										2
									
								
								.github/autolabeler-config.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/autolabeler-config.json
									
									
									
									
										vendored
									
									
								
							@@ -67,5 +67,5 @@
 | 
				
			|||||||
      "includeGlobs": ["misc/build.func", "misc/install.func", "ct/create_lxc.sh"],
 | 
					      "includeGlobs": ["misc/build.func", "misc/install.func", "ct/create_lxc.sh"],
 | 
				
			||||||
      "excludeGlobs": []
 | 
					      "excludeGlobs": []
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  ]
 | 
					  ]  
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								.github/changelog-pr-config.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								.github/changelog-pr-config.json
									
									
									
									
										vendored
									
									
								
							@@ -7,14 +7,27 @@
 | 
				
			|||||||
    "title": "🆕 New Scripts",
 | 
					    "title": "🆕 New Scripts",
 | 
				
			||||||
    "labels": ["new script"]
 | 
					    "labels": ["new script"]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
    "title": "🐞 Bug Fixes",
 | 
					 | 
				
			||||||
    "labels": ["bugfix"]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "title": "✨ New Features",
 | 
					    "title": "✨ New Features",
 | 
				
			||||||
    "labels": ["feature"]
 | 
					    "labels": ["feature"]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    "title": "🚀 Updated Scripts",
 | 
				
			||||||
 | 
					    "labels": ["update script"],
 | 
				
			||||||
 | 
					    "subCategories": [
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "title": "🐞 Bug Fixes",
 | 
				
			||||||
 | 
					        "labels": ["bugfix"],
 | 
				
			||||||
 | 
					        "notes" : []
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      {
 | 
				
			||||||
 | 
					        "title": "General Updates",
 | 
				
			||||||
 | 
					        "labels": ["general"],
 | 
				
			||||||
 | 
					        "notes" : []
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    "title": "🌐 Website",
 | 
					    "title": "🌐 Website",
 | 
				
			||||||
    "labels": ["website"]
 | 
					    "labels": ["website"]
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										43
									
								
								.github/workflows/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										43
									
								
								.github/workflows/autolabeler.yml
									
									
									
									
										vendored
									
									
								
							@@ -32,8 +32,8 @@ jobs:
 | 
				
			|||||||
            const autolabelerConfig = JSON.parse(fileContent);
 | 
					            const autolabelerConfig = JSON.parse(fileContent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const prNumber = context.payload.pull_request.number;
 | 
					            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();
 | 
					            let labelsToAdd = new Set();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const prListFilesResponse = await github.rest.pulls.listFiles({
 | 
					            const prListFilesResponse = await github.rest.pulls.listFiles({
 | 
				
			||||||
@@ -42,14 +42,35 @@ jobs:
 | 
				
			|||||||
              pull_number: prNumber,
 | 
					              pull_number: prNumber,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            const prFiles = prListFilesResponse.data;
 | 
					            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)) {
 | 
					            for (const [label, rules] of Object.entries(autolabelerConfig)) {
 | 
				
			||||||
              const shouldAddLabel = prFiles.some((prFile) => {
 | 
					              const shouldAddLabel = prFiles.some((prFile) => {
 | 
				
			||||||
                return rules.some((rule) => {
 | 
					                return rules.some((rule) => {
 | 
				
			||||||
                  const isFileStatusMatch = rule.fileStatus ? rule.fileStatus === prFile.status : true;
 | 
					                  const isFileStatusMatch = rule.fileStatus ? rule.fileStatus === prFile.status : true;
 | 
				
			||||||
                  const isIncludeGlobMatch = rule.includeGlobs.some((glob) => minimatch(prFile.filename, glob));
 | 
					                  const isIncludeGlobMatch = rule.includeGlobs.some((glob) => minimatch(prFile.filename, glob));
 | 
				
			||||||
                  const isExcludeGlobMatch = rule.excludeGlobs.some((glob) => minimatch(prFile.filename, glob));
 | 
					                  const isExcludeGlobMatch = rule.excludeGlobs.some((glob) => minimatch(prFile.filename, glob));
 | 
				
			||||||
                  
 | 
					
 | 
				
			||||||
                  return isFileStatusMatch && isIncludeGlobMatch && !isExcludeGlobMatch;
 | 
					                  return isFileStatusMatch && isIncludeGlobMatch && !isExcludeGlobMatch;
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
              });
 | 
					              });
 | 
				
			||||||
@@ -58,21 +79,7 @@ jobs:
 | 
				
			|||||||
                labelsToAdd.add(label);
 | 
					                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(", ")}`);
 | 
					            console.log(`Labels to add: ${Array.from(labelsToAdd).join(", ")}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (labelsToAdd.size > 0) {
 | 
					            if (labelsToAdd.size > 0) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										89
									
								
								.github/workflows/changelog-pr.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										89
									
								
								.github/workflows/changelog-pr.yml
									
									
									
									
										vendored
									
									
								
							@@ -30,7 +30,6 @@ jobs:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      - name: Get latest dates in changelog
 | 
					      - name: Get latest dates in changelog
 | 
				
			||||||
        run: |
 | 
					        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}')
 | 
					          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')
 | 
					          LATEST_DATE=$(echo "$DATES" | sed -n '1p')
 | 
				
			||||||
@@ -55,7 +54,15 @@ jobs:
 | 
				
			|||||||
            const configPath = path.resolve(process.env.CONFIG_PATH);
 | 
					            const configPath = path.resolve(process.env.CONFIG_PATH);
 | 
				
			||||||
            const fileContent = await fs.readFile(configPath, 'utf-8');
 | 
					            const fileContent = await fs.readFile(configPath, 'utf-8');
 | 
				
			||||||
            const changelogConfig = JSON.parse(fileContent);
 | 
					            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);
 | 
					            const latestDateInChangelog = new Date(process.env.LATEST_DATE);
 | 
				
			||||||
            latestDateInChangelog.setUTCHours(23, 59, 59, 999);
 | 
					            latestDateInChangelog.setUTCHours(23, 59, 59, 999);
 | 
				
			||||||
@@ -70,40 +77,36 @@ jobs:
 | 
				
			|||||||
              per_page: 100,
 | 
					              per_page: 100,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            pulls.filter(pr => 
 | 
					            pulls.filter(pr =>
 | 
				
			||||||
              pr.merged_at && 
 | 
					            pr.merged_at &&
 | 
				
			||||||
              new Date(pr.merged_at) > latestDateInChangelog && 
 | 
					            new Date(pr.merged_at) > latestDateInChangelog &&
 | 
				
			||||||
              !pr.labels.some(label => ["invalid", "wontdo", process.env.AUTOMATED_PR_LABEL].includes(label.name.toLowerCase()))
 | 
					            !pr.labels.some(label =>
 | 
				
			||||||
 | 
					              ["invalid", "wontdo", process.env.AUTOMATED_PR_LABEL].includes(label.name.toLowerCase())
 | 
				
			||||||
 | 
					              )
 | 
				
			||||||
            ).forEach(pr => {
 | 
					            ).forEach(pr => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              const prLabels = pr.labels.map(label => label.name.toLowerCase());
 | 
					              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}))`;
 | 
					              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 (updateScriptsCategory) {
 | 
				
			||||||
                // If no labels are specified (e.g., "Unlabelled"), assign to this category
 | 
					                
 | 
				
			||||||
                if (labels.length === 0 && prLabels.length === 0) {
 | 
					                const subCategory = updateScriptsCategory.subCategories.find(sub =>
 | 
				
			||||||
                  notes.push(prNote);
 | 
					                  sub.labels.some(label => prLabels.includes(label))
 | 
				
			||||||
                  isCategorized = true;
 | 
					                );
 | 
				
			||||||
                  break;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // If labels are specified, check if PR has ALL required labels
 | 
					                if (subCategory) {
 | 
				
			||||||
                if (labels.length > 0 && labels.every(label => prLabels.includes(label.toLowerCase()))) {
 | 
					                  subCategory.notes.push(prNote);
 | 
				
			||||||
                  notes.push(prNote);
 | 
					                } else {
 | 
				
			||||||
                  isCategorized = true;
 | 
					                  updateScriptsCategory.notes.push(prNote);
 | 
				
			||||||
                  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);
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            console.log(JSON.stringify(categorizedPRs, null, 2));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return categorizedPRs;
 | 
					            return categorizedPRs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -119,13 +122,33 @@ jobs:
 | 
				
			|||||||
            const changelogPath = path.resolve('CHANGELOG.md');
 | 
					            const changelogPath = path.resolve('CHANGELOG.md');
 | 
				
			||||||
            const categorizedPRs = ${{ steps.get-categorized-prs.outputs.result }};
 | 
					            const categorizedPRs = ${{ steps.get-categorized-prs.outputs.result }};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            let newReleaseNotes = `## ${today}\n\n### Changes\n\n`;
 | 
					            console.log(JSON.stringify(categorizedPRs, null, 2));
 | 
				
			||||||
            for (const { title, notes } of categorizedPRs) {
 | 
					 | 
				
			||||||
              if (notes.length > 0) {
 | 
					 | 
				
			||||||
                newReleaseNotes += `### ${title}\n\n${notes.join("\n")}\n\n`;
 | 
					 | 
				
			||||||
              }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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 changelogContent = await fs.readFile(changelogPath, 'utf-8');
 | 
				
			||||||
            const changelogIncludesTodaysReleaseNotes = changelogContent.includes(`\n## ${today}`);
 | 
					            const changelogIncludesTodaysReleaseNotes = changelogContent.includes(`\n## ${today}`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user