Skip to content

Commit ce02838

Browse files
committed
Fix release artifact installability
1 parent 59fbf6e commit ce02838

5 files changed

Lines changed: 117 additions & 9 deletions

File tree

package-lock.json

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"packages/runtime-playground/package.json",
8080
"packages/cli/dist",
8181
"packages/cli/package.json",
82+
"scripts/apply-development-patches.mjs",
8283
"README.md",
8384
"LICENSE"
8485
],
@@ -88,7 +89,7 @@
8889
"cloudflare:dry-run:d1": "npm exec -- wrangler deploy --dry-run --config packages/runtime-cloudflare/wrangler.d1.jsonc",
8990
"cloudflare:local-gate": "node scripts/cloudflare-local-gate.mjs",
9091
"cloudflare:local-gate:d1": "node scripts/cloudflare-local-gate.mjs --coordinator=d1",
91-
"postinstall": "patch-package",
92+
"postinstall": "node scripts/apply-development-patches.mjs",
9293
"generate:cloudflare-wordpress-runtime-corpus": "tsx scripts/generate-cloudflare-wordpress-runtime-corpus.ts",
9394
"provision:cloudflare-wordpress-runtime-corpus": "node scripts/provision-cloudflare-wordpress-runtime-corpus.mjs",
9495
"prepare": "npm run build",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { execFileSync } from "node:child_process"
2+
import { existsSync } from "node:fs"
3+
import { resolve } from "node:path"
4+
5+
const patchPackageBin = resolve(import.meta.dirname, "..", "node_modules", "patch-package", "index.js")
6+
7+
if (existsSync(patchPackageBin)) {
8+
execFileSync(process.execPath, [patchPackageBin], { stdio: "inherit" })
9+
} else {
10+
process.stdout.write("Skipping development patches in the production package.\n")
11+
}

scripts/package-release-artifact.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ try {
4141
cwd: packageRoot,
4242
maxBuffer: 1024 * 1024 * 20,
4343
})
44+
await materializeWorkspacePackages(packageRoot)
4445
await bundleNodeRuntime(packageRoot, platformName, archName)
4546

4647
const binDir = join(packageRoot, "bin")
@@ -51,7 +52,7 @@ set -euo pipefail
5152
SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
5253
NODE_BIN="\${WP_CODEBOX_NODE_BIN:-}"
5354
if [ -z "\${NODE_BIN}" ]; then
54-
if [ -x "\${SCRIPT_DIR}/../vendor/node/bin/node" ]; then
55+
if [ -x "\${SCRIPT_DIR}/../vendor/node/bin/node" ] && "\${SCRIPT_DIR}/../vendor/node/bin/node" --version >/dev/null 2>&1; then
5556
NODE_BIN="\${SCRIPT_DIR}/../vendor/node/bin/node"
5657
elif command -v node >/dev/null 2>&1; then
5758
NODE_BIN="$(command -v node)"
@@ -101,6 +102,22 @@ async function copyIfPresent(relativePath: string): Promise<void> {
101102
}
102103
}
103104

