mirror of
https://github.com/godotengine/godot-interactive-changelog.git
synced 2025-12-31 01:49:28 +03:00
The area prefix regex didn't include the `.` or `#` characters so it wasn't matching PRs with the prefix `[C#]` or `[.NET]`. Also added a special case for `.NET` since some PRs use that as the prefix, but the classifier expects the group name `C#` instead.
146 lines
5.1 KiB
JavaScript
146 lines
5.1 KiB
JavaScript
// This list is ordered from less general (and more likely to be used) to more general (and less likely to be used).
|
|
const GENERAL_TOPICS = [
|
|
"buildsystem", "porting", "tests", "thirdparty", "2d", "3d", "editor", "codestyle", "core"
|
|
];
|
|
|
|
const VERSION_PREFIX_REGEX = /^[\(\[][34]\.[0-9x][\)\]]/;
|
|
const VERSION_SUFFIX_REGEX = /[\(\[][34]\.[0-9x][\)\]]$/;
|
|
const AREA_PREFIX_REGEX = /^[\[`']([a-zA-Z0-9\.#]+)[\]`']/;
|
|
|
|
class PullClassifier {
|
|
determineGroup(pull) {
|
|
// Simplify the array.
|
|
const allLabels = pull.labels.map(item => item.name);
|
|
|
|
// We use labels to deduce which category does the change
|
|
// fall under. We consider more specific groups before more
|
|
// general ones. When in doubt, pick any group.
|
|
let groupName = "core";
|
|
|
|
// Extract all applied topical labels.
|
|
let topicLabels = allLabels
|
|
.filter((item) => {
|
|
return item.startsWith("topic:");
|
|
})
|
|
.map((item) => {
|
|
return item.substring(6);
|
|
});
|
|
|
|
// Find the first topical label which is not generic, and
|
|
// use it.
|
|
const firstLabel = topicLabels.find((item) => {
|
|
return GENERAL_TOPICS.indexOf(item) < 0;
|
|
});
|
|
|
|
if (firstLabel) {
|
|
groupName = firstLabel;
|
|
} else {
|
|
// If there is none, pick a general topic, in order of relevance.
|
|
let topicFound = false;
|
|
for (let name of GENERAL_TOPICS) {
|
|
if (topicLabels.indexOf(name) >= 0) {
|
|
groupName = name;
|
|
topicFound = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Besides topical labels, we can also check some other ones.
|
|
if (!topicFound) {
|
|
if (allLabels.indexOf("documentation") >= 0) {
|
|
groupName = "documentation";
|
|
}
|
|
else if (allLabels.indexOf("usability") >= 0) {
|
|
groupName = "editor";
|
|
}
|
|
}
|
|
}
|
|
|
|
// If no group was detected, we just stay on "core".
|
|
return groupName;
|
|
}
|
|
|
|
humanizeGroup(groupName) {
|
|
switch (groupName) {
|
|
case "2d":
|
|
return "2D";
|
|
case "3d":
|
|
return "3D";
|
|
case "dotnet":
|
|
return "C#";
|
|
case "gdextension":
|
|
return "GDExtension";
|
|
case "gdscript":
|
|
return "GDScript";
|
|
case "gui":
|
|
return "GUI";
|
|
case "visualscript":
|
|
return "VisualScript";
|
|
case "xr":
|
|
return "XR";
|
|
}
|
|
|
|
return groupName.charAt(0).toUpperCase() + groupName.substring(1);
|
|
}
|
|
|
|
cleanupTitle(pull) {
|
|
let cleanMessage = pull.title.trim();
|
|
// Sometimes there are periods at the end.
|
|
if (cleanMessage.endsWith(".")) {
|
|
cleanMessage = cleanMessage.substring(0, cleanMessage.length - 1);
|
|
}
|
|
|
|
// Backports and cherry-picks sometimes have a version number/mask as
|
|
// a prefix or suffix. We need to strip it.
|
|
if (VERSION_PREFIX_REGEX.test(cleanMessage)) {
|
|
// The size is fixed for all variations.
|
|
cleanMessage = cleanMessage.substring(5).trim();
|
|
}
|
|
if (VERSION_SUFFIX_REGEX.test(cleanMessage)) {
|
|
// The size is fixed for all variations.
|
|
cleanMessage = cleanMessage.substring(0, cleanMessage.length - 5).trim();
|
|
}
|
|
|
|
// Prefixes come in two forms, "[Prefix]" and "Prefix:". We prefer the
|
|
// second form, as it matches our manual style. So we convert the first
|
|
// form into the second.
|
|
let matched = cleanMessage.match(AREA_PREFIX_REGEX);
|
|
if (matched != null) {
|
|
let matchedString = matched[0];
|
|
let matchedPrefix = matched[1]
|
|
|
|
cleanMessage = cleanMessage.substring(matchedString.length + 1).trim();
|
|
cleanMessage = `${matchedPrefix}: ${cleanMessage}`;
|
|
}
|
|
|
|
// Some PR titles contain the same group prefix already,
|
|
// so we're going to remove it for a cleaner look.
|
|
if (cleanMessage.startsWith(`${pull.group_name}:`)) {
|
|
cleanMessage = cleanMessage.substring(pull.group_name.length + 1).trim();
|
|
}
|
|
|
|
// There are also some special cases where the prefix may
|
|
// be slightly different than the group name.
|
|
if (cleanMessage.startsWith("MP:")) {
|
|
cleanMessage = cleanMessage.substring(3).trim();
|
|
}
|
|
if (cleanMessage.startsWith(".NET:")) {
|
|
cleanMessage = cleanMessage.substring(5).trim();
|
|
}
|
|
if (cleanMessage.startsWith("doc:")) {
|
|
cleanMessage = cleanMessage.substring(4).trim();
|
|
}
|
|
|
|
// Repeat some steps in case other transformations changed the content.
|
|
|
|
// Sometimes there are periods at the end.
|
|
if (cleanMessage.endsWith(".")) {
|
|
cleanMessage = cleanMessage.substring(0, cleanMessage.length - 1);
|
|
}
|
|
|
|
return cleanMessage;
|
|
}
|
|
}
|
|
|
|
module.exports = PullClassifier;
|