mirror of
				https://github.com/monkeytypegame/monkeytype.git
				synced 2025-10-31 11:16:08 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			218 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			218 lines
		
	
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 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!";
 | |
| const footer = `\n### Other\n\n- Various style, documentation, refactoring, performance, or build improvements`;
 | |
| 
 | |
| 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
 | |
| 
 | |
| async function getLog() {
 | |
|   return new Promise((resolve, reject) => {
 | |
|     exec(
 | |
|       `git log --oneline $(git describe --tags --abbrev=0 @^)..@ --pretty="format:%H %h %s"`,
 | |
|       (err, stdout, stderr) => {
 | |
|         if (err) {
 | |
|           reject(err);
 | |
|         }
 | |
| 
 | |
|         resolve(stdout);
 | |
|       }
 | |
|     );
 | |
|   });
 | |
| }
 | |
| 
 | |
| function itemIsAddingQuotes(item) {
 | |
|   const scopeIsQuote =
 | |
|     item.scope?.includes("quote") ||
 | |
|     item.scope?.includes("quotes") ||
 | |
|     item.message?.includes("quote");
 | |
| 
 | |
|   const messageAdds =
 | |
|     item.message.includes("add") ||
 | |
|     item.message.includes("added") ||
 | |
|     item.message.includes("adding") ||
 | |
|     item.message.includes("adds");
 | |
| 
 | |
|   return scopeIsQuote && messageAdds;
 | |
| }
 | |
| 
 | |
| function itemIsAddressingQuoteReports(item) {
 | |
|   const scopeIsQuote =
 | |
|     item.scope?.includes("quote") || item.scope?.includes("quotes");
 | |
| 
 | |
|   const messageReport =
 | |
|     item.message.includes("report") || item.message.includes("reports");
 | |
| 
 | |
|   return scopeIsQuote && messageReport;
 | |
| }
 | |
| 
 | |
| const titles = {
 | |
|   feat: "Features",
 | |
|   impr: "Improvements",
 | |
|   fix: "Fixes",
 | |
| };
 | |
| 
 | |
| function getPrLink(pr) {
 | |
|   const prNum = pr.replace("#", "");
 | |
|   return `[#${prNum}](https://github.com/monkeytypegame/monkeytype/issues/${prNum})`;
 | |
| }
 | |
| 
 | |
| 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);
 | |
| 
 | |
|   if (items.length === 0) {
 | |
|     return "";
 | |
|   }
 | |
| 
 | |
|   for (let item of items) {
 | |
|     const scope = item.scope ? `**${item.scope}:** ` : "";
 | |
|     const usernames =
 | |
|       item.usernames.length > 0 ? ` (${item.usernames.join(", ")})` : "";
 | |
|     const pr =
 | |
|       item.prs.length > 0
 | |
|         ? ` (${item.prs.map((p) => getPrLink(p)).join(", ")})`
 | |
|         : "";
 | |
|     const hash = ` (${item.hashes
 | |
|       .map((h) => getCommitLink(h.short, h.full))
 | |
|       .join(", ")})`;
 | |
| 
 | |
|     ret += `- ${scope}${item.message}${usernames}${pr}${hash}\n`;
 | |
|   }
 | |
| 
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| async function main() {
 | |
|   let logString = await getLog();
 | |
|   logString = logString.split("\n");
 | |
| 
 | |
|   let log = [];
 | |
|   for (let line of logString) {
 | |
|     //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}) (.*)/
 | |
|     );
 | |
| 
 | |
|     //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(
 | |
|       /^(\w+)(?:\(([^)]+)\))?:\s+(.+?)\s*(?:\(([^)]+)\))?(?:\s+\(([^)]+)\))?(?:\s+\(([^)]+)\))?$/
 | |
|     );
 | |
| 
 | |
|     const usernames = message2 && message3 ? message2.split(", ") : [];
 | |
| 
 | |
|     let pr;
 | |
|     if (message2 && message3) {
 | |
|       pr = message3;
 | |
|     } else if (message2 && !message3) {
 | |
|       pr = message2;
 | |
|     }
 | |
| 
 | |
|     const prs = pr ? pr.split(", ") : [];
 | |
| 
 | |
|     if (type && message) {
 | |
|       log.push({
 | |
|         hashes: [
 | |
|           {
 | |
|             short: shortHash,
 | |
|             full: hash,
 | |
|           },
 | |
|         ],
 | |
|         type,
 | |
|         scope,
 | |
|         message,
 | |
|         usernames,
 | |
|         prs,
 | |
|       });
 | |
|     } else {
 | |
|       console.warn("skipping line due to invalid format: " + line);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   let quoteAddCommits = log.filter((item) => itemIsAddingQuotes(item));
 | |
|   log = log.filter((item) => !itemIsAddingQuotes(item));
 | |
| 
 | |
|   let quoteReportCommits = log.filter((item) =>
 | |
|     itemIsAddressingQuoteReports(item)
 | |
|   );
 | |
|   log = log.filter((item) => !itemIsAddressingQuoteReports(item));
 | |
| 
 | |
|   if (quoteAddCommits.length > 0) {
 | |
|     log.push({
 | |
|       hashes: quoteAddCommits.map((item) => item.hashes).flat(),
 | |
|       type: "impr",
 | |
|       scope: "quote",
 | |
|       message: "add quotes in various languages",
 | |
|       usernames: quoteAddCommits.map((item) => item.usernames).flat(),
 | |
|       prs: quoteAddCommits.map((item) => item.prs).flat(),
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   if (quoteReportCommits.length > 0) {
 | |
|     log.push({
 | |
|       hashes: quoteReportCommits.map((item) => item.hashes).flat(),
 | |
|       type: "fix",
 | |
|       scope: "quote",
 | |
|       message: "update or remove quotes reported by users",
 | |
|       usernames: quoteReportCommits.map((item) => item.usernames).flat(),
 | |
|       prs: quoteReportCommits.map((item) => item.prs).flat(),
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   let final = "";
 | |
| 
 | |
|   final += header + "\n\n\n";
 | |
| 
 | |
|   const sections = [];
 | |
|   for (const type of Object.keys(titles)) {
 | |
|     const section = buildSection(type, log);
 | |
|     if (section) {
 | |
|       sections.push(section);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   final += sections.join("\n\n");
 | |
| 
 | |
|   final += "\n" + footer;
 | |
| 
 | |
|   console.log(final);
 | |
| }
 | |
| 
 | |
| main();
 |