mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-29 23:57:29 +00:00
Add automatic changelogs (#11)
This commit is contained in:
@@ -0,0 +1,56 @@
|
|||||||
|
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: ubuntu-latest
|
||||||
|
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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Entries:
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
// 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();
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"name": "changelogs",
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.3.4",
|
||||||
|
"js-yaml": "^4.1.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user