mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
## Summary - Fixes `bun pm pack` not respecting changes to `package.json` made by prepack/prepare scripts - Tracks whether lifecycle scripts (prepublishOnly, prepack, prepare) ran - If scripts ran, invalidates the cached package.json and re-reads from disk before creating the tarball Closes #24314 ## Test plan - Added regression test `test/regression/issue/24314.test.ts` that verifies package.json modifications from prepack/prepare scripts are included in the tarball - All existing pack tests pass (69 tests) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
116 lines
3.6 KiB
TypeScript
116 lines
3.6 KiB
TypeScript
import { readTarball } from "bun:internal-for-testing";
|
|
import { expect, test } from "bun:test";
|
|
import { bunEnv, bunExe, tempDir } from "harness";
|
|
import path from "node:path";
|
|
|
|
// Helper to normalize path separators for cross-platform tarball entry lookup
|
|
function normalizePath(p: string): string {
|
|
return p.replace(/\\/g, "/");
|
|
}
|
|
|
|
test("bun pm pack respects changes to package.json from prepack scripts", async () => {
|
|
using dir = tempDir("pack-prepack", {
|
|
"package.json": JSON.stringify(
|
|
{
|
|
name: "test-prepack",
|
|
version: "1.0.0",
|
|
scripts: {
|
|
prepack: "node prepack.js",
|
|
},
|
|
description: "ORIGINAL DESCRIPTION",
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
"prepack.js": `
|
|
const fs = require('fs');
|
|
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
pkg.description = 'MODIFIED BY PREPACK';
|
|
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
|
|
`,
|
|
});
|
|
|
|
await using proc = Bun.spawn({
|
|
cmd: [bunExe(), "pm", "pack"],
|
|
cwd: String(dir),
|
|
env: bunEnv,
|
|
stderr: "pipe",
|
|
stdout: "pipe",
|
|
});
|
|
|
|
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
|
|
|
// Check stdout/stderr first to provide context on failure
|
|
expect(stderr).not.toContain("error");
|
|
expect(stdout).toContain("test-prepack-1.0.0.tgz");
|
|
expect(exitCode).toBe(0);
|
|
|
|
// Read the tarball and check the package.json inside
|
|
const tarballPath = path.join(String(dir), "test-prepack-1.0.0.tgz");
|
|
const tarball = readTarball(tarballPath);
|
|
|
|
// Find the package.json entry (normalize path separators for Windows)
|
|
const pkgJsonEntry = tarball.entries.find(
|
|
(e: { pathname: string }) => normalizePath(e.pathname) === "package/package.json",
|
|
);
|
|
expect(pkgJsonEntry).toBeDefined();
|
|
|
|
const extractedPkg = JSON.parse(pkgJsonEntry.contents);
|
|
|
|
// The description should be modified by the prepack script
|
|
expect(extractedPkg.description).toBe("MODIFIED BY PREPACK");
|
|
});
|
|
|
|
test("bun pm pack respects changes to package.json from prepare scripts", async () => {
|
|
using dir = tempDir("pack-prepare", {
|
|
"package.json": JSON.stringify(
|
|
{
|
|
name: "test-prepare",
|
|
version: "1.0.0",
|
|
scripts: {
|
|
prepare: "node prepare.js",
|
|
},
|
|
keywords: ["original"],
|
|
},
|
|
null,
|
|
2,
|
|
),
|
|
"prepare.js": `
|
|
const fs = require('fs');
|
|
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
pkg.keywords = ['modified', 'by', 'prepare'];
|
|
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
|
|
`,
|
|
});
|
|
|
|
await using proc = Bun.spawn({
|
|
cmd: [bunExe(), "pm", "pack"],
|
|
cwd: String(dir),
|
|
env: bunEnv,
|
|
stderr: "pipe",
|
|
stdout: "pipe",
|
|
});
|
|
|
|
const [stdout, stderr, exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]);
|
|
|
|
// Check stdout/stderr first to provide context on failure
|
|
expect(stderr).not.toContain("error");
|
|
expect(stdout).toContain("test-prepare-1.0.0.tgz");
|
|
expect(exitCode).toBe(0);
|
|
|
|
// Read the tarball and check the package.json inside
|
|
const tarballPath = path.join(String(dir), "test-prepare-1.0.0.tgz");
|
|
const tarball = readTarball(tarballPath);
|
|
|
|
// Find the package.json entry (normalize path separators for Windows)
|
|
const pkgJsonEntry = tarball.entries.find(
|
|
(e: { pathname: string }) => normalizePath(e.pathname) === "package/package.json",
|
|
);
|
|
expect(pkgJsonEntry).toBeDefined();
|
|
|
|
const extractedPkg = JSON.parse(pkgJsonEntry.contents);
|
|
|
|
// The keywords should be modified by the prepare script
|
|
expect(extractedPkg.keywords).toEqual(["modified", "by", "prepare"]);
|
|
});
|