Skip to content

Commit

Permalink
impr(changelog generator): include non user-facing changes
Browse files Browse the repository at this point in the history
!nuf
  • Loading branch information
Miodec committed Mar 24, 2024
1 parent a8a78ec commit f27abd9
Showing 1 changed file with 165 additions and 77 deletions.
242 changes: 165 additions & 77 deletions bin/buildChangelog.mjs
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
import conventionalChangelog from "conventional-changelog";
import { exec } from "child_process";

const stream = conventionalChangelog(
{
preset: {
name: "conventionalcommits",
types: [
{ type: "feat", section: "Features" },
{ type: "impr", section: "Improvements" },
{ type: "fix", section: "Fixes" },
],
},
},
undefined,
undefined,
undefined,
{
headerPartial: "",
}
);

const header =
"Thank you to all the contributors who made this release possible!";

let log = "";
for await (const chunk of stream) {
log += chunk;
}

log = log.replace(/^\*/gm, "-");
// const stream = conventionalChangelog(
// {
// preset: {
// name: "conventionalcommits",
// types: [
// { type: "feat", section: "Features" },
// { type: "impr", section: "Improvements" },
// { type: "fix", section: "Fixes" },
// ],
// },
// },
// undefined,
// undefined,
// undefined,
// {
// headerPartial: "",
// }
// );

// let log = "";
// for await (const chunk of stream) {
// log += chunk;
// }

// log = log.replace(/^\*/gm, "-");

// console.log(log);

// console.log(header + log + footer);
//i might come back to the approach below at some point

const lineDelimiter =
"thisismylinedelimiterthatwilldefinitelynotappearintheactualcommitmessage";
const logDelimiter =
"thisismylogdelimiterthatwilldefinitelynotappearintheactualcommitmessage";

