From f678d7f04afa80d4b575d7f8c8f77f5cd912d946 Mon Sep 17 00:00:00 2001 From: Piras314 <92357316+Piras314@users.noreply.github.com> Date: Fri, 14 Jun 2024 17:50:15 -0400 Subject: [PATCH] Update changelog.js --- Tools/changelog/changelog.js | 209 +++++++++++++++++++++++++---------- 1 file changed, 153 insertions(+), 56 deletions(-) diff --git a/Tools/changelog/changelog.js b/Tools/changelog/changelog.js index fa5732e06d9..8396b12db70 100644 --- a/Tools/changelog/changelog.js +++ b/Tools/changelog/changelog.js @@ -1,57 +1,154 @@ // From https://github.com/DeltaV-Station/Delta-v/ -name: PR Changelogs -concurrency: commit_action -on: - pull_request_target: - types: [closed] - -env: - GITHUB_TOKEN: ${{ secrets.BOT_TOKEN }} - CHANGELOG_DIR: ${{ vars.CHANGELOG_DIR }} - PR_NUMBER: ${{ github.event.number }} - -jobs: - changelog: - runs-on: self-hosted - if: github.event.pull_request.merged == true - permissions: - contents: write - steps: - - name: Checkout Master - uses: actions/checkout@v3 - with: - token: ${{ secrets.BOT_TOKEN }} - ref: "${{ vars.CHANGELOG_BRANCH }}" - - - name: Setup Git - run: | - git config --global user.name "${{ vars.CHANGELOG_USER }}" - git config --global user.email "${{ vars.CHANGELOG_EMAIL }}" - shell: bash - - - name: Setup Node - uses: actions/setup-node@v3 - with: - node-version: 18.x - - - name: Install Dependencies - run: | - cd "Tools/changelog" - npm install - shell: bash - continue-on-error: true - - - name: Generate Changelog - run: | - cd "Tools/changelog" - node changelog.js - shell: bash - continue-on-error: true - - - name: Commit Changelog - run: | - git add *.yml - git commit -m "${{ vars.CHANGELOG_MESSAGE }} (#${{ env.PR_NUMBER }})" - git push - shell: bash - continue-on-error: true +// Dependencies +const fs = require("fs"); +const yaml = require("js-yaml"); +const axios = require("axios"); + +// Use GitHub token if available +if (process.env.GITHUB_TOKEN) axios.defaults.headers.common["Authorization"] = `Bearer ${process.env.GITHUB_TOKEN}`; + +// Regexes +const HeaderRegex = /^\s*(?::cl:|🆑) *([a-z0-9_\- ]+)?\s+/im; // :cl: or 🆑 [0] followed by optional author name [1] +const EntryRegex = /^ *[*-]? *(add|remove|tweak|fix): *([^\n\r]+)\r?$/img; // * or - followed by change type [0] and change message [1] +const CommentRegex = //gs; // HTML comments + +// Main function +async function main() { + // Get PR details + const pr = await axios.get(`https://api.github.com/repos/${process.env.GITHUB_REPOSITORY}/pulls/${process.env.PR_NUMBER}`); + const { merged_at, body, user } = pr.data; + + // Remove comments from the body + commentlessBody = body.replace(CommentRegex, ''); + + // Get author + const headerMatch = HeaderRegex.exec(commentlessBody); + if (!headerMatch) { + console.log("No changelog entry found, skipping"); + return; + } + + let author = headerMatch[1]; + if (!author) { + console.log("No author found, setting it to author of the PR\n"); + author = user.login; + } + + // Get all changes from the body + const entries = getChanges(commentlessBody); + + + // Time is something like 2021-08-29T20:00:00Z + // Time should be something like 2023-02-18T00:00:00.0000000+00:00 + let time = merged_at; + if (time) + { + time = time.replace("z", ".0000000+00:00").replace("Z", ".0000000+00:00"); + } + else + { + console.log("Pull request was not merged, skipping"); + return; + } + + + // Construct changelog yml entry + const entry = { + author: author, + changes: entries, + id: getHighestCLNumber() + 1, + time: time, + }; + + // Write changelogs + writeChangelog(entry); + + console.log(`Changelog updated with changes from PR #${process.env.PR_NUMBER}`); +} + + +// Code chunking + +// Get all changes from the PR body +function getChanges(body) { + const matches = []; + const entries = []; + + for (const match of body.matchAll(EntryRegex)) { + matches.push([match[1], match[2]]); + } + + if (!matches) + { + console.log("No changes found, skipping"); + return; + } + + + // Check change types and construct changelog entry + matches.forEach((entry) => { + let type; + + switch (entry[0].toLowerCase()) { + case "add": + type = "Add"; + break; + case "remove": + type = "Remove"; + break; + case "tweak": + type = "Tweak"; + break; + case "fix": + type = "Fix"; + break; + default: + break; + } + + if (type) { + entries.push({ + type: type, + message: entry[1], + }); + } + }); + + return entries; +} + +// Get the highest changelog number from the changelogs file +function getHighestCLNumber() { + // Read changelogs file + const file = fs.readFileSync(`../../${process.env.CHANGELOG_DIR}`, "utf8"); + + // Get list of CL numbers + const data = yaml.load(file); + const entries = data && data.Entries ? Array.from(data.Entries) : []; + const clNumbers = entries.map((entry) => entry.id); + + // Return highest changelog number + return Math.max(...clNumbers, 0); +} + +function writeChangelog(entry) { + let data = { Entries: [] }; + + // Create a new changelogs file if it does not exist + if (fs.existsSync(`../../${process.env.CHANGELOG_DIR}`)) { + const file = fs.readFileSync(`../../${process.env.CHANGELOG_DIR}`, "utf8"); + data = yaml.load(file); + } + + data.Entries.push(entry); + + // Write updated changelogs file + fs.writeFileSync( + `../../${process.env.CHANGELOG_DIR}`, + "Entries:\n" + + yaml.dump(data.Entries, { indent: 2 }).replace(/^---/, "") + ); +} + +// Run main +main();