Compare commits

...

15 Commits

Author SHA1 Message Date
Michael B. Gale 7ba697a3ec Fix comment and clear time component 2026-05-19 14:32:00 +01:00
Michael B. Gale 74374a3893 Rebuild (newer semver version) 2026-05-19 14:15:04 +01:00
Michael B. Gale 3e85884434 Remove Python version 2026-05-19 14:10:44 +01:00
Michael B. Gale 5aed9f7d64 Update workflow to use update-ghes-versions.ts 2026-05-19 14:10:44 +01:00
Michael B. Gale f9feddd874 Add tests for update-ghes-versions.ts 2026-05-19 14:10:44 +01:00
Michael B. Gale 15f19e1870 Add date as a parameter for determineSupportedRange 2026-05-19 14:10:44 +01:00
Michael B. Gale 51cc08af6f Add determineSupportedRange 2026-05-19 14:10:44 +01:00
Michael B. Gale 71b697dd8b Add helpers for GHES versions 2026-05-19 14:10:43 +01:00
Michael B. Gale f5808271b0 Add readEnterpriseReleases 2026-05-19 14:10:43 +01:00
Michael B. Gale da26a016ee Add readApiCompatibility 2026-05-19 14:10:43 +01:00
Michael B. Gale 4536424fcf Throw if ENTERPRISE_RELEASES_PATH is not set 2026-05-19 14:10:41 +01:00
Michael B. Gale d98bedfdea Add constant for FIRST_SUPPORTED_RELEASE 2026-05-19 14:10:25 +01:00
Michael B. Gale 952a538c24 Add constant for API_COMPATIBILITY_FILE 2026-05-19 14:09:45 +01:00
Michael B. Gale 04d4fd51e9 Add semver dependency 2026-05-18 19:42:36 +01:00
Michael B. Gale c05837d3e8 Scaffold update-ghes-versions.ts script 2026-05-18 19:38:16 +01:00
11 changed files with 561 additions and 101 deletions
@@ -9,7 +9,7 @@ on:
- main
paths:
- .github/workflows/update-supported-enterprise-server-versions.yml
- .github/workflows/update-supported-enterprise-server-versions/update.py
- pr-checks/update-ghes-versions.ts
jobs:
update-supported-enterprise-server-versions:
@@ -22,12 +22,18 @@ jobs:
pull-requests: write # needed to create pull request
steps:
- name: Setup Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Checkout CodeQL Action
uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Checkout Enterprise Releases
uses: actions/checkout@v6
with:
@@ -35,18 +41,18 @@ jobs:
token: ${{ secrets.ENTERPRISE_RELEASE_TOKEN }}
path: ${{ github.workspace }}/enterprise-releases/
sparse-checkout: releases.json
- name: Update Supported Enterprise Server Versions
working-directory: pr-checks
run: |
cd ./.github/workflows/update-supported-enterprise-server-versions/
python3 -m pip install pipenv
pipenv install
pipenv run ./update.py
npx tsx update-ghes-versions.ts
rm --recursive "$ENTERPRISE_RELEASES_PATH"
npm ci
npm run build
env:
ENTERPRISE_RELEASES_PATH: ${{ github.workspace }}/enterprise-releases/
- name: Rebuild
run: npm run build
- name: Update git config
run: |
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
@@ -1,9 +0,0 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
semver = "*"
@@ -1,27 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "e3ba923dcb4888e05de5448c18a732bf40197e80fabfa051a61c01b22c504879"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"semver": {
"hashes": [
"sha256:ced8b23dceb22134307c1b8abfa523da14198793d9787ac838e70e29e77458d4",
"sha256:fa0fe2722ee1c3f57eac478820c3a5ae2f624af8264cbdf9000c980ff7f75e3f"
],
"index": "pypi",
"version": "==2.13.0"
}
},
"develop": {}
}
@@ -1,51 +0,0 @@
#!/usr/bin/env python3
import datetime
import json
import os
import pathlib
import semver
_API_COMPATIBILITY_PATH = pathlib.Path(__file__).absolute().parents[3] / "src" / "api-compatibility.json"
_ENTERPRISE_RELEASES_PATH = pathlib.Path(os.environ["ENTERPRISE_RELEASES_PATH"])
_RELEASE_FILE_PATH = _ENTERPRISE_RELEASES_PATH / "releases.json"
_FIRST_SUPPORTED_RELEASE = semver.VersionInfo.parse("2.22.0") # Versions older than this did not include Code Scanning.
def main():
api_compatibility_data = json.loads(_API_COMPATIBILITY_PATH.read_text())
releases = json.loads(_RELEASE_FILE_PATH.read_text())
# Remove GHES version using a previous version numbering scheme.
if "11.10" in releases:
del releases["11.10"]
oldest_supported_release = None
newest_supported_release = semver.VersionInfo.parse(api_compatibility_data["maximumVersion"] + ".0")
for release_version_string, release_data in releases.items():
release_version = semver.VersionInfo.parse(release_version_string + ".0")
if release_version < _FIRST_SUPPORTED_RELEASE:
continue
if release_version > newest_supported_release:
feature_freeze_date = datetime.date.fromisoformat(release_data["feature_freeze"])
if feature_freeze_date < datetime.date.today() + datetime.timedelta(weeks=2):
newest_supported_release = release_version
if oldest_supported_release is None or release_version < oldest_supported_release:
end_of_life_date = datetime.date.fromisoformat(release_data["end"])
# The GHES version is not actually end of life until the end of the day specified by
# `end_of_life_date`. Wait an extra week to be safe.
is_end_of_life = datetime.date.today() > end_of_life_date + datetime.timedelta(weeks=1)
if not is_end_of_life:
oldest_supported_release = release_version
api_compatibility_data = {
"minimumVersion": f"{oldest_supported_release.major}.{oldest_supported_release.minor}",
"maximumVersion": f"{newest_supported_release.major}.{newest_supported_release.minor}",
}
_API_COMPATIBILITY_PATH.write_text(json.dumps(api_compatibility_data, sort_keys=True) + "\n")
if __name__ == "__main__":
main()
+43
View File
@@ -26704,6 +26704,47 @@ var require_coerce = __commonJS({
}
});
// node_modules/semver/functions/truncate.js
var require_truncate = __commonJS({
"node_modules/semver/functions/truncate.js"(exports2, module2) {
"use strict";
var parse2 = require_parse2();
var constants = require_constants6();
var SemVer = require_semver();
var truncate = (version, truncation, options) => {
if (!constants.RELEASE_TYPES.includes(truncation)) {
return null;
}
const clonedVersion = cloneInputVersion(version, options);
return clonedVersion && doTruncation(clonedVersion, truncation);
};
var cloneInputVersion = (version, options) => {
const versionStringToParse = version instanceof SemVer ? version.version : version;
return parse2(versionStringToParse, options);
};
var doTruncation = (version, truncation) => {
if (isPrerelease(truncation)) {
return version.version;
}
version.prerelease = [];
switch (truncation) {
case "major":
version.minor = 0;
version.patch = 0;
break;
case "minor":
version.patch = 0;
break;
}
return version.format();
};
var isPrerelease = (type2) => {
return type2.startsWith("pre");
};
module2.exports = truncate;
}
});
// node_modules/semver/internal/lrucache.js
var require_lrucache = __commonJS({
"node_modules/semver/internal/lrucache.js"(exports2, module2) {
@@ -27738,6 +27779,7 @@ var require_semver2 = __commonJS({
var lte = require_lte();
var cmp = require_cmp();
var coerce3 = require_coerce();
var truncate = require_truncate();
var Comparator = require_comparator();
var Range2 = require_range();
var satisfies2 = require_satisfies();
@@ -27776,6 +27818,7 @@ var require_semver2 = __commonJS({
lte,
cmp,
coerce: coerce3,
truncate,
Comparator,
Range: Range2,
satisfies: satisfies2,
+43
View File
@@ -28009,6 +28009,47 @@ var require_coerce = __commonJS({
}
});
// node_modules/semver/functions/truncate.js
var require_truncate = __commonJS({
"node_modules/semver/functions/truncate.js"(exports2, module2) {
"use strict";
var parse2 = require_parse2();
var constants = require_constants6();
var SemVer = require_semver();
var truncate = (version, truncation, options) => {
if (!constants.RELEASE_TYPES.includes(truncation)) {
return null;
}
const clonedVersion = cloneInputVersion(version, options);
return clonedVersion && doTruncation(clonedVersion, truncation);
};
var cloneInputVersion = (version, options) => {
const versionStringToParse = version instanceof SemVer ? version.version : version;
return parse2(versionStringToParse, options);
};
var doTruncation = (version, truncation) => {
if (isPrerelease(truncation)) {
return version.version;
}
version.prerelease = [];
switch (truncation) {
case "major":
version.minor = 0;
version.patch = 0;
break;
case "minor":
version.patch = 0;
break;
}
return version.format();
};
var isPrerelease = (type2) => {
return type2.startsWith("pre");
};
module2.exports = truncate;
}
});
// node_modules/semver/internal/lrucache.js
var require_lrucache = __commonJS({
"node_modules/semver/internal/lrucache.js"(exports2, module2) {
@@ -29043,6 +29084,7 @@ var require_semver2 = __commonJS({
var lte = require_lte();
var cmp = require_cmp();
var coerce3 = require_coerce();
var truncate = require_truncate();
var Comparator = require_comparator();
var Range2 = require_range();
var satisfies2 = require_satisfies();
@@ -29081,6 +29123,7 @@ var require_semver2 = __commonJS({
lte,
cmp,
coerce: coerce3,
truncate,
Comparator,
Range: Range2,
satisfies: satisfies2,
+4 -3
View File
@@ -8320,9 +8320,9 @@
}
},
"node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz",
"integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
@@ -10404,6 +10404,7 @@
"@octokit/core": "^7.0.6",
"@octokit/plugin-paginate-rest": ">=9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
"semver": "^7.8.0",
"yaml": "^2.8.4"
},
"devDependencies": {
+6
View File
@@ -21,3 +21,9 @@ export const BUILTIN_LANGUAGES_FILE = path.join(
"languages",
"builtin.json",
);
/** Path to the api-compatibility.json file. */
export const API_COMPATIBILITY_FILE = path.join(
SOURCE_ROOT,
"api-compatibility.json",
);
+1
View File
@@ -7,6 +7,7 @@
"@octokit/core": "^7.0.6",
"@octokit/plugin-paginate-rest": ">=9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
"semver": "^7.8.0",
"yaml": "^2.8.4"
},
"devDependencies": {
+204
View File
@@ -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/,
);
});
});
+243
View File
@@ -0,0 +1,243 @@
#!/usr/bin/env npx tsx
/**
* Updates src/api-compatibility.json with the current range of supported
* GitHub Enterprise Server versions by reading the releases.json file from
* an `enterprise-releases` checkout.
*/
import * as fs from "node:fs";
import * as path from "node:path";
import { type SemVer } from "semver";
import * as semver from "semver";
import * as json from "../src/json";
import { API_COMPATIBILITY_FILE } from "./config";
/** The first GHES version that included Code Scanning. */
const FIRST_SUPPORTED_RELEASE: SemVer = new semver.SemVer("2.22.0");
/** Environment variables specific to this script. */
export enum EnvVar {
ENTERPRISE_RELEASES_PATH = "ENTERPRISE_RELEASES_PATH",
}
/**
* The semver specification requires three numeric components, but GHES release families
* only have two. This function uses `semver.coerce` to first coerce the version string
* into an acceptable input for `semver.parse`. E.g. `3.10` becomes `3.10.0`.
*/
export function parseEnterpriseVersion(val: string): SemVer | null {
return semver.parse(semver.coerce(val));
}
/**
* Mirroring `parseEnterpriseVersion`, this function returns only the major and minor
* version components from `ver`.
*/
export function printEnterpriseVersion(ver: SemVer) {
if (ver.patch === 0) {
return `${ver.major}.${ver.minor}`;
}
return ver.toString();
}
/** The JSON schema for `API_COMPATIBILITY_FILE`. */
const apiCompatibilitySchema = {
minimumVersion: json.string,
maximumVersion: json.string,
} as const satisfies json.Schema;
/** The type representing the expected contents of `API_COMPATIBILITY_FILE`. */
type ApiCompatibility = json.FromSchema<typeof apiCompatibilitySchema>;
/** Reads the current contents of the `API_COMPATIBILITY_FILE` file. */
export function readApiCompatibility(): ApiCompatibility {
const apiCompatibilityData: unknown = JSON.parse(
fs.readFileSync(API_COMPATIBILITY_FILE, "utf8"),
);
if (!json.isObject(apiCompatibilityData)) {
throw new Error(
`Expected '${API_COMPATIBILITY_FILE}' to contain an object.`,
);
}
if (!json.validateSchema(apiCompatibilitySchema, apiCompatibilityData)) {
throw new Error(
`The contents of '${API_COMPATIBILITY_FILE}' do not match the expected JSON schema.`,
);
}
return apiCompatibilityData;
}
/** The JSON schema for entries in the `releases.json` file. */
const releaseDataSchema = {
feature_freeze: json.string,
end: json.string,
} as const satisfies json.Schema;
/** The type representing entries in the `releases.json` file. */
export type ReleaseData = json.FromSchema<typeof releaseDataSchema>;
/** A mapping from GHES releases to release information. */
export type EnterpriseReleases = Record<string, ReleaseData>;
/** Reads information about GHES releases. */
export function readEnterpriseReleases(
enterpriseReleasesPath: string,
): EnterpriseReleases {
const releaseFilePath = path.join(enterpriseReleasesPath, "releases.json");
const releases: unknown = JSON.parse(
fs.readFileSync(releaseFilePath, "utf8"),
);
if (!json.isObject(releases)) {
throw new Error(`Expected '${releaseFilePath}' to contain an object.`);
}
// Remove GHES version using a previous version numbering scheme.
delete releases["11.10"];
// Validate that the object satisfies the schema.
for (const [, releaseData] of Object.entries(releases)) {
if (!json.isObject(releaseData)) {
throw new Error(
`Expected release data to be an object, but it is ${typeof releaseData}.`,
);
}
if (!json.validateSchema(releaseDataSchema, releaseData)) {
throw new Error("Expected release data to satisfy schema.");
}
}
return releases;
}
/** Adds `weeks`-many weeks to the UTC date of `date`. */
export function addWeeks(date: Date, weeks: number): Date {
const result = new Date(date);
result.setUTCDate(date.getUTCDate() + weeks * 7);
return result;
}
/** Determines the current range of GHES versions we should support. */
export function determineSupportedRange(
today: Date,
apiCompatibilityData: ApiCompatibility,
releases: EnterpriseReleases,
): ApiCompatibility {
// We only care about the UTC date component.
today.setUTCHours(0, 0, 0, 0);
// Our goal is to identify the oldest and newest GHES release we should support.
// We begin with `oldestSupportRelease = undefined` so that we determine the
// minimum from scratch and don't stick to `apiCompatibilityData.minimumVersion`
// when it is no longer supported.
// For `newestSupportedRelease`, we assume that `apiCompatibilityData.maximumVersion`
// is guaranteed to not be outdated.
let oldestSupportedRelease: SemVer | undefined;
let newestSupportedRelease = parseEnterpriseVersion(
apiCompatibilityData.maximumVersion,
);
if (newestSupportedRelease === null) {
throw new Error(
`${apiCompatibilityData.maximumVersion} is not a valid semantic version.`,
);
}
// NOTE: We deliberately omit including any data from `releases` in the error messages below.
for (const [releaseVersionString, releaseData] of Object.entries(releases)) {
const releaseVersion = parseEnterpriseVersion(releaseVersionString);
if (releaseVersion === null) {
throw new Error("Invalid enterprise release version.");
}
// Ignore GHES releases older than `FIRST_SUPPORTED_RELEASE`.
if (semver.compare(releaseVersion, FIRST_SUPPORTED_RELEASE) < 0) {
continue;
}
// Set `newestSupportedRelease` to a GHES release if it has a greater version
// than the current `newestSupportedRelease` and the feature freeze has
// already happened or will be in the next two weeks.
if (semver.compare(releaseVersion, newestSupportedRelease) > 0) {
const featureFreezeDate = new Date(releaseData.feature_freeze);
if (featureFreezeDate < addWeeks(today, 2)) {
newestSupportedRelease = releaseVersion;
}
}
if (
oldestSupportedRelease === undefined ||
semver.compare(releaseVersion, oldestSupportedRelease) < 0
) {
const endOfLifeDate = new Date(releaseData.end);
// The GHES version is not actually end of life until the end of the day
// specified by `endOfLifeDate`. Wait an extra week to be safe.
const isEndOfLife = today > addWeeks(endOfLifeDate, 1);
if (!isEndOfLife) {
oldestSupportedRelease = releaseVersion;
}
}
}
if (!oldestSupportedRelease) {
throw new Error("Could not determine oldest supported release.");
}
return {
maximumVersion: printEnterpriseVersion(newestSupportedRelease),
minimumVersion: printEnterpriseVersion(oldestSupportedRelease),
};
}
function main() {
const enterpriseReleasesPath = process.env[EnvVar.ENTERPRISE_RELEASES_PATH];
if (!enterpriseReleasesPath) {
throw new Error(
`${EnvVar.ENTERPRISE_RELEASES_PATH} environment variable must be set`,
);
}
// Get the version compatibility data stored in the repo.
const apiCompatibilityData = readApiCompatibility();
// Get the GHES release information.
const releases = readEnterpriseReleases(enterpriseReleasesPath);
// Determine the supported range.
const newCompatibilityData: ApiCompatibility = determineSupportedRange(
new Date(),
apiCompatibilityData,
releases,
);
// If the version range has changed, write the updates to `API_COMPATIBILITY_FILE`.
if (
newCompatibilityData.minimumVersion !==
apiCompatibilityData.minimumVersion ||
newCompatibilityData.maximumVersion !== apiCompatibilityData.maximumVersion
) {
const data = JSON.stringify(newCompatibilityData);
fs.writeFileSync(API_COMPATIBILITY_FILE, `${data}\n`);
console.log(
`Updated '${path.basename(API_COMPATIBILITY_FILE)}': ${newCompatibilityData.minimumVersion} - ${newCompatibilityData.maximumVersion}`,
);
} else {
console.log(
`No changes, not writing to '${path.basename(API_COMPATIBILITY_FILE)}'.`,
);
}
}
// Only call `main` if this script was run directly.
if (require.main === module) {
main();
}