diff --git a/src/extensions/__tests__/extension-compatibility.test.ts b/src/extensions/__tests__/extension-compatibility.test.ts index 6bcac675019b..6a3dc0265d8a 100644 --- a/src/extensions/__tests__/extension-compatibility.test.ts +++ b/src/extensions/__tests__/extension-compatibility.test.ts @@ -19,29 +19,24 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { isCompatibleExtension } from "../extension-compatibility"; +import { rawIsCompatibleExtension } from "../extension-compatibility"; import { Console } from "console"; import { stdout, stderr } from "process"; import type { LensExtensionManifest } from "../lens-extension"; -import { appSemVer } from "../../common/vars"; +import { SemVer } from "semver"; console = new Console(stdout, stderr); describe("extension compatibility", () => { describe("appSemVer with no prerelease tag", () => { - beforeAll(() => { - appSemVer.major = 5; - appSemVer.minor = 0; - appSemVer.patch = 3; - appSemVer.prerelease = []; - }); + const isCompatibleExtension = rawIsCompatibleExtension(new SemVer("5.0.3")); it("has no extension comparator", () => { const manifest = { name: "extensionName", version: "0.0.1" }; expect(isCompatibleExtension(manifest)).toBe(false); }); - + it.each([ { comparator: "", @@ -83,19 +78,32 @@ describe("extension compatibility", () => { }); describe("appSemVer with prerelease tag", () => { - beforeAll(() => { - appSemVer.major = 5; - appSemVer.minor = 0; - appSemVer.patch = 3; - appSemVer.prerelease = ["beta", 3]; + const isCompatibleExtension = rawIsCompatibleExtension(new SemVer("5.0.3-beta.3")); + + it("^5.1.0 should work when lens' version is 5.1.0-latest.123456789", () => { + const comparer = rawIsCompatibleExtension(new SemVer("5.1.0-latest.123456789")); + + expect(comparer({ name: "extensionName", version: "0.0.1", engines: { lens: "^5.1.0" }})).toBe(true); }); - + + it("^5.1.0 should not when lens' version is 5.1.0-beta.1.123456789", () => { + const comparer = rawIsCompatibleExtension(new SemVer("5.1.0-beta.123456789")); + + expect(comparer({ name: "extensionName", version: "0.0.1", engines: { lens: "^5.1.0" }})).toBe(false); + }); + + it("^5.1.0 should not when lens' version is 5.1.0-alpha.1.123456789", () => { + const comparer = rawIsCompatibleExtension(new SemVer("5.1.0-alpha.123456789")); + + expect(comparer({ name: "extensionName", version: "0.0.1", engines: { lens: "^5.1.0" }})).toBe(false); + }); + it("has no extension comparator", () => { const manifest = { name: "extensionName", version: "0.0.1" }; expect(isCompatibleExtension(manifest)).toBe(false); }); - + it.each([ { comparator: "", @@ -130,9 +138,7 @@ describe("extension compatibility", () => { expected: false, }, ])("extension comparator test: %p", ({ comparator, expected }) => { - const manifest: LensExtensionManifest = { name: "extensionName", version: "0.0.1", engines: { lens: comparator }}; - - expect(isCompatibleExtension(manifest)).toBe(expected); + expect(isCompatibleExtension({ name: "extensionName", version: "0.0.1", engines: { lens: comparator }})).toBe(expected); }); }); }); diff --git a/src/extensions/extension-compatibility.ts b/src/extensions/extension-compatibility.ts index 3d958072dca8..ba5dcf2e1a31 100644 --- a/src/extensions/extension-compatibility.ts +++ b/src/extensions/extension-compatibility.ts @@ -19,19 +19,47 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import semver from "semver"; +import semver, { SemVer } from "semver"; import { appSemVer, isProduction } from "../common/vars"; import type { LensExtensionManifest } from "./lens-extension"; -export function isCompatibleExtension(manifest: LensExtensionManifest): boolean { - if (manifest.engines?.lens) { - /* include Lens's prerelease tag in the matching so the extension's compatibility is not limited by it */ - return semver.satisfies(appSemVer, manifest.engines.lens, { includePrerelease: true }); +export function rawIsCompatibleExtension(version: SemVer): (manifest: LensExtensionManifest) => boolean { + const { major, minor, patch, prerelease: oldPrelease } = version; + let prerelease = ""; + + if (oldPrelease.length > 0) { + const [first] = oldPrelease; + + if (first === "alpha" || first === "beta" || first === "rc") { + /** + * Strip the build IDs and "latest" prerelease tag as that is not really + * a part of API version + */ + prerelease = `-${oldPrelease.slice(0, 2).join(".")}`; + } } - return false; + /** + * We unfortunately have to format as string because the constructor only + * takes an instance or a string. + */ + const strippedVersion = new SemVer(`${major}.${minor}.${patch}${prerelease}`, { includePrerelease: true }); + + return (manifest: LensExtensionManifest): boolean => { + if (manifest.engines?.lens) { + /** + * include Lens's prerelease tag in the matching so the extension's + * compatibility is not limited by it + */ + return semver.satisfies(strippedVersion, manifest.engines.lens, { includePrerelease: true }); + } + + return false; + }; } +export const isCompatibleExtension = rawIsCompatibleExtension(appSemVer); + export function isCompatibleBundledExtension(manifest: LensExtensionManifest): boolean { return !isProduction || manifest.version === appSemVer.raw; }