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 = "