105+
async function materializeWorkspacePackages(root: string): Promise<void> {
106+
const automatticModules = join(root, "node_modules", "@automattic")
107+
await mkdir(automatticModules, { recursive: true })
108+
109+
const packages = new Map([
110+
["runtime-core", "wp-codebox-core"],
111+
["runtime-playground", "wp-codebox-playground"],
112+
["cli", "wp-codebox-cli"],
113+
])
114+
for (const [sourceName, packageName] of packages) {
115+
const target = join(automatticModules, packageName)
116+
await rm(target, recursiveRmOptions)
117+
await cp(join(root, "packages", sourceName), target, { recursive: true, dereference: true })
118+
}
119+
}
120+
104121
async function bundleNodeRuntime(root: string, platformName: string, archName: string): Promise<void> {
105122
const nodePackageName = nodeRuntimePackageName(platformName, archName)
106123
const runtimeRoot = join(root, "vendor", "node")

tests/release-package-coverage.test.ts

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import assert from "node:assert/strict"
22
import { execFile } from "node:child_process"
3-
import { readFile } from "node:fs/promises"
4-
import { resolve } from "node:path"
3+
import { cp, lstat, mkdir, mkdtemp, readFile, rm } from "node:fs/promises"
4+
import { tmpdir } from "node:os"
5+
import { join, resolve } from "node:path"
56
import { promisify } from "node:util"
67

78
const execFileAsync = promisify(execFile)
@@ -19,6 +20,11 @@ assert.deepEqual(homeboy.release?.package_coverage, [{
1920

2021
const { stdout } = await execFileAsync("npm", ["run", "release:package"], {
2122
cwd: repositoryRoot,
23+
env: {
24+
...process.env,
25+
WP_CODEBOX_RELEASE_PLATFORM: "linux",
26+
WP_CODEBOX_RELEASE_ARCH: "x64",
27+
},
2228
maxBuffer: 1024 * 1024 * 20,
2329
})
2430
const artifacts = JSON.parse(stdout.trim().split("\n").at(-1) ?? "[]")
@@ -59,4 +65,77 @@ const { stdout: tarEntries } = await execFileAsync("tar", ["-tzf", cliArtifact.p
5965
})
6066
assert.ok(tarEntries.split("\n").some((path) => path === "wp-codebox-cli/"), "CLI tarball root changed")
6167

68+
const extractionRoot = await mkdtemp(join(tmpdir(), "wp-codebox-release-coverage-"))
69+
try {
70+
const pluginExtraction = join(extractionRoot, "plugin")
71+
const cliExtraction = join(extractionRoot, "cli")
72+
await mkdir(pluginExtraction, { recursive: true })
73+
await mkdir(cliExtraction, { recursive: true })
74+
await execFileAsync("unzip", ["-q", resolve(repositoryRoot, pluginArtifact), "-d", pluginExtraction])
75+
await execFileAsync("tar", ["-xzf", resolve(repositoryRoot, cliArtifact.path), "-C", cliExtraction])
76+
77+
const pluginCliRoot = join(pluginExtraction, "wp-codebox", "vendor", "wp-codebox-cli")
78+
const tarCliRoot = join(cliExtraction, "wp-codebox-cli")
79+
for (const root of [pluginCliRoot, tarCliRoot]) {
80+
for (const packageName of ["wp-codebox-cli", "wp-codebox-core", "wp-codebox-playground"]) {
81+
const packagePath = join(root, "node_modules", "@automattic", packageName)
82+
const packageStat = await lstat(packagePath)
83+
assert.equal(packageStat.isDirectory(), true, `${packagePath} must be a materialized directory`)
84+
assert.equal(packageStat.isSymbolicLink(), false, `${packagePath} must not depend on archive symlinks`)
85+
await lstat(join(packagePath, "package.json"))
86+
}
87+
88+
const cliEntrypoint = join(root, "packages", "cli", "dist", "index.js")
89+
const { stdout: version } = await execFileAsync(process.execPath, [cliEntrypoint, "--version"])
90+
assert.match(version, /^\d+\.\d+\.\d+\s*$/)
91+
await execFileAsync(process.execPath, [cliEntrypoint, "commands"])
92+
93+
const wrapper = join(root, "bin", "wp-codebox")
94+
const { stdout: wrapperVersion } = await execFileAsync(wrapper, ["--version"], {
95+
env: { ...process.env, WP_CODEBOX_NODE_BIN: "" },
96+
})
97+
assert.equal(wrapperVersion, version, "wrapper must fall back to host Node when bundled Node is incompatible")
98+
}
99+
} finally {
100+
await rm(extractionRoot, { recursive: true, force: true })
101+
}
102+
103+
const rootPackage = JSON.parse(await readFile(resolve(repositoryRoot, "package.json"), "utf8"))
104+
assert.equal(rootPackage.scripts.postinstall, "node scripts/apply-development-patches.mjs")
105+
assert.ok(rootPackage.files.includes("scripts/apply-development-patches.mjs"))
106+
107+
const lifecycleRoot = await mkdtemp(join(tmpdir(), "wp-codebox-production-lifecycle-"))
108+
try {
109+
const lifecycleScript = resolve(repositoryRoot, "scripts", "apply-development-patches.mjs")
110+
const packedLifecycleScript = join(lifecycleRoot, "scripts", "apply-development-patches.mjs")
111+
await mkdir(join(lifecycleRoot, "scripts"), { recursive: true })
112+
await cp(lifecycleScript, packedLifecycleScript)
113+
const { stdout: lifecycleOutput } = await execFileAsync(process.execPath, [packedLifecycleScript], { cwd: lifecycleRoot })
114+
assert.equal(lifecycleOutput, "Skipping development patches in the production package.\n")
115+
} finally {
116+
await rm(lifecycleRoot, { recursive: true, force: true })
117+
}
118+
119+
const consumerRoot = await mkdtemp(join(tmpdir(), "wp-codebox-consumer-install-"))
120+
try {
121+
const packRoot = join(consumerRoot, "pack")
122+
const installRoot = join(consumerRoot, "install")
123+
await mkdir(packRoot, { recursive: true })
124+
const { stdout: packOutput } = await execFileAsync("npm", ["pack", "--ignore-scripts", "--json", "--pack-destination", packRoot], {
125+
cwd: repositoryRoot,
126+
maxBuffer: 1024 * 1024 * 20,
127+
})
128+
const [packed] = JSON.parse(packOutput) as Array<{ filename: string }>
129+
await execFileAsync("npm", ["install", "--global", "--prefix", installRoot, join(packRoot, packed.filename), "--omit=dev", "--no-audit", "--no-fund"], {
130+
cwd: consumerRoot,
131+
maxBuffer: 1024 * 1024 * 20,
132+
})
133+
const installedCli = join(installRoot, "bin", "wp-codebox")
134+
const { stdout: installedVersion } = await execFileAsync(installedCli, ["--version"])
135+
assert.match(installedVersion, /^\d+\.\d+\.\d+\s*$/)
136+
await execFileAsync(installedCli, ["commands"])
137+
} finally {
138+
await rm(consumerRoot, { recursive: true, force: true })
139+
}
140+
62141
console.log("release package coverage passed")

0 commit comments

Comments
 (0)