async function getLog() {
return new Promise((resolve, reject) => {
exec(
`git log --oneline $(git describe --tags --abbrev=0 @^)..@ --pretty="format:%H %h %s"`,
`git log --oneline $(git describe --tags --abbrev=0 @^)..@ --pretty="format:${lineDelimiter}%H${logDelimiter}%h${logDelimiter}%s${logDelimiter}%b"`,
(err, stdout, stderr) => {
if (err) {
reject(err);
Expand Down Expand Up @@ -90,17 +92,15 @@ function getCommitLink(hash, longHash) {
return `[${hash}](https://github.com/monkeytypegame/monkeytype/commit/${longHash})`;
}

function buildSection(type, allItems) {
let ret = `### ${titles[type]}\n\n`;

const items = allItems.filter((item) => item.type === type);
function buildItems(items, mergeTypeAndScope = false) {
let ret = "";
for (let item of items) {
let scope = item.scope ? `**${item.scope}:** ` : "";

if (items.length === 0) {
return "";
}
if (mergeTypeAndScope) {
scope = `**${item.type}${item.scope ? `(${item.scope})` : ""}:** `;
}

for (let item of items) {
const scope = item.scope ? `**${item.scope}:** ` : "";
const usernames =
item.usernames.length > 0 ? ` (${item.usernames.join(", ")})` : "";
const pr =
Expand All @@ -113,68 +113,144 @@ function buildSection(type, allItems) {

ret += `- ${scope}${item.message}${usernames}${pr}${hash}\n`;
}

return ret;
}

function buildSection(type, allItems) {
let ret = `### ${titles[type]}\n\n`;

const items = allItems.filter(
(item) => item.type === type && !item.body.includes("!nuf")
);

if (items.length === 0) {
return "";
}

return (ret += buildItems(items));
}

function buildFooter(logs) {
let out =
"\n### Nerd stuff\n\nThese changes will not be visible to users, but are included for completeness and to credit contributors.\n\n";

const featLogs = logs.filter(
(item) => item.type === "feat" && item.body.includes("!nuf")
);
const imprLogs = logs.filter(
(item) => item.type === "impr" && item.body.includes("!nuf")
);
const fixLogs = logs.filter(
(item) => item.type === "fix" && item.body.includes("!nuf")
);
const styleLogs = logs.filter((item) => item.type === "style");
const docLogs = logs.filter((item) => item.type === "docs");
const refactorLogs = logs.filter((item) => item.type === "refactor");
const perfLogs = logs.filter((item) => item.type === "perf");
const ciLogs = logs.filter((item) => item.type === "ci");
const testLogs = logs.filter((item) => item.type === "test");
const buildLogs = logs.filter((item) => item.type === "build");
const choreLogs = logs.filter((item) => item.type === "chore");

const allOtherLogs = [
...featLogs,
...imprLogs,
...fixLogs,
...styleLogs,
...docLogs,
...refactorLogs,
...perfLogs,
...ciLogs,
...testLogs,
...buildLogs,
...choreLogs,
];

//remove dupes based on hash
const uniqueOtherLogs = allOtherLogs.filter(
(item, index, self) =>
index === self.findIndex((t) => t.hashes[0].full === item.hashes[0].full)
);

const otherStrings = [];

if (styleLogs.length > 0) {
otherStrings.push("style");
}
if (docLogs.length > 0) {
otherStrings.push("documentation");
}
if (refactorLogs.length > 0) {
otherStrings.push("refactoring");
}
if (perfLogs.length > 0) {
otherStrings.push("performance");
}
if (ciLogs.length > 0) {
otherStrings.push("CI");
}
if (testLogs.length > 0) {
otherStrings.push("testing");
}
if (buildLogs.length > 0) {
otherStrings.push("build");
}

if (otherStrings.length === 0) {
return "";
}
// console.log(uniqueOtherLogs);

//build a string where otherStrings are joined by commas and the last one is joined by "and"
const finalString =
otherStrings.length > 1
? otherStrings.slice(0, -1).join(", ") + " and " + otherStrings.slice(-1)
: otherStrings[0];
out += buildItems(uniqueOtherLogs, true);

return `\n### Other\n\n- Various ${finalString} changes`;
return out;
}

// function buildFooter(logs) {
// const styleLogs = logs.filter((item) => item.type === "style");
// const docLogs = logs.filter((item) => item.type === "docs");
// const refactorLogs = logs.filter((item) => item.type === "refactor");
// const perfLogs = logs.filter((item) => item.type === "perf");
// const ciLogs = logs.filter((item) => item.type === "ci");
// const testLogs = logs.filter((item) => item.type === "test");
// const buildLogs = logs.filter((item) => item.type === "build");

// const otherStrings = [];

// if (styleLogs.length > 0) {
// otherStrings.push("style");
// }
// if (docLogs.length > 0) {
// otherStrings.push("documentation");
// }
// if (refactorLogs.length > 0) {
// otherStrings.push("refactoring");
// }
// if (perfLogs.length > 0) {
// otherStrings.push("performance");
// }
// if (ciLogs.length > 0) {
// otherStrings.push("CI");
// }
// if (testLogs.length > 0) {
// otherStrings.push("testing");
// }
// if (buildLogs.length > 0) {
// otherStrings.push("build");
// }

// if (otherStrings.length === 0) {
// return "";
// }

// //build a string where otherStrings are joined by commas and the last one is joined by "and"
// const finalString =
// otherStrings.length > 1
// ? otherStrings.slice(0, -1).join(", ") + " and " + otherStrings.slice(-1)
// : otherStrings[0];

// return `\n### Other\n\n- Various ${finalString} changes`;
// }

console.log("---------");

function convertStringToLog(logString) {
let log = [];
for (let line of logString) {
if (line === "" || line === "\r" || line === "\n") continue;
// console.log(line);

//split line based on the format: d2739e4f193137db4d86450f0d50b3489d75c106 d2739e4f1 style: adjusted testConfig and modesNotice.
//use regex to split
const [_, hash, shortHash, fullMessage] = line.split(
/(\w{40}) (\w{9,10}) (.*)/
);
// const [_, hash, shortHash, fullMessage] = line.split(
// /(\w{40}) (\w{9,10}) (.*)/
// );

const [hash, shortHash, title, body] = line.split(logDelimiter);

// console.log({
// hash,
// shortHash,
// title,
// body,
// });

//split message using regex based on fix(language): spelling mistakes in Nepali wordlist and quotes (sapradhan) (#4528)
//scope is optional, username is optional, pr number is optional
const [__, type, scope, message, message2, message3] = fullMessage.split(
const [__, type, scope, message, message2, message3] = title.split(
/^(\w+)(?:\(([^)]+)\))?:\s+(.+?)\s*(?:\(([^)]+)\))?(?:\s+\(([^)]+)\))?(?:\s+\(([^)]+)\))?$/
);

Expand Down Expand Up @@ -202,6 +278,7 @@ function convertStringToLog(logString) {
message,
usernames,
prs,
body,
});
} else {
console.warn("skipping line due to invalid format: " + line);
Expand All @@ -210,9 +287,12 @@ function convertStringToLog(logString) {
return log;
}

const header =
"Thank you to all the contributors who made this release possible!";

async function main() {
let logString = await getLog();
logString = logString.split("\n");
logString = logString.split(lineDelimiter);

//test commits
// const logString = [
Expand Down Expand Up @@ -242,6 +322,14 @@ async function main() {
// "d2739e4f193137db4d86450f0d50b3489d75c106 d2739e4f1 test(scope): add new feature (#1234)",
// ];

//test commits
// logString = [
// "d2739e4f193137db4d86450f0d50b3489d75c101 d2739e4f1 fix: add new fix (#1234)",
// "d2739e4f193137db4d86450f0d50b3489d75c102 d2739e4f1 fix(nuf something): add new fix nuf (#1234)",
// "d2739e4f193137db4d86450f0d50b3489d75c103 d2739e4f1 test: add new test (#1234)",
// "d2739e4f193137db4d86450f0d50b3489d75c104 d2739e4f1 test(blah): add new test blah (#1234)",
// ];

let log = convertStringToLog(logString);

const contributorCount = log
Expand Down

0 comments on commit f27abd9

Please sign in to comment.