|
| 1 | +import assert from "node:assert/strict" |
| 2 | +import { chmod, mkdir, readFile, stat, writeFile } from "node:fs/promises" |
| 3 | +import { join } from "node:path" |
| 4 | + |
| 5 | +import { cleanupRecipePreparedSources, prepareRecipeExtraPlugins } from "../packages/cli/src/recipe-sources.js" |
| 6 | +import { assertWorkspaceRecipeJsonSchema, type WorkspaceRecipe } from "../packages/runtime-core/src/index.js" |
| 7 | +import { withTempDir } from "../scripts/test-kit.js" |
| 8 | + |
| 9 | +async function pathExists(path: string): Promise<boolean> { |
| 10 | + try { |
| 11 | + await stat(path) |
| 12 | + return true |
| 13 | + } catch { |
| 14 | + return false |
| 15 | + } |
| 16 | +} |
| 17 | + |
| 18 | +await withTempDir("wp-codebox-composer-metadata-plugin-", async (recipeDirectory) => { |
| 19 | + const source = join(recipeDirectory, "shipped-plugin") |
| 20 | + await mkdir(source, { recursive: true }) |
| 21 | + await writeFile(join(source, "composer.json"), `${JSON.stringify({ name: "example/shipped-plugin", require: { "composer/installers": "^2" } }, null, 2)}\n`) |
| 22 | + await writeFile(join(source, "shipped-plugin.php"), "<?php\n/* Plugin Name: Shipped Plugin */\n") |
| 23 | + |
| 24 | + const recipe: WorkspaceRecipe = { |
| 25 | + schema: "wp-codebox/workspace-recipe/v1", |
| 26 | + inputs: { extra_plugins: [{ source: "shipped-plugin", slug: "shipped-plugin", pluginFile: "shipped-plugin/shipped-plugin.php" }] }, |
| 27 | + workflow: { steps: [{ command: "inspect-mounted-inputs" }] }, |
| 28 | + } |
| 29 | + |
| 30 | + assertWorkspaceRecipeJsonSchema(recipe) |
| 31 | + const [plugin] = await prepareRecipeExtraPlugins(recipe, recipeDirectory) |
| 32 | + assert.equal(plugin.source, source, "Composer metadata alone must not stage or prepare the plugin") |
| 33 | + assert.deepEqual(plugin.cleanupPaths, []) |
| 34 | + assert.equal(await pathExists(join(source, "vendor")), false, "the shipped plugin source must remain untouched") |
| 35 | +}) |
| 36 | + |
| 37 | +await withTempDir("wp-codebox-explicit-composer-plugin-", async (recipeDirectory) => { |
| 38 | + const source = join(recipeDirectory, "source-plugin") |
| 39 | + const bin = join(recipeDirectory, "bin") |
| 40 | + await mkdir(source, { recursive: true }) |
| 41 | + await mkdir(bin, { recursive: true }) |
| 42 | + await writeFile(join(source, "composer.json"), `${JSON.stringify({ name: "example/source-plugin", autoload: { classmap: ["src/"] } }, null, 2)}\n`) |
| 43 | + await writeFile(join(source, "source-plugin.php"), "<?php\n/* Plugin Name: Source Plugin */\n") |
| 44 | + const composer = join(bin, "composer") |
| 45 | + await writeFile(composer, "#!/bin/sh\nmkdir -p vendor/composer\nprintf '<?php\\n' > vendor/autoload.php\nprintf '[]\\n' > vendor/composer/installed.json\nprintf '<?php return array();\\n' > vendor/composer/autoload_classmap.php\n") |
| 46 | + await chmod(composer, 0o755) |
| 47 | + |
| 48 | + const recipe: WorkspaceRecipe = { |
| 49 | + schema: "wp-codebox/workspace-recipe/v1", |
| 50 | + inputs: { extra_plugins: [{ source: "source-plugin", slug: "source-plugin", pluginFile: "source-plugin/source-plugin.php", composer: "install" }] }, |
| 51 | + workflow: { steps: [{ command: "inspect-mounted-inputs" }] }, |
| 52 | + } |
| 53 | + |
| 54 | + assertWorkspaceRecipeJsonSchema(recipe) |
| 55 | + const originalPath = process.env.PATH |
| 56 | + process.env.PATH = `${bin}:${originalPath ?? ""}` |
| 57 | + let plugin: Awaited<ReturnType<typeof prepareRecipeExtraPlugins>>[number] | undefined |
| 58 | + try { |
| 59 | + ;[plugin] = await prepareRecipeExtraPlugins(recipe, recipeDirectory) |
| 60 | + } finally { |
| 61 | + process.env.PATH = originalPath |
| 62 | + } |
| 63 | + |
| 64 | + assert.ok(plugin) |
| 65 | + assert.notEqual(plugin.source, source, "explicit Composer preparation must use a staged copy") |
| 66 | + assert.equal(await pathExists(join(plugin.source, "vendor", "autoload.php")), true) |
| 67 | + assert.match(await readFile(join(plugin.source, "vendor", "autoload_packages.php"), "utf8"), /require_once __DIR__ \. '\/autoload\.php';/) |
| 68 | + assert.equal(await pathExists(join(source, "vendor")), false, "explicit preparation must not mutate the caller source") |
| 69 | + assert.equal(plugin.provenance.localPathCategory, "temporary-composer-autoload") |
| 70 | + await cleanupRecipePreparedSources([], [plugin]) |
| 71 | +}) |
| 72 | + |
| 73 | +console.log("recipe extra plugin Composer preparation ok") |
0 commit comments