IntegerLimit 123adfeccb Improve Checks for Same Author (#502)
[COMBINE]
commits = ["ce5272fcf17b617495f05de102cf39dc23aece95"]
[COMBINE]

[FIXUP]
[[fixes]]
sha = "ce5272fcf17b617495f05de102cf39dc23aece95"
newTitle = "Changelog Improvements (#466)"
newBody = "[INTERNAL]"

[[fixes]]
sha = "3b03b11b7d2cebe3595a38ad2cccc37b38e2c1b9"
newTitle = "Update Custom Main Menu Per Update (#468)"
newBody = """
[COMBINE]
commits = [\"ce5272fcf17b617495f05de102cf39dc23aece95\"]
[COMBINE]
"""

[[fixes]]
sha = "21037b17f3e1174d581a95ab4462025ac87f699d"
newTitle = "Add More Ignore Tag Options (#500)"
newBody = """
[COMBINE]
commits = [\"ce5272fcf17b617495f05de102cf39dc23aece95\"]
[COMBINE]
"""

[[fixes]]
sha = "5d557b642477aed767b0a4207d123453f3ea46e3"
newTitle = "Implement Ignore Tag (#481)"
newBody = """
[COMBINE]
commits = [\"ce5272fcf17b617495f05de102cf39dc23aece95\"]
[COMBINE]
"""

[[fixes]]
sha = "542655bcfb3437656495a0f6941dc931bac76bc5"
newTitle = "Allow for Multiple Changelogs (#488)"
newBody = """
[COMBINE]
commits = [\"ce5272fcf17b617495f05de102cf39dc23aece95\"]
[COMBINE]
"""

[[fixes]]
sha = "2a0f5eab525c7f9b29ace0c003c95ef44160af05"
newTitle = "Fix Workflows Pushing to Main (#465)"
newBody = """
[COMBINE]
commits = [\"fbd1584e7baed4a3603e3c810066603185f1b230\"]
[COMBINE]
"""

[[fixes]]
sha = "e2aac147e539f48b01e702a24fba8e6fa6666861"
newTitle = "Fix Non Release Commit Workflow (#464)"
newBody = """
[COMBINE]
commits = [\"fbd1584e7baed4a3603e3c810066603185f1b230\"]
[COMBINE]
"""

[[fixes]]
sha = "7a6a147006dbc6fca439e6fc4c1bff8f3d4e1c9d"
newTitle = "Fix Parsing Complex Bodies in GitHub Commits (#460)"
newBody = """
[COMBINE]
commits = [\"fbd1584e7baed4a3603e3c810066603185f1b230\"]
[COMBINE]
"""

[[fixes]]
sha = "8fc1c45080f3247f973308aa8824629b98b18a91"
newTitle = "Fix Draconic Evolution Crash (#484)"
newBody = """
[BUG]
[IGNORE]
checks = { compareNot = \"1.7-alpha-1\" }
[IGNORE]
"""
[FIXUP]
2023-10-29 21:56:26 +11:00

231 lines
7.5 KiB
TypeScript

import ChangelogData from "./changelogData";
import { categories, defaultIndentation } from "./definitions";
import { Category, ChangelogMessage, Commit } from "../../types/changelogTypes";
import { repoLink } from "./definitions";
let data: ChangelogData;
export default function pushAll(inputData: ChangelogData): void {
pushTitle(inputData);
pushChangelog(inputData);
}
export function pushTitle(inputData: ChangelogData): void {
data = inputData;
// Push the titles.
// Center Align is replaced by the correct center align style in the respective deployments.
// Must be triple bracketed, to make mustache not html escape it.
if (data.releaseType === "Cutting Edge Build") {
const date = new Date().toLocaleDateString("en-us", {
year: "numeric",
month: "short",
day: "numeric",
hour12: true,
hour: "numeric",
minute: "numeric",
timeZoneName: "short",
});
// noinspection HtmlDeprecatedAttribute
data.builder.push(`<h1 align="center">${data.releaseType} (${date})</h1>`, "");
} else {
// noinspection HtmlUnknownAttribute
data.builder.push(`<h1 {{{ CENTER_ALIGN }}}>${data.releaseType} ${data.to}</h1>`, "");
data.builder.push("{{{ CF_REDIRECT }}}", "");
}
}
export function pushChangelog(inputData: ChangelogData): void {
data = inputData;
data.builder.push(`# Changes Since ${data.since}`, "");
// Push Sections of Changelog
categories.forEach((category) => {
pushCategory(category);
});
// Push the commit log
if (data.commitList.length > 0) {
sortCommitList(data.commitList, (commit) => commit);
data.builder.push("## Commits");
data.commitList.forEach((commit) => {
data.builder.push(formatCommit(commit));
});
} else {
// No Commit List = No Changes
data.builder.push("");
data.builder.push("**There haven't been any changes.**");
}
// Push link
data.builder.push(
"",
`**Full Changelog**: [\`${data.since}...${data.to}\`](${repoLink}compare/${data.since}...${data.to})`,
);
}
export function pushSeperator(inputData: ChangelogData): void {
data = inputData;
data.builder.push("", "<hr>", "");
}
/**
* Pushes a given category to the builders.
*/
function pushCategory(category: Category) {
const categoryLog: string[] = [];
let hasValues = false;
// Push All Sub Categories
category.subCategories.forEach((subCategory) => {
// Loop through key list instead of map to produce correct order
const list = category.changelogSection.get(subCategory);
if (list && list.length != 0) {
// Push Key Name (only pushes if Key Name is not "")
if (subCategory.keyName) {
categoryLog.push(`### ${subCategory.keyName}:`);
}
// Sort Log
sortCommitList(
list,
(message) => message.commitObject,
(a, b) => a.commitMessage.localeCompare(b.commitMessage),
);
// Push Log
list.forEach((changelogMessage) => {
categoryLog.push(formatChangelogMessage(changelogMessage));
// Push Sub Messages
if (changelogMessage.subChangelogMessages) {
changelogMessage.subChangelogMessages.forEach((subMessage) => {
categoryLog.push(formatChangelogMessage(subMessage, true));
});
}
});
categoryLog.push("");
hasValues = true;
}
});
if (hasValues) {
// Push Title
data.builder.push(`## ${category.categoryName}:`);
// Push previously made log
data.builder.push(...categoryLog);
}
}
/**
* Sorts a list that contains commit data
* @param list A list of type T that contains commit data
* @param transform A function to turn each element of type T into an element of type Commit
* @param backup A backup sort, to call when either element does not have a commit object, or when the commit objects' times are the same. Optional, if not set, will just return 0 (equal) or will compare commit messages.
*/
function sortCommitList<T>(list: T[], transform: (obj: T) => Commit | undefined, backup?: (a: T, b: T) => number) {
list.sort((a, b): number => {
const commitA = transform(a);
const commitB = transform(b);
if (!commitA || !commitB) {
// If either commit is undefined
if (backup) return backup(a, b);
return 0;
}
const dateA = new Date(commitA.date);
const dateB = new Date(commitB.date);
// This is reversed, so the newest commits go on top
if (dateB.getTime() - dateA.getTime() !== 0) return dateB.getTime() - dateA.getTime();
if (backup) return backup(a, b);
return commitA.message.localeCompare(commitB.message);
});
}
/**
* Sorts a commits list so that newest commits are on the bottom.
* @param list The commit list.
*/
export function sortCommitListReverse(list: Commit[]): void {
list.sort((a, b) => {
const dateA = new Date(a.date);
const dateB = new Date(b.date);
if (dateB.getTime() - dateA.getTime() !== 0) return dateA.getTime() - dateB.getTime();
return a.message.localeCompare(b.message);
});
}
/**
* Formats a Changelog Message
* @param changelogMessage The message to format.
* @param subMessage Whether this message is a subMessage (used in details). Set to true to make it a subMessage (different parsing). Defaults to false.
* @return string Formatted Changelog Message
*/
function formatChangelogMessage(changelogMessage: ChangelogMessage, subMessage = false): string {
if (changelogMessage.specialFormatting)
return changelogMessage.specialFormatting.formatting(changelogMessage, changelogMessage.specialFormatting.storage);
const indentation = changelogMessage.indentation == undefined ? defaultIndentation : changelogMessage.indentation;
let message = changelogMessage.commitMessage.trim();
// Transform PR tags into a link.
if (message.match(/\(#\d+\)/g)) {
const matched = message.match(/\(#\d+\)/g);
matched.forEach((match) => {
// Extract digits
const digits = match.match(/\d+/g);
message = message.replace(match, `([#${digits}](${repoLink}pull/${digits}))`);
});
}
if (changelogMessage.commitObject && !subMessage) {
if (data.combineList.has(changelogMessage.commitObject.hash)) {
const commits = data.combineList.get(changelogMessage.commitObject.hash);
commits.push(changelogMessage.commitObject);
// Sort original array so newest commits appear at the end instead of start of commit string
sortCommitListReverse(commits);
const formattedCommits: string[] = [];
const authors: string[] = [];
const authorEmails: Set<string> = new Set<string>();
const processedSHAs: Set<string> = new Set<string>();
commits.forEach((commit) => {
if (processedSHAs.has(commit.hash)) return;
if (!authors.includes(commit.author_name) && !authorEmails.has(commit.author_email)) {
authors.push(commit.author_name);
authorEmails.add(commit.author_email);
}
formattedCommits.push(`[\`${commit.hash.substring(0, 7)}\`](${repoLink}commit/${commit.hash})`);
processedSHAs.add(commit.hash);
});
authors.sort();
return `${indentation}* ${message} - **${authors.join("**, **")}** (${formattedCommits.join(", ")})`;
}
const commit = changelogMessage.commitObject;
const shortSHA = commit.hash.substring(0, 7);
const author = commit.author_name;
return `${indentation}* ${message} - **${author}** ([\`${shortSHA}\`](${repoLink}commit/${commit.hash}))`;
}
return `${indentation}* ${message}`;
}
/**
* Returns a formatted commit
*/
function formatCommit(commit: Commit): string {
const date = new Date(commit.date).toLocaleDateString("en-us", { year: "numeric", month: "short", day: "numeric" });
const formattedCommit = `${commit.message} - **${commit.author_name}** (${date})`;
const shortSHA = commit.hash.substring(0, 7);
return `* [\`${shortSHA}\`](${repoLink}commit/${commit.hash}): ${formattedCommit}`;
}