From f9feddd874d4b3da054c2d5a50bf973b7c0dcbb9 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Tue, 19 May 2026 14:03:20 +0100 Subject: [PATCH] Add tests for `update-ghes-versions.ts` --- pr-checks/update-ghes-versions.test.ts | 204 +++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 pr-checks/update-ghes-versions.test.ts diff --git a/pr-checks/update-ghes-versions.test.ts b/pr-checks/update-ghes-versions.test.ts new file mode 100644 index 000000000..187c067c3 --- /dev/null +++ b/pr-checks/update-ghes-versions.test.ts @@ -0,0 +1,204 @@ +#!/usr/bin/env npx tsx + +/* + * Tests for the update-ghes-versions.ts script + */ + +import * as assert from "node:assert/strict"; +import { describe, it } from "node:test"; + +import { + addWeeks, + determineSupportedRange, + type EnterpriseReleases, + parseEnterpriseVersion, + printEnterpriseVersion, +} from "./update-ghes-versions"; + +describe("parseEnterpriseVersion", async () => { + await it("parses a two-component version string", () => { + const ver = parseEnterpriseVersion("3.10"); + assert.notEqual(ver, null); + assert.equal(ver!.major, 3); + assert.equal(ver!.minor, 10); + assert.equal(ver!.patch, 0); + }); + + await it("parses a three-component version string", () => { + const ver = parseEnterpriseVersion("3.10.2"); + assert.notEqual(ver, null); + assert.equal(ver!.major, 3); + assert.equal(ver!.minor, 10); + assert.equal(ver!.patch, 2); + }); + + await it("returns null for invalid input", () => { + assert.equal(parseEnterpriseVersion("not-a-version"), null); + }); +}); + +describe("printEnterpriseVersion", async () => { + await it("prints only major.minor when patch is 0", () => { + const ver = parseEnterpriseVersion("3.10")!; + assert.equal(printEnterpriseVersion(ver), "3.10"); + }); + + await it("includes patch when non-zero", () => { + const ver = parseEnterpriseVersion("3.10.2")!; + assert.equal(printEnterpriseVersion(ver), "3.10.2"); + }); +}); + +describe("addWeeks", async () => { + await it("adds weeks to a date", () => { + const date = new Date("2025-01-01T00:00:00Z"); + const result = addWeeks(date, 2); + assert.equal(result.toISOString(), "2025-01-15T00:00:00.000Z"); + }); + + await it("does not mutate the original date", () => { + const date = new Date("2025-01-01T00:00:00Z"); + addWeeks(date, 2); + assert.equal(date.toISOString(), "2025-01-01T00:00:00.000Z"); + }); +}); + +/** + * Helper to build a release entry with a feature freeze and end-of-life date. + * Dates are ISO date strings (e.g. "2025-06-01"). + */ +function release(featureFreeze: string, end: string) { + return { feature_freeze: featureFreeze, end }; +} + +describe("determineSupportedRange", async () => { + // A fixed "today" for deterministic tests. + const today = new Date("2025-06-15"); + + const farPastEnd = "2020-01-01"; + const farFutureEnd = "2099-12-31"; + const farPastFreeze = "2020-01-01"; + const farFutureFreeze = "2099-12-31"; + + await it("returns the only supported release as both min and max", () => { + const releases: EnterpriseReleases = { + "3.10": release(farPastFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.10" }, + releases, + ); + assert.equal(result.minimumVersion, "3.10"); + assert.equal(result.maximumVersion, "3.10"); + }); + + await it("determines the range from multiple supported releases", () => { + const releases: EnterpriseReleases = { + "3.10": release(farPastFreeze, farFutureEnd), + "3.11": release(farPastFreeze, farFutureEnd), + "3.12": release(farPastFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.12" }, + releases, + ); + assert.equal(result.minimumVersion, "3.10"); + assert.equal(result.maximumVersion, "3.12"); + }); + + await it("drops an end-of-life release from the minimum", () => { + const releases: EnterpriseReleases = { + // 3.10 has been end of life for a long time. + "3.10": release(farPastFreeze, farPastEnd), + "3.11": release(farPastFreeze, farFutureEnd), + "3.12": release(farPastFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.12" }, + releases, + ); + assert.equal(result.minimumVersion, "3.11"); + assert.equal(result.maximumVersion, "3.12"); + }); + + await it("bumps the maximum when a newer release's feature freeze has passed", () => { + const releases: EnterpriseReleases = { + "3.10": release(farPastFreeze, farFutureEnd), + "3.11": release(farPastFreeze, farFutureEnd), + // 3.12 has a feature freeze far in the past, so it should be picked up. + "3.12": release(farPastFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + // The stored maximum is 3.11, but 3.12 should be picked up. + { minimumVersion: "3.10", maximumVersion: "3.11" }, + releases, + ); + assert.equal(result.minimumVersion, "3.10"); + assert.equal(result.maximumVersion, "3.12"); + }); + + await it("does not bump the maximum when feature freeze is far in the future", () => { + const releases: EnterpriseReleases = { + "3.10": release(farPastFreeze, farFutureEnd), + "3.11": release(farPastFreeze, farFutureEnd), + // 3.12 has a feature freeze far in the future, so it should NOT be picked up. + "3.12": release(farFutureFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.11" }, + releases, + ); + assert.equal(result.minimumVersion, "3.10"); + assert.equal(result.maximumVersion, "3.11"); + }); + + await it("ignores releases older than the first supported release (2.22)", () => { + const releases: EnterpriseReleases = { + "2.21": release(farPastFreeze, farFutureEnd), + "3.10": release(farPastFreeze, farFutureEnd), + "3.11": release(farPastFreeze, farFutureEnd), + }; + const result = determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.11" }, + releases, + ); + // 2.21 is older than 2.22, so it should be ignored — 3.10 remains the minimum. + assert.equal(result.minimumVersion, "3.10"); + assert.equal(result.maximumVersion, "3.11"); + }); + + await it("throws when no supported releases remain", () => { + const releases: EnterpriseReleases = { + // All releases are end of life. + "3.10": release(farPastFreeze, farPastEnd), + "3.11": release(farPastFreeze, farPastEnd), + }; + assert.throws( + () => + determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "3.11" }, + releases, + ), + /Could not determine oldest supported release/, + ); + }); + + await it("throws when maximumVersion is not a valid version", () => { + assert.throws( + () => + determineSupportedRange( + today, + { minimumVersion: "3.10", maximumVersion: "invalid" }, + {}, + ), + /is not a valid semantic version/, + ); + }); +});