From ae48798f3bbaa8c5eac5968d60ae411c37dabbb5 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 14 Jul 2026 15:48:57 +0100 Subject: [PATCH] Make `versions.ts` testable and add basic tests --- pr-checks/update-release-branch.ts | 28 +++++++++++++++---- pr-checks/versions.test.ts | 44 ++++++++++++++++++++++++++++++ pr-checks/versions.ts | 38 ++++++++++++++++---------- 3 files changed, 90 insertions(+), 20 deletions(-) create mode 100755 pr-checks/versions.test.ts diff --git a/pr-checks/update-release-branch.ts b/pr-checks/update-release-branch.ts index d6cc7670a..56f3aef31 100755 --- a/pr-checks/update-release-branch.ts +++ b/pr-checks/update-release-branch.ts @@ -24,7 +24,11 @@ import { parseArgs } from "node:util"; import { type ApiClient, getApiClient } from "./api-client"; import * as changelog from "./changelog"; import { DryRunOption, REPO_ROOT } from "./config"; -import { getCurrentVersion, replaceVersionInPackageJson } from "./versions"; +import { + getCurrentVersion, + replaceVersionInPackageJson, + withPackageJson, +} from "./versions"; /** * NB: This exact commit message is used to find commits for reverting during backports. @@ -636,10 +640,20 @@ export async function prepareNewBranch( // Migrate the package version number. console.log(`Setting version number to '${version}' in package.json`); - const currentPkgVersion = getCurrentVersion(); - if (currentPkgVersion) { - replaceVersionInPackageJson(options, currentPkgVersion, version); - } + withPackageJson((content) => { + const currentPkgVersion = getCurrentVersion(content); + if (currentPkgVersion) { + return { + content: replaceVersionInPackageJson( + currentPkgVersion, + version, + content, + ), + value: currentPkgVersion, + }; + } + return { value: currentPkgVersion }; + }, options); runGit(["add", "package.json"], { dryRun: options.dryRun, }); @@ -733,7 +747,9 @@ async function main(): Promise { "", ); - const currentVersion = getCurrentVersion(); + const currentVersion = withPackageJson((content) => { + return { value: getCurrentVersion(content) }; + }, options); if (!currentVersion) { throw new Error("Failed to read current version from package.json"); diff --git a/pr-checks/versions.test.ts b/pr-checks/versions.test.ts new file mode 100755 index 000000000..6697710f8 --- /dev/null +++ b/pr-checks/versions.test.ts @@ -0,0 +1,44 @@ +#!/usr/bin/env npx tsx + +/** + * Tests for `versions.ts`. + */ + +import * as assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { getCurrentVersion, replaceVersionInPackageJson } from "./versions"; + +describe("getCurrentVersion", async () => { + await it("reads versions", async () => { + const result = getCurrentVersion(`{ "version": "1.23.4" }`); + assert.deepEqual(result, "1.23.4"); + }); +}); + +const packageJsonContents = `{ + "name": "codeql", + "version": "1.23.4" +} +`; + +const packageJsonContentsExpected = `{ + "name": "codeql", + "version": "2.23.4" +} +`; + +describe("replaceVersionInPackageJson", async () => { + await it("replaces versions", async () => { + const result = replaceVersionInPackageJson( + "1.23.4", + "2.23.4", + packageJsonContents, + ); + assert.deepEqual( + result.split("\n"), + packageJsonContentsExpected.split("\n"), + ); + assert.deepEqual(JSON.parse(result), { name: "codeql", version: "2.23.4" }); + }); +}); diff --git a/pr-checks/versions.ts b/pr-checks/versions.ts index 359868350..4abc7faa1 100644 --- a/pr-checks/versions.ts +++ b/pr-checks/versions.ts @@ -2,11 +2,27 @@ import * as fs from "node:fs"; import { DryRunOption, PACKAGE_JSON } from "./config"; +export function withPackageJson( + transformer: (content: string) => { value: T; content?: string }, + options: DryRunOption, +): T { + const content = fs.readFileSync(PACKAGE_JSON, "utf8"); + const result = transformer(content); + + if (result.content !== undefined) { + if (!options.dryRun) { + fs.writeFileSync(PACKAGE_JSON, result.content, "utf8"); + } else { + console.info(`[DRY RUN] Would have written an updated package.json`); + } + } + + return result.value; +} + /** Reads the current version from `package.json`. */ -export function getCurrentVersion(): string | undefined { - const pkg: { version: string } = JSON.parse( - fs.readFileSync(PACKAGE_JSON, "utf8"), - ); +export function getCurrentVersion(content: string): string | undefined { + const pkg: { version: string } = JSON.parse(content); return pkg.version; } @@ -17,11 +33,11 @@ export function getCurrentVersion(): string | undefined { * replace the version in package.json textually. */ export function replaceVersionInPackageJson( - options: DryRunOption, prevVersion: string, newVersion: string, -): void { - const lines = fs.readFileSync(PACKAGE_JSON, "utf8").split("\n"); + content: string, +): string { + const lines = content.split("\n"); let prevLineIsCodeql = false; const output: string[] = []; @@ -34,11 +50,5 @@ export function replaceVersionInPackageJson( prevLineIsCodeql = line.includes('"name": "codeql",'); } - if (!options.dryRun) { - fs.writeFileSync(PACKAGE_JSON, `${output.join("\n")}\n`, "utf8"); - } else { - console.info( - `[DRY RUN] Would have replaced '${prevVersion}' with '${newVersion}' in package.json`, - ); - } + return output.join("\n"); }