diff --git a/biome.json b/biome.json
index 73718decc5b..e00e95dc4c0 100644
--- a/biome.json
+++ b/biome.json
@@ -1,5 +1,5 @@
{
- "$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
+ "$schema": "https://biomejs.dev/schemas/2.4.16/schema.json",
"assist": {
"actions": {
"source": {
diff --git a/bun.lock b/bun.lock
index fde39f4c0a0..12a035251e1 100644
--- a/bun.lock
+++ b/bun.lock
@@ -4,30 +4,30 @@
"workspaces": {
"": {
"devDependencies": {
- "@biomejs/biome": "^2.3.10",
- "prettier": "^3.7.4",
- },
- },
+ "@biomejs/biome": "^2.4.16",
+ "prettier": "^3.8.3"
+ }
+ }
},
"packages": {
- "@biomejs/biome": ["@biomejs/biome@2.3.10", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.10", "@biomejs/cli-darwin-x64": "2.3.10", "@biomejs/cli-linux-arm64": "2.3.10", "@biomejs/cli-linux-arm64-musl": "2.3.10", "@biomejs/cli-linux-x64": "2.3.10", "@biomejs/cli-linux-x64-musl": "2.3.10", "@biomejs/cli-win32-arm64": "2.3.10", "@biomejs/cli-win32-x64": "2.3.10" }, "bin": { "biome": "bin/biome" } }, "sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ=="],
+ "@biomejs/biome": ["@biomejs/biome@2.4.16", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.16", "@biomejs/cli-darwin-x64": "2.4.16", "@biomejs/cli-linux-arm64": "2.4.16", "@biomejs/cli-linux-arm64-musl": "2.4.16", "@biomejs/cli-linux-x64": "2.4.16", "@biomejs/cli-linux-x64-musl": "2.4.16", "@biomejs/cli-win32-arm64": "2.4.16", "@biomejs/cli-win32-x64": "2.4.16" }, "bin": { "biome": "bin/biome" } }, "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA=="],
- "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w=="],
+ "@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.4.16", "", { "os": "darwin", "cpu": "arm64" }, "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A=="],
- "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg=="],
+ "@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.4.16", "", { "os": "darwin", "cpu": "x64" }, "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw=="],
- "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA=="],
+ "@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ=="],
- "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A=="],
+ "@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.4.16", "", { "os": "linux", "cpu": "arm64" }, "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg=="],
- "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.10", "", { "os": "linux", "cpu": "x64" }, "sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw=="],
+ "@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ=="],
- "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.10", "", { "os": "linux", "cpu": "x64" }, "sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g=="],
+ "@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.4.16", "", { "os": "linux", "cpu": "x64" }, "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg=="],
- "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ=="],
+ "@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.4.16", "", { "os": "win32", "cpu": "arm64" }, "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A=="],
- "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.10", "", { "os": "win32", "cpu": "x64" }, "sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ=="],
+ "@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.4.16", "", { "os": "win32", "cpu": "x64" }, "sha512-Kp85jgoBHa05gix6UIRjfCDiUV3w/8VIdZ247VyyO2gEjaw12WEVhdIjlxp/AMzXxqxQwbxNTDVZ3Mwd2RG5rw=="],
- "prettier": ["prettier@3.7.4", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA=="],
+ "prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="]
}
}
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000000..51f0906c481
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,200 @@
+{
+ "name": "TG-STATION",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "devDependencies": {
+ "@biomejs/biome": "^2.4.16",
+ "prettier": "^3.8.3"
+ }
+ },
+ "node_modules/@biomejs/biome": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.16.tgz",
+ "integrity": "sha512-x9ajFh1zChVybCiM3TN6OD4phAqLgtPZjFrZF+aTMYCPjwBO+k529TX7PPsAqtGNLeV4UgzwQnowEgS7bGmzcA==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "bin": {
+ "biome": "bin/biome"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/biome"
+ },
+ "optionalDependencies": {
+ "@biomejs/cli-darwin-arm64": "2.4.16",
+ "@biomejs/cli-darwin-x64": "2.4.16",
+ "@biomejs/cli-linux-arm64": "2.4.16",
+ "@biomejs/cli-linux-arm64-musl": "2.4.16",
+ "@biomejs/cli-linux-x64": "2.4.16",
+ "@biomejs/cli-linux-x64-musl": "2.4.16",
+ "@biomejs/cli-win32-arm64": "2.4.16",
+ "@biomejs/cli-win32-x64": "2.4.16"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-arm64": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.16.tgz",
+ "integrity": "sha512-wxPvu4XOA85YJk9ixSWUmq/QBHbid85BISbOAqqBM/5xQpPk9ayjk5375tOlSC0BeCwNSbPFafQBm+vBumXq0A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-x64": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.16.tgz",
+ "integrity": "sha512-xFCqGPwYusQJp4N4NJLi1XJiZqjwFdjhT+KqtNy+Ug3qgfczqnTa6MSDvxJF6TkuDLoYJItMapz6tAf7kCekFw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.16.tgz",
+ "integrity": "sha512-2kFb4//jxfZaP6D+Rj5VkHkxgyD9EoRAVBEQb8PKRv+s4NO2zYNJKXFaJmK1CmhufJOWEfpHKaRbOja7qjmdhQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64-musl": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.16.tgz",
+ "integrity": "sha512-oYxnW0ARfJkr72ezzF2OR8N/rtkgLUQeYtF8cFhVswbknHxtTcmzSsanVJP8yQKnGpGpc2ck6c5zLvHahL6Cbg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.16.tgz",
+ "integrity": "sha512-NbcBbi/nJqn5baae6wqRXdS7Gadf2uRpehSh6vMSYpG8OhkXl/Xg8aorWrJ+9VWqAT5ml90alLvorkpMW0nBwQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64-musl": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.16.tgz",
+ "integrity": "sha512-iHDS+MCM65DPqWGu+ECC3uoALyj2H7F4nVUPxIPjz/PIl94EUu+EDfGZDzFP+NY1EOPVt9NQvwFqq7HdMmowdg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-arm64": {
+ "version": "2.4.16",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.16.tgz",
+ "integrity": "sha512-0rgImMsNb5v/chhkIFe3wu7PEFClS6RBAYUijGL9UsYN3PanSaoK24HSSuSJb1pYbYYVjzAyZTl3gtjJ84BM8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-x64": {
+ "version": "2.4.16",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "3.8.3",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ }
+ }
+}
diff --git a/package.json b/package.json
index 68493d466f4..9f494dce393 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"devDependencies": {
- "@biomejs/biome": "^2.3.10",
- "prettier": "^3.7.4"
+ "@biomejs/biome": "^2.4.16",
+ "prettier": "^3.8.3"
},
"scripts": {
"tgui:fix": "biome check --write --unsafe tgui",
diff --git a/tgui/packages/tgui/drag.ts b/tgui/packages/tgui/drag.ts
index aeb991bac36..68ed9df38d7 100644
--- a/tgui/packages/tgui/drag.ts
+++ b/tgui/packages/tgui/drag.ts
@@ -5,8 +5,8 @@
*/
import { storage } from 'common/storage';
-import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'tgui-core/vector';
import type { BooleanLike } from 'tgui-core/react';
+import { vecAdd, vecMultiply, vecScale, vecSubtract } from 'tgui-core/vector';
import { createLogger } from './logging';
type Point = [number, number];
diff --git a/tools/autowiki/autowiki.js b/tools/autowiki/autowiki.js
index 0d2a4c1c459..83db11e18b3 100644
--- a/tools/autowiki/autowiki.js
+++ b/tools/autowiki/autowiki.js
@@ -1,49 +1,49 @@
-const fs = require("fs").promises;
-const MWBot = require("mwbot");
+import { promises as fs } from 'node:fs';
+import MWBot from 'mwbot';
const { USERNAME, PASSWORD } = process.env;
if (!USERNAME) {
- console.error("USERNAME was not set.");
+ console.error('USERNAME was not set.');
process.exit(1);
}
if (!PASSWORD) {
- console.error("PASSWORD was not set.");
+ console.error('PASSWORD was not set.');
process.exit(1);
}
const PAGE_EDIT_FILENAME = process.argv[2];
if (!PAGE_EDIT_FILENAME) {
- console.error("No filename specified to edit pages");
+ console.error('No filename specified to edit pages');
process.exit(1);
}
const FILE_EDIT_FILENAME = process.argv[3];
if (!FILE_EDIT_FILENAME) {
- console.error("No filename specified to edit files");
+ console.error('No filename specified to edit files');
process.exit(1);
}
async function main() {
console.log(`Reading from ${PAGE_EDIT_FILENAME}`);
- const editFile = await (
- await fs.readFile(PAGE_EDIT_FILENAME, "utf8")
- ).split("\n");
+ const editFile = await (await fs.readFile(PAGE_EDIT_FILENAME, 'utf8')).split(
+ '\n',
+ );
console.log(`Logging in as ${USERNAME}`);
const bot = new MWBot();
await bot.loginGetEditToken({
- apiUrl: "https://wiki.tgstation13.org/api.php",
+ apiUrl: 'https://wiki.tgstation13.org/api.php',
username: USERNAME,
password: PASSWORD,
});
- console.log("Logged in");
+ console.log('Logged in');
// This is not Promise.all as to not flood with a bunch of traffic at once
for (const editLine of editFile) {
@@ -53,7 +53,7 @@ async function main() {
let { title, text } = JSON.parse(editLine);
text =
- "This page is automated by Autowiki. Do NOT edit it manually." +
+ 'This page is automated by Autowiki. Do NOT edit it manually.' +
text;
console.log(`Editing ${title}...`);
@@ -73,7 +73,7 @@ async function main() {
`Autowiki upload @ ${new Date().toISOString()}`,
)
.catch((error) => {
- if (error.code === "fileexists-no-change") {
+ if (error.code === 'fileexists-no-change') {
console.log(`${assetName} is an exact duplicate`);
} else {
return Promise.reject(error);
diff --git a/tools/pull_request_hooks/autoChangelog.js b/tools/pull_request_hooks/autoChangelog.js
index 2e9f656fe7e..5da32cbd8c9 100644
--- a/tools/pull_request_hooks/autoChangelog.js
+++ b/tools/pull_request_hooks/autoChangelog.js
@@ -1,7 +1,7 @@
-import { parseChangelog } from "./changelogParser.js";
+import { parseChangelog } from './changelogParser.js';
const safeYml = (string) =>
- string.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
+ string.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, '\\n');
export function changelogToYml(changelog, login) {
const author = changelog.author || login;
@@ -17,13 +17,13 @@ export function changelogToYml(changelog, login) {
);
}
- return ymlLines.join("\n");
+ return ymlLines.join('\n');
}
export async function processAutoChangelog({ github, context }) {
const changelog = parseChangelog(context.payload.pull_request.body);
if (!changelog || changelog.changes.length === 0) {
- console.log("no changelog found");
+ console.log('no changelog found');
return;
}
@@ -37,6 +37,6 @@ export async function processAutoChangelog({ github, context }) {
repo: context.repo.repo,
path: `html/changelogs/AutoChangeLog-pr-${context.payload.pull_request.number}.yml`,
message: `Automatic changelog for PR #${context.payload.pull_request.number} [ci skip]`,
- content: Buffer.from(yml).toString("base64"),
+ content: Buffer.from(yml).toString('base64'),
});
}
diff --git a/tools/pull_request_hooks/autoChangelog.test.js b/tools/pull_request_hooks/autoChangelog.test.js
index 821c29c6a42..2d9973d8e4c 100644
--- a/tools/pull_request_hooks/autoChangelog.test.js
+++ b/tools/pull_request_hooks/autoChangelog.test.js
@@ -1,6 +1,6 @@
-import assert from "node:assert/strict";
-import { changelogToYml } from "./autoChangelog.js";
-import { parseChangelog } from "./changelogParser.js";
+import assert from 'node:assert/strict';
+import { changelogToYml } from './autoChangelog.js';
+import { parseChangelog } from './changelogParser.js';
assert.equal(
changelogToYml(
diff --git a/tools/pull_request_hooks/autoLabel.js b/tools/pull_request_hooks/autoLabel.js
index 02ed25a2b6c..ac45c3abb9a 100644
--- a/tools/pull_request_hooks/autoLabel.js
+++ b/tools/pull_request_hooks/autoLabel.js
@@ -1,4 +1,4 @@
-import * as autoLabelConfig from "./autoLabelConfig.js";
+import * as autoLabelConfig from './autoLabelConfig.js';
/**
* Precompute a lowercase keyword → changelog label map
@@ -6,7 +6,7 @@ import * as autoLabelConfig from "./autoLabelConfig.js";
const keywordToClLabel = (() => {
const map = {};
for (const [label, { keywords }] of Object.entries(
- autoLabelConfig.changelog_labels
+ autoLabelConfig.changelog_labels,
)) {
for (const keyword of keywords) {
map[keyword.toLowerCase()] = label;
@@ -21,7 +21,7 @@ const keywordToClLabel = (() => {
const titleKeywordSets = (() => {
const map = {};
for (const [label, { keywords }] of Object.entries(
- autoLabelConfig.title_labels
+ autoLabelConfig.title_labels,
)) {
map[label] = new Set(keywords.map((k) => k.toLowerCase()));
}
@@ -33,10 +33,15 @@ const titleKeywordSets = (() => {
*/
const fileLabelFilepathSets = (() => {
const map = {};
- for (const [label, { filepaths = [], file_extensions = [], add_only }] of Object.entries(
- autoLabelConfig.file_labels
- )) {
- map[label] = { filepaths: new Set(filepaths), file_extensions: new Set(file_extensions), add_only };
+ for (const [
+ label,
+ { filepaths = [], file_extensions = [], add_only },
+ ] of Object.entries(autoLabelConfig.file_labels)) {
+ map[label] = {
+ filepaths: new Set(filepaths),
+ file_extensions: new Set(file_extensions),
+ add_only,
+ };
}
return map;
})();
@@ -48,29 +53,30 @@ function check_body_for_labels(body) {
const labels_to_add = [];
// detect "fixes #1234" or "resolves #1234" in body
- const fix_regex = /\b(?:fix(?:es|ed)?|resolve[sd]?)\s*(?:#\d+|https:\/\/github\.com\/\S+\/issues\/\d+)/gim;
+ const fix_regex =
+ /\b(?:fix(?:es|ed)?|resolve[sd]?)\s*(?:#\d+|https:\/\/github\.com\/\S+\/issues\/\d+)/gim;
if (fix_regex.test(body)) {
- labels_to_add.push("Fix");
+ labels_to_add.push('Fix');
}
- const lines = body.split("\n");
+ const lines = body.split('\n');
let inChangelog = false;
for (const line of lines) {
- if (line.startsWith(":cl:")) {
+ if (line.startsWith(':cl:')) {
inChangelog = true;
continue;
}
- if (line.startsWith("/:cl:")) break;
+ if (line.startsWith('/:cl:')) break;
if (!inChangelog) continue;
// see if the first segment of the line is one of the keywords
- const keyword = line.split(":")[0]?.toLowerCase();
+ const keyword = line.split(':')[0]?.toLowerCase();
const found_label = keywordToClLabel[keyword];
if (!found_label) continue;
// don't add a billion tags if they forgot to clear all the default ones
- const line_text = line.split(":")[1]?.trim();
+ const line_text = line.split(':')[1]?.trim();
const { default_text, alt_default_text } =
autoLabelConfig.changelog_labels[found_label];
@@ -109,27 +115,25 @@ async function check_diff_files_for_labels(github, context) {
try {
// Use github.paginate to fetch all files (up to ~3000 max)
- const allFiles = await github.paginate(
- github.rest.pulls.listFiles,
- {
- owner: context.repo.owner,
- repo: context.repo.repo,
- pull_number: context.payload.pull_request.number,
- per_page: 100, // max per request
- }
- );
+ const allFiles = await github.paginate(github.rest.pulls.listFiles, {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ pull_number: context.payload.pull_request.number,
+ per_page: 100, // max per request
+ });
if (!allFiles?.length) {
- console.error("No files returned in pagination.");
+ console.error('No files returned in pagination.');
return { labels_to_add, labels_to_remove };
}
// Set of changed filenames for quick lookup
const changedFiles = new Set(allFiles.map((f) => f.filename));
- for (const [label, { filepaths = new Set(), file_extensions = new Set(), add_only }] of Object.entries(
- fileLabelFilepathSets
- )) {
+ for (const [
+ label,
+ { filepaths = new Set(), file_extensions = new Set(), add_only },
+ ] of Object.entries(fileLabelFilepathSets)) {
let found = false;
// Filepath-based matching
@@ -163,7 +167,7 @@ async function check_diff_files_for_labels(github, context) {
}
}
} catch (error) {
- console.error("Error fetching paginated files:", error);
+ console.error('Error fetching paginated files:', error);
}
return { labels_to_add, labels_to_remove };
@@ -174,12 +178,7 @@ async function check_diff_files_for_labels(github, context) {
*/
export async function get_updated_label_set({ github, context }) {
const { pull_request } = context.payload;
- const {
- body = "",
- diff_url,
- mergeable,
- title = "",
- } = pull_request;
+ const { body = '', diff_url, mergeable, title = '' } = pull_request;
const updated_labels = new Set();
@@ -187,15 +186,23 @@ export async function get_updated_label_set({ github, context }) {
if (diff_url) {
const { labels_to_add, labels_to_remove } =
await check_diff_files_for_labels(github, context);
- labels_to_add.forEach((label) => updated_labels.add(label));
- labels_to_remove.forEach((label) => updated_labels.delete(label));
+ labels_to_add.forEach((label) => {
+ updated_labels.add(label);
+ });
+ labels_to_remove.forEach((label) => {
+ updated_labels.delete(label);
+ });
}
// Always check body/title (otherwise we can lose the changelog labels)
if (title)
- check_title_for_labels(title).forEach((label) => updated_labels.add(label));
+ check_title_for_labels(title).forEach((label) => {
+ updated_labels.add(label);
+ });
if (body)
- check_body_for_labels(body).forEach((label) => updated_labels.add(label));
+ check_body_for_labels(body).forEach((label) => {
+ updated_labels.add(label);
+ });
// Keep track of labels that were manually added/removed by maintainers in the events.
// And make sure they -stay- added/removed.
@@ -207,29 +214,29 @@ export async function get_updated_label_set({ github, context }) {
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
per_page: 100,
- }
+ },
);
for (const eventData of events) {
// Skip all bot actions
- if (eventData.actor?.login === "github-actions[bot]") {
+ if (eventData.actor?.login === 'github-actions[bot]') {
continue;
}
- if (eventData.event === "labeled") {
+ if (eventData.event === 'labeled') {
updated_labels.add(eventData.label.name);
- } else if (eventData.event === "unlabeled") {
+ } else if (eventData.event === 'unlabeled') {
updated_labels.delete(eventData.label.name);
}
}
} catch (error) {
- console.error("Error fetching paginated events:", error);
- for(const label of pull_request.labels){
+ console.error('Error fetching paginated events:', error);
+ for (const label of pull_request.labels) {
updated_labels.add(label.name);
}
}
// Always remove Test Merge Candidate
- updated_labels.delete("Test Merge Candidate");
+ updated_labels.delete('Test Merge Candidate');
// Handle merge conflict label
let merge_conflict = mergeable === false;
@@ -245,7 +252,7 @@ export async function get_updated_label_set({ github, context }) {
// failed to find? still processing? try again in a few seconds
if (response.data.mergeable === null) {
- console.log("Awaiting GitHub response for merge status...");
+ console.log('Awaiting GitHub response for merge status...');
await new Promise((r) => setTimeout(r, 10000));
response = await github.rest.pulls.get({
owner: context.repo.owner,
@@ -253,7 +260,7 @@ export async function get_updated_label_set({ github, context }) {
pull_number: pull_request.number,
});
if (response.data.mergeable === null) {
- throw new Error("Merge status not available");
+ throw new Error('Merge status not available');
}
}
@@ -264,9 +271,9 @@ export async function get_updated_label_set({ github, context }) {
}
if (merge_conflict) {
- updated_labels.add("Merge Conflict");
+ updated_labels.add('Merge Conflict');
} else {
- updated_labels.delete("Merge Conflict");
+ updated_labels.delete('Merge Conflict');
}
// return the labels to the action, which will apply it
diff --git a/tools/pull_request_hooks/autoLabel.test.js b/tools/pull_request_hooks/autoLabel.test.js
index 09a3946f52f..3d85af595ba 100644
--- a/tools/pull_request_hooks/autoLabel.test.js
+++ b/tools/pull_request_hooks/autoLabel.test.js
@@ -1,11 +1,11 @@
-import { strict as assert } from "node:assert";
-import { get_updated_label_set } from "./autoLabel.js";
+import { strict as assert } from 'node:assert';
+import { get_updated_label_set } from './autoLabel.js';
const empty_pr = {
- action: "opened",
+ action: 'opened',
pull_request: {
- body: "This PR will have no labels",
- title: "Pr with no labels",
+ body: 'This PR will have no labels',
+ title: 'Pr with no labels',
mergeable: true,
},
};
@@ -13,7 +13,7 @@ const empty_label_set = await get_updated_label_set({
github: null,
context: { payload: empty_pr },
});
-assert.equal(empty_label_set.length, 0, "No labels should be added");
+assert.equal(empty_label_set.length, 0, 'No labels should be added');
const cl = `
My Awesome PR
@@ -24,10 +24,10 @@ refactor: refactored some code
:/cl:
`;
const cl_pr = {
- action: "opened",
+ action: 'opened',
pull_request: {
body: cl,
- title: "Awesome PR",
+ title: 'Awesome PR',
mergeable: false,
},
};
@@ -36,19 +36,19 @@ const cl_label_set = await get_updated_label_set({
context: { payload: cl_pr },
});
assert.ok(
- cl_label_set.includes("Merge Conflict"),
- "Merge Conflict label should be added",
+ cl_label_set.includes('Merge Conflict'),
+ 'Merge Conflict label should be added',
);
-assert.ok(cl_label_set.includes("Feature"), "Feature label should be added");
+assert.ok(cl_label_set.includes('Feature'), 'Feature label should be added');
assert.ok(
- !cl_label_set.includes("Refactor"),
- "Refactor label should not be added",
+ !cl_label_set.includes('Refactor'),
+ 'Refactor label should not be added',
);
const title_pr = {
- action: "opened",
+ action: 'opened',
pull_request: {
- title: "Logging is important",
+ title: 'Logging is important',
mergeable: true,
},
};
@@ -56,4 +56,4 @@ const title_label_set = await get_updated_label_set({
github: null,
context: { payload: title_pr },
});
-assert.ok(title_label_set.includes("Logging"), "Logging label should be added");
+assert.ok(title_label_set.includes('Logging'), 'Logging label should be added');
diff --git a/tools/pull_request_hooks/autoLabelConfig.js b/tools/pull_request_hooks/autoLabelConfig.js
index 6d848fa715c..0c1e6a7a44c 100644
--- a/tools/pull_request_hooks/autoLabelConfig.js
+++ b/tools/pull_request_hooks/autoLabelConfig.js
@@ -7,34 +7,34 @@
// the label will not be removed
export const file_labels = {
GitHub: {
- filepaths: [".github/"],
+ filepaths: ['.github/'],
},
SQL: {
- filepaths: ["SQL/"],
+ filepaths: ['SQL/'],
},
- "Map Edit": {
- filepaths: ["_maps/"],
- file_extensions: [".dmm"],
+ 'Map Edit': {
+ filepaths: ['_maps/'],
+ file_extensions: ['.dmm'],
},
Tools: {
- filepaths: ["tools/"],
+ filepaths: ['tools/'],
},
- "Config Update": {
- filepaths: ["config/", "code/controllers/configuration/entries/"],
+ 'Config Update': {
+ filepaths: ['config/', 'code/controllers/configuration/entries/'],
add_only: true,
},
Sprites: {
- filepaths: ["icons/"],
- file_extensions: [".dmi"],
+ filepaths: ['icons/'],
+ file_extensions: ['.dmi'],
add_only: true,
},
Sound: {
- filepaths: ["sound/"],
- file_extensions: [".ogg"],
+ filepaths: ['sound/'],
+ file_extensions: ['.ogg'],
add_only: true,
},
UI: {
- filepaths: ["tgui/"],
+ filepaths: ['tgui/'],
add_only: true,
},
};
@@ -44,28 +44,28 @@ export const file_labels = {
// Add a label based on keywords in the title
export const title_labels = {
Logging: {
- keywords: ["log", "logging"],
+ keywords: ['log', 'logging'],
},
Removal: {
- keywords: ["remove", "delete"],
+ keywords: ['remove', 'delete'],
},
Refactor: {
- keywords: ["refactor"],
+ keywords: ['refactor'],
},
- "Unit Tests": {
- keywords: ["unit test"],
+ 'Unit Tests': {
+ keywords: ['unit test'],
},
- "April Fools": {
- keywords: ["[april fools]"],
+ 'April Fools': {
+ keywords: ['[april fools]'],
},
- "Do Not Merge": {
- keywords: ["[dnm]", "[do not merge]"],
+ 'Do Not Merge': {
+ keywords: ['[dnm]', '[do not merge]'],
},
- "GBP: No Update": {
- keywords: ["[no gbp]"],
+ 'GBP: No Update': {
+ keywords: ['[no gbp]'],
},
- "Test Merge Only": {
- keywords: ["[tm only]", "[test merge only]"],
+ 'Test Merge Only': {
+ keywords: ['[tm only]', '[test merge only]'],
},
};
@@ -75,52 +75,52 @@ export const title_labels = {
// TODO use the existing changelog parser
export const changelog_labels = {
Fix: {
- default_text: "fixed a few things",
- keywords: ["fix", "fixes", "bugfix"],
+ default_text: 'fixed a few things',
+ keywords: ['fix', 'fixes', 'bugfix'],
},
- "Quality of Life": {
- default_text: "made something easier to use",
- keywords: ["qol"],
+ 'Quality of Life': {
+ default_text: 'made something easier to use',
+ keywords: ['qol'],
},
Sound: {
- default_text: "added/modified/removed audio or sound effects",
- keywords: ["sound"],
+ default_text: 'added/modified/removed audio or sound effects',
+ keywords: ['sound'],
},
Feature: {
- default_text: "Added new mechanics or gameplay changes",
- alt_default_text: "Added more things",
- keywords: ["add", "adds", "rscadd"],
+ default_text: 'Added new mechanics or gameplay changes',
+ alt_default_text: 'Added more things',
+ keywords: ['add', 'adds', 'rscadd'],
},
Removal: {
- default_text: "Removed old things",
- keywords: ["del", "dels", "rscdel"],
+ default_text: 'Removed old things',
+ keywords: ['del', 'dels', 'rscdel'],
},
Sprites: {
- default_text: "added/modified/removed some icons or images",
- keywords: ["image"],
+ default_text: 'added/modified/removed some icons or images',
+ keywords: ['image'],
},
- "Grammar and Formatting": {
- default_text: "fixed a few typos",
- keywords: ["typo", "spellcheck"],
+ 'Grammar and Formatting': {
+ default_text: 'fixed a few typos',
+ keywords: ['typo', 'spellcheck'],
},
Balance: {
- default_text: "rebalanced something",
- keywords: ["balance"],
+ default_text: 'rebalanced something',
+ keywords: ['balance'],
},
- "Code Improvement": {
- default_text: "changed some code",
- keywords: ["code_imp", "code"],
+ 'Code Improvement': {
+ default_text: 'changed some code',
+ keywords: ['code_imp', 'code'],
},
Refactor: {
- default_text: "refactored some code",
- keywords: ["refactor"],
+ default_text: 'refactored some code',
+ keywords: ['refactor'],
},
- "Config Update": {
- default_text: "changed some config setting",
- keywords: ["config"],
+ 'Config Update': {
+ default_text: 'changed some config setting',
+ keywords: ['config'],
},
Administration: {
- default_text: "messed with admin stuff",
- keywords: ["admin"],
+ default_text: 'messed with admin stuff',
+ keywords: ['admin'],
},
};
diff --git a/tools/pull_request_hooks/changelogConfig.js b/tools/pull_request_hooks/changelogConfig.js
index f0f87e90e43..b215abfd232 100644
--- a/tools/pull_request_hooks/changelogConfig.js
+++ b/tools/pull_request_hooks/changelogConfig.js
@@ -9,112 +9,112 @@
*/
export const CHANGELOG_ENTRIES = [
[
- ["rscadd", "add", "adds"],
+ ['rscadd', 'add', 'adds'],
{
placeholders: [
- "Added new mechanics or gameplay changes",
- "Added more things",
+ 'Added new mechanics or gameplay changes',
+ 'Added more things',
],
},
],
[
- ["bugfix", "fix", "fixes"],
+ ['bugfix', 'fix', 'fixes'],
{
- placeholders: ["fixed a few things"],
+ placeholders: ['fixed a few things'],
},
],
[
- ["rscdel", "del", "dels"],
+ ['rscdel', 'del', 'dels'],
{
- placeholders: ["Removed old things"],
+ placeholders: ['Removed old things'],
},
],
[
- ["qol"],
+ ['qol'],
{
- placeholders: ["made something easier to use"],
+ placeholders: ['made something easier to use'],
},
],
[
- ["sound"],
+ ['sound'],
{
- placeholders: ["added/modified/removed audio or sound effects"],
+ placeholders: ['added/modified/removed audio or sound effects'],
},
],
[
- ["image"],
+ ['image'],
{
- placeholders: ["added/modified/removed some icons or images"],
+ placeholders: ['added/modified/removed some icons or images'],
},
],
[
- ["map"],
+ ['map'],
{
- placeholders: ["added/modified/removed map content"],
+ placeholders: ['added/modified/removed map content'],
},
],
[
- ["spellcheck", "typo"],
+ ['spellcheck', 'typo'],
{
- placeholders: ["fixed a few typos"],
+ placeholders: ['fixed a few typos'],
},
],
[
- ["balance"],
+ ['balance'],
{
- placeholders: ["rebalanced something"],
+ placeholders: ['rebalanced something'],
},
],
[
- ["code_imp", "code"],
+ ['code_imp', 'code'],
{
- placeholders: ["changed some code"],
+ placeholders: ['changed some code'],
},
],
[
- ["refactor"],
+ ['refactor'],
{
- placeholders: ["refactored some code"],
+ placeholders: ['refactored some code'],
},
],
[
- ["config"],
+ ['config'],
{
- placeholders: ["changed some config setting"],
+ placeholders: ['changed some config setting'],
},
],
[
- ["admin"],
+ ['admin'],
{
- placeholders: ["messed with admin stuff"],
+ placeholders: ['messed with admin stuff'],
},
],
[
- ["server"],
+ ['server'],
{
- placeholders: ["something server ops should know"],
+ placeholders: ['something server ops should know'],
},
],
];
// Valid changelog openers
-export const CHANGELOG_OPEN_TAGS = [":cl:", "??"];
+export const CHANGELOG_OPEN_TAGS = [':cl:', '??'];
// Valid changelog closers
-export const CHANGELOG_CLOSE_TAGS = ["/:cl:", "/ :cl:", ":/cl:", "/??", "/ ??"];
+export const CHANGELOG_CLOSE_TAGS = ['/:cl:', '/ :cl:', ':/cl:', '/??', '/ ??'];
// Placeholder value for an author
-export const CHANGELOG_AUTHOR_PLACEHOLDER_NAME = "optional name here";
+export const CHANGELOG_AUTHOR_PLACEHOLDER_NAME = 'optional name here';
diff --git a/tools/pull_request_hooks/changelogParser.js b/tools/pull_request_hooks/changelogParser.js
index d17472140e9..64bab70900e 100644
--- a/tools/pull_request_hooks/changelogParser.js
+++ b/tools/pull_request_hooks/changelogParser.js
@@ -1,4 +1,4 @@
-import * as changelogConfig from "./changelogConfig.js";
+import * as changelogConfig from './changelogConfig.js';
const REGEX_CHANGELOG_LINE = /^(\w+): (.+)$/;
@@ -66,7 +66,7 @@ export function parseChangelog(text) {
if (text == null) {
return undefined;
}
- const lines = text.split("\n").map((line) => line.trim());
+ const lines = text.split('\n').map((line) => line.trim());
for (let index = 0; index < lines.length; index++) {
const line = lines[index];
diff --git a/tools/pull_request_hooks/changelogParser.test.js b/tools/pull_request_hooks/changelogParser.test.js
index fdb460ed34a..1a975930034 100644
--- a/tools/pull_request_hooks/changelogParser.test.js
+++ b/tools/pull_request_hooks/changelogParser.test.js
@@ -1,5 +1,5 @@
-import { strict as assert } from "node:assert";
-import { parseChangelog } from "./changelogParser.js";
+import { strict as assert } from 'node:assert';
+import { parseChangelog } from './changelogParser.js';
// Basic test
const basicChangelog = parseChangelog(`
@@ -9,10 +9,10 @@ const basicChangelog = parseChangelog(`
/:cl:
`);
-assert.equal(basicChangelog.author, "DenverCoder9");
+assert.equal(basicChangelog.author, 'DenverCoder9');
assert.equal(basicChangelog.changes.length, 1);
-assert.equal(basicChangelog.changes[0].type.changelogKey, "rscadd");
-assert.equal(basicChangelog.changes[0].description, "Adds new stuff");
+assert.equal(basicChangelog.changes[0].type.changelogKey, 'rscadd');
+assert.equal(basicChangelog.changes[0].description, 'Adds new stuff');
// Case-insensitivity test
const mixedCaseChangelog = parseChangelog(`
@@ -22,10 +22,10 @@ const mixedCaseChangelog = parseChangelog(`
/:cl:
`);
-assert.equal(mixedCaseChangelog.author, "DenverCoder9");
+assert.equal(mixedCaseChangelog.author, 'DenverCoder9');
assert.equal(mixedCaseChangelog.changes.length, 1);
-assert.equal(mixedCaseChangelog.changes[0].type.changelogKey, "rscadd");
-assert.equal(mixedCaseChangelog.changes[0].description, "Adds new stuff");
+assert.equal(mixedCaseChangelog.changes[0].type.changelogKey, 'rscadd');
+assert.equal(mixedCaseChangelog.changes[0].description, 'Adds new stuff');
// Multi-line test
const multiLineChangelog = parseChangelog(`
@@ -38,10 +38,10 @@ const multiLineChangelog = parseChangelog(`
assert.equal(multiLineChangelog.author, undefined);
assert.equal(multiLineChangelog.changes.length, 1);
-assert.equal(multiLineChangelog.changes[0].type.changelogKey, "rscadd");
+assert.equal(multiLineChangelog.changes[0].type.changelogKey, 'rscadd');
assert.equal(
multiLineChangelog.changes[0].description,
- "Adds new stuff\nto the game",
+ 'Adds new stuff\nto the game',
);
// Placeholders
@@ -70,8 +70,8 @@ const noCloseChangelog = parseChangelog(`
`);
assert.equal(noCloseChangelog.changes.length, 1);
-assert.equal(noCloseChangelog.changes[0].type.changelogKey, "rscadd");
-assert.equal(noCloseChangelog.changes[0].description, "Adds new stuff");
+assert.equal(noCloseChangelog.changes[0].type.changelogKey, 'rscadd');
+assert.equal(noCloseChangelog.changes[0].description, 'Adds new stuff');
// :cl: with arbitrary text
diff --git a/tools/pull_request_hooks/removeGuideComments.js b/tools/pull_request_hooks/removeGuideComments.js
index 66846ad3c85..5482d248458 100644
--- a/tools/pull_request_hooks/removeGuideComments.js
+++ b/tools/pull_request_hooks/removeGuideComments.js
@@ -1,4 +1,4 @@
-import fs from "fs";
+import fs from 'node:fs';
const REGEX_COMMENT = //g;
@@ -6,13 +6,13 @@ const REGEX_COMMENT = //g;
const comments = [];
for (const match of fs
- .readFileSync(".github/PULL_REQUEST_TEMPLATE.md", { encoding: "utf8" })
+ .readFileSync('.github/PULL_REQUEST_TEMPLATE.md', { encoding: 'utf8' })
.matchAll(REGEX_COMMENT)) {
comments.push(match[0]);
}
function escapeRegex(string) {
- return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
+ return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
}
export async function removeGuideComments({ github, context }) {
@@ -25,7 +25,7 @@ export async function removeGuideComments({ github, context }) {
).data.body;
if (!originalBody) {
- console.log("PR body is empty, skipping...");
+ console.log('PR body is empty, skipping...');
return;
}
@@ -33,8 +33,8 @@ export async function removeGuideComments({ github, context }) {
for (const comment of comments) {
newBody = newBody.replace(
- new RegExp(`^\\s*${escapeRegex(comment)}\\s*`, "gm"),
- "\n",
+ new RegExp(`^\\s*${escapeRegex(comment)}\\s*`, 'gm'),
+ '\n',
);
}
diff --git a/tools/pull_request_hooks/rerunFlakyTests.js b/tools/pull_request_hooks/rerunFlakyTests.js
index 8170a0541bb..98e20443dc8 100644
--- a/tools/pull_request_hooks/rerunFlakyTests.js
+++ b/tools/pull_request_hooks/rerunFlakyTests.js
@@ -1,9 +1,9 @@
-const LABEL = "🤖 Flaky Test Report";
-const TITLE_BOT_HEADER = "title: ";
+const LABEL = '🤖 Flaky Test Report';
+const TITLE_BOT_HEADER = 'title: ';
// Only check jobs that start with these.
// Helps make sure we don't restart something like screenshot tests or linters, which are not known to be flaky.
-const CONSIDERED_JOBS = ["Integration Tests"];
+const CONSIDERED_JOBS = ['Integration Tests'];
async function getFailedJobsForRun(github, context, workflowRunId, runAttempt) {
const jobs = await github.paginate(
@@ -19,7 +19,7 @@ async function getFailedJobsForRun(github, context, workflowRunId, runAttempt) {
},
);
- return jobs.filter((job) => job.conclusion === "failure");
+ return jobs.filter((job) => job.conclusion === 'failure');
}
export async function rerunFlakyTests({ github, context }) {
@@ -35,7 +35,7 @@ export async function rerunFlakyTests({ github, context }) {
return CONSIDERED_JOBS.some((title) => job.name.startsWith(title));
});
if (filteredFailingJobs.length === 0) {
- console.log("Failing jobs are NOT designated flaky. Not rerunning.");
+ console.log('Failing jobs are NOT designated flaky. Not rerunning.');
return;
}
@@ -51,13 +51,13 @@ export async function rerunFlakyTests({ github, context }) {
// Tries its best to extract a useful error title and message for the given log
export function extractDetails(log) {
// Strip off timestamp
- const lines = log.split(/^[0-9.:T\-]*?Z /gm);
+ const lines = log.split(/^[0-9.:T-]*?Z /gm);
const failureRegex = /^\t?FAILURE #(?[0-9]+): (?.+)/;
const groupRegex = /^##\[group\](?.+)/;
const failures = [];
- let lastGroup = "root";
+ let lastGroup = 'root';
let loggingFailure;
const newFailure = (failureMatch) => {
@@ -65,7 +65,7 @@ export function extractDetails(log) {
loggingFailure = {
headline,
- group: lastGroup.replace("/datum/unit_test/", ""),
+ group: lastGroup.replace('/datum/unit_test/', ''),
details: [],
};
};
@@ -85,7 +85,7 @@ export function extractDetails(log) {
}
newFailure(failureMatch);
- } else if (failureMatch || line.startsWith("##")) {
+ } else if (failureMatch || line.startsWith('##')) {
failures.push(loggingFailure);
loggingFailure = undefined;
@@ -100,7 +100,7 @@ export function extractDetails(log) {
// We had no logged failures, there's not really anything we can do here
if (failures.length === 0) {
return {
- title: "Flaky test failure with no obvious source",
+ title: 'Flaky test failure with no obvious source',
failures,
};
}
@@ -116,7 +116,7 @@ export function extractDetails(log) {
return {
title: `Multiple flaky test failures in ${Array.from(uniqueGroups)
.sort()
- .join(", ")}`,
+ .join(', ')}`,
failures,
};
}
@@ -164,7 +164,7 @@ export function extractDetails(log) {
}
// Try to normalize the title and remove anything that might be variable
- const normalizedError = failure.headline.replace(/\s*at .+?:[0-9]+.*/g, ""); // " at code.dm:123"
+ const normalizedError = failure.headline.replace(/\s*at .+?:[0-9]+.*/g, ''); // " at code.dm:123"
return {
title: `Flaky test ${failGroup}: ${normalizedError}`,
@@ -231,11 +231,11 @@ function createBody({ title, failures }, runUrl) {
${failures
.map(
(failure) =>
- `${failure.group}: ${failure.headline}\n\t${failure.details.join("\n")}`,
+ `${failure.group}: ${failure.headline}\n\t${failure.details.join('\n')}`,
)
- .join("\n")}
+ .join('\n')}
\`\`\`
- `.replace(/^\s*/gm, "");
+ `.replace(/^\s*/gm, '');
}
export async function reportFlakyTests({ github, context }) {
@@ -254,7 +254,7 @@ export async function reportFlakyTests({ github, context }) {
// This could one day be relaxed if we face serious enough flaky test problems, so we're going to loop anyway
if (filteredFailingJobs.length !== 1) {
console.log(
- "Multiple jobs failing after retry, assuming maintainer rerun.",
+ 'Multiple jobs failing after retry, assuming maintainer rerun.',
);
return;
diff --git a/tools/pull_request_hooks/rerunFlakyTests.test.js b/tools/pull_request_hooks/rerunFlakyTests.test.js
index 7f0b2dfb015..6fc0f2ad9ab 100644
--- a/tools/pull_request_hooks/rerunFlakyTests.test.js
+++ b/tools/pull_request_hooks/rerunFlakyTests.test.js
@@ -1,45 +1,45 @@
-import { strict as assert } from "node:assert";
-import fs from "node:fs";
-import { extractDetails } from "./rerunFlakyTests.js";
+import { strict as assert } from 'node:assert';
+import fs from 'node:fs';
+import { extractDetails } from './rerunFlakyTests.js';
function extractDetailsFromPayload(filename) {
return extractDetails(
fs.readFileSync(`tests/flakyTestPayloads/${filename}.txt`, {
- encoding: "utf8",
+ encoding: 'utf8',
}),
);
}
-const chatClient = extractDetailsFromPayload("chat_client");
+const chatClient = extractDetailsFromPayload('chat_client');
assert.equal(
chatClient.title,
- "Flaky hard delete: /datum/computer_file/program/chatclient",
+ 'Flaky hard delete: /datum/computer_file/program/chatclient',
);
assert.equal(chatClient.failures.length, 1);
-const monkeyBusiness = extractDetailsFromPayload("monkey_business");
+const monkeyBusiness = extractDetailsFromPayload('monkey_business');
assert.equal(
monkeyBusiness.title,
- "Flaky test monkey_business: Cannot execute null.resolve().",
+ 'Flaky test monkey_business: Cannot execute null.resolve().',
);
assert.equal(monkeyBusiness.failures.length, 1);
-const shapeshift = extractDetailsFromPayload("shapeshift");
+const shapeshift = extractDetailsFromPayload('shapeshift');
assert.equal(
shapeshift.title,
- "Multiple errors in flaky test shapeshift_spell",
+ 'Multiple errors in flaky test shapeshift_spell',
);
assert.equal(shapeshift.failures.length, 16);
-const multipleFailures = extractDetailsFromPayload("multiple_failures");
+const multipleFailures = extractDetailsFromPayload('multiple_failures');
assert.equal(
multipleFailures.title,
- "Multiple flaky test failures in more_shapeshift_spell, shapeshift_spell",
+ 'Multiple flaky test failures in more_shapeshift_spell, shapeshift_spell',
);
assert.equal(multipleFailures.failures.length, 2);
-const invalidTimer = extractDetailsFromPayload("invalid_timer");
+const invalidTimer = extractDetailsFromPayload('invalid_timer');
assert.equal(
invalidTimer.title,
- "Flaky test monkey_business: Invalid timer: /datum/looping_sound/proc/start_sound_loop() on /datum/looping_sound/showering",
+ 'Flaky test monkey_business: Invalid timer: /datum/looping_sound/proc/start_sound_loop() on /datum/looping_sound/showering',
);
diff --git a/tools/screenshot-test-comparison/index.js b/tools/screenshot-test-comparison/index.js
index 0998344cf05..75f0a19f2d2 100644
--- a/tools/screenshot-test-comparison/index.js
+++ b/tools/screenshot-test-comparison/index.js
@@ -1,25 +1,33 @@
-const fs = require("fs");
-const path = require("path");
-const pixelmatch = require("pixelmatch");
-const process = require("process");
-const PNG = require("pngjs").PNG;
+import {
+ copyFileSync,
+ existsSync,
+ mkdirSync,
+ readdirSync,
+ readFileSync,
+ statSync,
+ writeFileSync,
+} from 'node:fs';
+import { join, parse } from 'node:path';
+import { argv, exit } from 'node:process';
+import pixelmatch from 'pixelmatch';
+import { PNG } from 'pngjs';
-const artifactsDirectory = process.argv[2];
+const artifactsDirectory = argv[2];
if (!artifactsDirectory) {
- console.error("Artifacts directory was not passed in");
- process.exit(1);
+ console.error('Artifacts directory was not passed in');
+ exit(1);
}
-const screenshotsDirectory = process.argv[3];
+const screenshotsDirectory = argv[3];
if (!screenshotsDirectory) {
- console.error("Screenshots directory was not passed in");
- process.exit(1);
+ console.error('Screenshots directory was not passed in');
+ exit(1);
}
-const outputDirectory = process.argv[4];
+const outputDirectory = argv[4];
if (!outputDirectory) {
- console.error("Output directory was not passed in");
- process.exit(1);
+ console.error('Output directory was not passed in');
+ exit(1);
}
const knownFailures = new Set();
@@ -27,49 +35,46 @@ const knownFailures = new Set();
const fail = (screenshotName, newScreenshot, oldScreenshot, diff) => {
knownFailures.add(screenshotName);
- const outputPath = path.join(
- outputDirectory,
- path.parse(screenshotName).name,
- );
- fs.mkdirSync(outputPath, {
+ const outputPath = join(outputDirectory, parse(screenshotName).name);
+ mkdirSync(outputPath, {
recursive: true,
});
- fs.copyFileSync(newScreenshot, path.join(outputPath, "new.png"));
+ copyFileSync(newScreenshot, join(outputPath, 'new.png'));
if (oldScreenshot) {
- fs.copyFileSync(oldScreenshot, path.join(outputPath, "old.png"));
+ copyFileSync(oldScreenshot, join(outputPath, 'old.png'));
}
if (diff) {
- fs.writeFileSync(path.join(outputPath, "diff.png"), PNG.sync.write(diff));
+ writeFileSync(join(outputPath, 'diff.png'), PNG.sync.write(diff));
}
};
-for (const filename of fs.readdirSync(artifactsDirectory)) {
- if (!filename.startsWith("test_artifacts")) {
+for (const filename of readdirSync(artifactsDirectory)) {
+ if (!filename.startsWith('test_artifacts')) {
continue;
}
- const fullPath = path.join(artifactsDirectory, filename, "screenshots_new");
+ const fullPath = join(artifactsDirectory, filename, 'screenshots_new');
- const fullPathStat = fs.statSync(fullPath);
+ const fullPathStat = statSync(fullPath);
if (!fullPathStat.isDirectory()) {
continue;
}
- for (const screenshotName of fs.readdirSync(fullPath)) {
+ for (const screenshotName of readdirSync(fullPath)) {
if (knownFailures.has(screenshotName)) {
continue;
}
- const fullPathScreenshotName = path.join(fullPath, screenshotName);
+ const fullPathScreenshotName = join(fullPath, screenshotName);
- const fullPathCompareScreenshot = path.join(
+ const fullPathCompareScreenshot = join(
screenshotsDirectory,
screenshotName,
);
- if (!fs.existsSync(fullPathCompareScreenshot)) {
+ if (!existsSync(fullPathCompareScreenshot)) {
console.error(
`${fullPathCompareScreenshot} is missing an existing screenshot to compare against`,
);
@@ -77,11 +82,9 @@ for (const filename of fs.readdirSync(artifactsDirectory)) {
continue;
}
- const screenshotNew = PNG.sync.read(
- fs.readFileSync(fullPathScreenshotName),
- );
+ const screenshotNew = PNG.sync.read(readFileSync(fullPathScreenshotName));
const screenshotCompare = PNG.sync.read(
- fs.readFileSync(fullPathCompareScreenshot),
+ readFileSync(fullPathCompareScreenshot),
);
if (
@@ -122,5 +125,5 @@ for (const filename of fs.readdirSync(artifactsDirectory)) {
if (knownFailures.size > 0) {
console.error(`${knownFailures.size} screenshots failed`);
- process.exit(1);
+ exit(1);
}
diff --git a/tools/test_merge_bot/comment.js b/tools/test_merge_bot/comment.js
index b512870e3a6..3a7d5c76a9e 100644
--- a/tools/test_merge_bot/comment.js
+++ b/tools/test_merge_bot/comment.js
@@ -13,7 +13,7 @@ export const createComment = (servers, existingComment) => {
servers[serverName] = server;
}
- for (const line of entries.split("\n")) {
+ for (const line of entries.split('\n')) {
const match = line.match(ENTRY_PATTERN);
if (!match) {
continue;
@@ -39,7 +39,7 @@ export const createComment = (servers, existingComment) => {
.flat()
.map(({ round_id }) => round_id)
.sort()
- .join(", ");
+ .join(', ');
const newHeader = ``;
@@ -48,30 +48,30 @@ export const createComment = (servers, existingComment) => {
}
let totalRounds = 0;
- let listOfRounds = "";
+ let listOfRounds = '';
for (const [server, rounds] of Object.entries(servers).sort(
([a], [b]) => b - a,
)) {
totalRounds += rounds.length;
- listOfRounds += `${"\n"}### ${server}`;
+ listOfRounds += `${'\n'}### ${server}`;
for (const { datetime, round_id, url } of rounds.sort(
(a, b) => b.round_id - a.round_id,
)) {
- listOfRounds += `${"\n"}- [${round_id} @ ${datetime}](${url})`;
+ listOfRounds += `${'\n'}- [${round_id} @ ${datetime}](${url})`;
}
- listOfRounds += "\n";
+ listOfRounds += '\n';
}
return (
newHeader +
`\nThis pull request was test merged in ${totalRounds} round(s).` +
- "\n" +
- "Round list
\n\n" +
+ '\n' +
+ 'Round list
\n\n' +
listOfRounds +
- "\n \n"
+ '\n \n'
);
};
diff --git a/tools/test_merge_bot/comment.test.js b/tools/test_merge_bot/comment.test.js
index d561bf4faec..c0f1182019a 100644
--- a/tools/test_merge_bot/comment.test.js
+++ b/tools/test_merge_bot/comment.test.js
@@ -1,13 +1,13 @@
-import { strict as assert } from "assert";
-import { createComment } from "./comment.js";
+import { strict as assert } from 'node:assert';
+import { createComment } from './comment.js';
const baseServers = {
bagil: [
{
round_id: 1,
- datetime: "2020-01-01 00:00:00",
- server: "bagil",
- url: "https://tgstation13.org/round/1",
+ datetime: '2020-01-01 00:00:00',
+ server: 'bagil',
+ url: 'https://tgstation13.org/round/1',
},
],
};
@@ -40,9 +40,9 @@ assert.equal(
bagil: [
{
round_id: 2,
- datetime: "2020-01-01 01:00:00",
- server: "bagil",
- url: "https://tgstation13.org/round/2",
+ datetime: '2020-01-01 01:00:00',
+ server: 'bagil',
+ url: 'https://tgstation13.org/round/2',
},
],
},
diff --git a/tools/test_merge_bot/main.js b/tools/test_merge_bot/main.js
index 1a1f343601d..4d7e2436859 100644
--- a/tools/test_merge_bot/main.js
+++ b/tools/test_merge_bot/main.js
@@ -1,12 +1,12 @@
-import fetch from "node-fetch";
-import { createComment } from "./comment.js";
+import fetch from 'node-fetch';
+import { createComment } from './comment.js';
-const TEST_MERGE_COMMENT_HEADER = "