mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-30 21:23:04 +00:00
Accept prerelease Paseo versions in plugin requirements and prepare plugin docs for the 0.8 beta (#4452)
Accept plugin requirements against the runtime version or its stable core while preserving the legacy version boundary. Validate all example manifests, correct the ACP example metadata, and prepare plugin author documentation for the beta.
This commit is contained in:
@@ -1,24 +1,26 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { assertPluginCompatibility, validatePluginRequirements } from "./plugin-requirements.js";
|
||||
|
||||
describe("plugin requirements", () => {
|
||||
describe.each(["daemon", "app"] as const)("plugin requirements on %s", (runtime) => {
|
||||
it("rejects legacy manifests on the first breaking release with migration instructions", () => {
|
||||
expect(() =>
|
||||
assertPluginCompatibility({ id: "legacy", version: "0.8.0", runtime: "daemon" }),
|
||||
).toThrow(/legacy.*<0\.8\.0.*0\.8\.0.*https:\/\/paseo.sh\/docs\/plugins\/v0.8\/migration/);
|
||||
expect(() => assertPluginCompatibility({ id: "legacy", version: "0.8.0", runtime })).toThrow(
|
||||
/legacy.*<0\.8\.0.*0\.8\.0.*https:\/\/paseo.sh\/docs\/plugins\/v0.8\/migration/,
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
[undefined, "0.7.2"],
|
||||
[">=0.8.0", "0.8.0"],
|
||||
[">=0.8.0", "0.8.0-beta.1"],
|
||||
[">=0.8.0", "1.0.0"],
|
||||
["^0.8.0", "0.8.4"],
|
||||
[">=0.8.0-beta.1", "0.8.0-beta.2"],
|
||||
[">=0.8.0-beta.1", "0.8.0-beta.1"],
|
||||
[">=0.8.0-beta.1", "0.8.0"],
|
||||
["^0.8.0 || ^0.9.0", "0.9.2+build.42"],
|
||||
])("accepts %s on %s", (paseo, version) => {
|
||||
expect(() =>
|
||||
assertPluginCompatibility({ id: "test", requirements: { paseo }, version, runtime: "app" }),
|
||||
assertPluginCompatibility({ id: "test", requirements: { paseo }, version, runtime }),
|
||||
).not.toThrow();
|
||||
});
|
||||
|
||||
@@ -27,11 +29,11 @@ describe("plugin requirements", () => {
|
||||
[undefined, "0.9.0"],
|
||||
[">=0.8.0", "0.7.2"],
|
||||
["^0.8.0", "0.9.0"],
|
||||
[">=0.8.0", "0.8.0-beta.1"],
|
||||
["<0.8.0", "0.8.0-beta.1"],
|
||||
])("rejects %s on %s", (paseo, version) => {
|
||||
expect(() =>
|
||||
assertPluginCompatibility({ id: "test", requirements: { paseo }, version, runtime: "app" }),
|
||||
).toThrow(`Your app is ${version}`);
|
||||
assertPluginCompatibility({ id: "test", requirements: { paseo }, version, runtime }),
|
||||
).toThrow(`Your ${runtime} is ${version}`);
|
||||
});
|
||||
|
||||
it.each(["", " ", "latest", ">=potato", "0.8.0 nonsense"])(
|
||||
@@ -47,8 +49,8 @@ describe("plugin requirements", () => {
|
||||
id: "test",
|
||||
requirements: { paseo: "*" },
|
||||
version,
|
||||
runtime: "app",
|
||||
runtime,
|
||||
}),
|
||||
).toThrow("Paseo app version is unknown");
|
||||
).toThrow(`Paseo ${runtime} version is unknown`);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginRequirements } from "./messages.js";
|
||||
import valid from "semver/functions/valid.js";
|
||||
import parse from "semver/functions/parse.js";
|
||||
import validRange from "semver/ranges/valid.js";
|
||||
import satisfies from "semver/functions/satisfies.js";
|
||||
|
||||
@@ -21,14 +21,16 @@ interface PluginCompatibilityInput {
|
||||
|
||||
export function assertPluginCompatibility(input: PluginCompatibilityInput): void {
|
||||
validatePluginRequirements(input.requirements);
|
||||
// COMPAT(plugin-requirements): added in v0.8.0; remove after 2027-03-07 once pre-0.8 plugins and catalogs are unsupported.
|
||||
// COMPAT(plugin-requirements): added in v0.8.0-beta.1; remove after 2027-03-07 once pre-0.8 plugins and catalogs are unsupported. The legacy range excludes 0.8 prereleases and their stable core.
|
||||
const range = input.requirements?.paseo ?? "<0.8.0";
|
||||
if (!input.version || !valid(input.version)) {
|
||||
const version = input.version ? parse(input.version) : null;
|
||||
if (!version) {
|
||||
throw new Error(
|
||||
`Cannot check plugin "${input.id}" requirements: Paseo ${input.runtime} version is unknown. Update the ${input.runtime}.`,
|
||||
);
|
||||
}
|
||||
if (satisfies(input.version, range)) return;
|
||||
const stableCore = `${version.major}.${version.minor}.${version.patch}`;
|
||||
if (satisfies(version, range) || satisfies(stableCore, range)) return;
|
||||
const action =
|
||||
input.requirements?.paseo === undefined
|
||||
? "This plugin has no requirements.paseo and targets Paseo before 0.8. Ask its author to migrate it: https://paseo.sh/docs/plugins/v0.8/migration"
|
||||
|
||||
@@ -1,16 +1,29 @@
|
||||
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
||||
import { mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { readPluginManifest } from "./manifest.js";
|
||||
|
||||
const directories: string[] = [];
|
||||
const examplesDirectory = fileURLToPath(
|
||||
new URL("../../../../../plugin-examples/", import.meta.url),
|
||||
);
|
||||
const examples = (await readdir(examplesDirectory, { withFileTypes: true }))
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => entry.name);
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(directories.splice(0).map((directory) => rm(directory, { recursive: true })));
|
||||
});
|
||||
|
||||
describe("plugin manifest", () => {
|
||||
it.each(examples)("validates the %s example manifest", async (name) => {
|
||||
await expect(readPluginManifest(path.join(examplesDirectory, name))).resolves.toMatchObject({
|
||||
id: expect.any(String),
|
||||
});
|
||||
});
|
||||
|
||||
it("reads and validates requirements before any plugin code runs", async () => {
|
||||
const directory = await mkdtemp(path.join(tmpdir(), "paseo-plugin-manifest-"));
|
||||
directories.push(directory);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import { buildDocsNavTree, getDocs, getLegacyDocsRedirect } from "./docs";
|
||||
|
||||
describe("versioned plugin documentation", () => {
|
||||
it("keeps current and preview releases together in the Plugins navigation", () => {
|
||||
it("keeps stable and beta releases together in the Plugins navigation", () => {
|
||||
const plugins = buildDocsNavTree(getDocs()).find(
|
||||
(node) => node.type === "category" && node.label === "Plugins",
|
||||
);
|
||||
@@ -19,11 +19,12 @@ describe("versioned plugin documentation", () => {
|
||||
},
|
||||
{
|
||||
type: "group",
|
||||
label: "Paseo v0.8 — Preview",
|
||||
label: "Paseo v0.8 — Beta",
|
||||
href: "/docs/plugins/v0.8",
|
||||
children: [
|
||||
{ type: "page", label: "Reference", href: "/docs/plugins/v0.8/reference" },
|
||||
{ type: "page", label: "Provider plugins", href: "/docs/plugins/v0.8/providers" },
|
||||
{ type: "page", label: "Migration", href: "/docs/plugins/v0.8/migration" },
|
||||
{ type: "page", label: "Reference", href: "/docs/plugins/v0.8/reference" },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user