Files
bun.sh/test/cli/install/bun-publish.test.ts

851 lines
28 KiB
TypeScript

import { file, spawn, write } from "bun";
import { afterAll, beforeAll, describe, expect, it, test } from "bun:test";
import { exists, rm } from "fs/promises";
import {
VerdaccioRegistry,
bunExe,
bunEnv as env,
isWindows,
pack,
runBunInstall,
stderrForInstall,
tmpdirSync,
} from "harness";
import { join } from "path";
const registry = new VerdaccioRegistry();
beforeAll(async () => {
await registry.start();
});
afterAll(() => {
registry.stop();
});
export async function publish(
env: any,
cwd: string,
...args: string[]
): Promise<{ out: string; err: string; exitCode: number }> {
const { stdout, stderr, exited } = spawn({
cmd: [bunExe(), "publish", ...args],
cwd,
stdout: "pipe",
stderr: "pipe",
env,
});
const out = await Bun.readableStreamToText(stdout);
const err = stderrForInstall(await Bun.readableStreamToText(stderr));
const exitCode = await exited;
return { out, err, exitCode };
}
describe("otp", async () => {
const mockRegistryFetch = function (opts: {
token: string;
setAuthHeader?: boolean;
otpFail?: boolean;
npmNotice?: boolean;
xLocalCache?: boolean;
expectedCI?: string;
}) {
return async function (req: Request) {
const { token, setAuthHeader = true, otpFail = false, npmNotice = false, xLocalCache = false } = opts;
if (req.url.includes("otp-pkg")) {
if (opts.expectedCI) {
expect(req.headers.get("user-agent")).toContain("ci/" + opts.expectedCI);
}
if (req.headers.get("npm-otp") === token) {
if (otpFail) {
return new Response(
JSON.stringify({
error: "You must provide a one-time pass. Upgrade your client to npm@latest in order to use 2FA.",
}),
{ status: 401 },
);
} else {
return new Response("OK", { status: 200 });
}
} else {
const headers = new Headers();
if (setAuthHeader) headers.set("www-authenticate", "OTP");
// `bun publish` won't request a url from a message in the npm-notice header, but we
// can test that it's displayed
if (npmNotice) headers.set("npm-notice", `visit http://localhost:${this.port}/auth to login`);
// npm-notice will be ignored
if (xLocalCache) headers.set("x-local-cache", "true");
return new Response(
JSON.stringify({
// this isn't accurate, but we just want to check that finding this string works
mock: setAuthHeader ? "" : "one-time password",
authUrl: `http://localhost:${this.port}/auth`,
doneUrl: `http://localhost:${this.port}/done`,
}),
{
status: 401,
headers,
},
);
}
} else if (req.url.endsWith("auth")) {
expect.unreachable("url given to user, bun publish should not request");
} else if (req.url.endsWith("done")) {
// send a fake response saying the user has authenticated successfully with the auth url
return new Response(JSON.stringify({ token: token }), { status: 200 });
}
expect.unreachable("unexpected url");
};
};
for (const setAuthHeader of [true, false]) {
test("mock web login" + (setAuthHeader ? "" : " (without auth header)"), async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const token = await registry.generateUser("otp" + (setAuthHeader ? "" : "noheader"), "otp");
using mockRegistry = Bun.serve({
port: 0,
fetch: mockRegistryFetch({ token }),
});
const bunfig = `
[install]
cache = false
registry = { url = "http://localhost:${mockRegistry.port}", token = "${token}" }`;
await Promise.all([
rm(join(registry.packagesPath, "otp-pkg-1"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "otp-pkg-1",
version: "2.2.2",
dependencies: {
"otp-pkg-1": "2.2.2",
},
}),
),
]);
const { out, err, exitCode } = await publish(env, packageDir);
expect(exitCode).toBe(0);
});
}
test("otp failure", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const token = await registry.generateUser("otp-fail", "otp");
using mockRegistry = Bun.serve({
port: 0,
fetch: mockRegistryFetch({ token, otpFail: true }),
});
const bunfig = `
[install]
cache = false
registry = { url = "http://localhost:${mockRegistry.port}", token = "${token}" }`;
await Promise.all([
rm(join(registry.packagesPath, "otp-pkg-2"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "otp-pkg-2",
version: "1.1.1",
dependencies: {
"otp-pkg-2": "1.1.1",
},
}),
),
]);
const { out, err, exitCode } = await publish(env, packageDir);
expect(exitCode).toBe(1);
expect(err).toContain(" - Received invalid OTP");
});
for (const shouldIgnoreNotice of [false, true]) {
test(`npm-notice with login url${shouldIgnoreNotice ? " (ignored)" : ""}`, async () => {
const { packageDir, packageJson } = await registry.createTestDir();
// Situation: user has 2FA enabled account with faceid sign-in.
// They run `bun publish` with --auth-type=legacy, prompting them
// to enter their OTP. Because they have faceid sign-in, they don't
// have a code to enter, so npm sends a message in the npm-notice
// header with a url for logging in.
const token = await registry.generateUser(`otp-notice${shouldIgnoreNotice ? "-ignore" : ""}`, "otp");
using mockRegistry = Bun.serve({
port: 0,
fetch: mockRegistryFetch({ token, npmNotice: true, xLocalCache: shouldIgnoreNotice }),
});
const bunfig = `
[install]
cache = false
registry = { url = "http://localhost:${mockRegistry.port}", token = "${token}" }`;
await Promise.all([
rm(join(registry.packagesPath, "otp-pkg-3"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "otp-pkg-3",
version: "3.3.3",
dependencies: {
"otp-pkg-3": "3.3.3",
},
}),
),
]);
const { out, err, exitCode } = await publish(env, packageDir);
expect(exitCode).toBe(0);
if (shouldIgnoreNotice) {
expect(err).not.toContain(`note: visit http://localhost:${mockRegistry.port}/auth to login`);
} else {
expect(err).toContain(`note: visit http://localhost:${mockRegistry.port}/auth to login`);
}
});
}
const fakeCIEnvs = [
{ ci: "expo-application-services", envs: { EAS_BUILD: "hi" } },
{ ci: "codemagic", envs: { CM_BUILD_ID: "hi" } },
{ ci: "vercel", envs: { "NOW_BUILDER": "hi" } },
];
for (const envInfo of fakeCIEnvs) {
test(`CI user agent name: ${envInfo.ci}`, async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const token = await registry.generateUser(`otp-${envInfo.ci}`, "otp");
using mockRegistry = Bun.serve({
port: 0,
fetch: mockRegistryFetch({ token, expectedCI: envInfo.ci }),
});
const bunfig = `
[install]
cache = false
registry = { url = "http://localhost:${mockRegistry.port}", token = "${token}" }`;
await Promise.all([
rm(join(registry.packagesPath, "otp-pkg-4"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "otp-pkg-4",
version: "4.4.4",
dependencies: {
"otp-pkg-4": "4.4.4",
},
}),
),
]);
const { out, err, exitCode } = await publish(
{ ...env, ...envInfo.envs, ...{ BUILDKITE: undefined, GITHUB_ACTIONS: undefined } },
packageDir,
);
expect(exitCode).toBe(0);
});
}
});
test("can publish a package then install it", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("basic");
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-1"), { recursive: true, force: true }),
write(
packageJson,
JSON.stringify({
name: "publish-pkg-1",
version: "1.1.1",
dependencies: {
"publish-pkg-1": "1.1.1",
},
}),
),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
const { out, err, exitCode } = await publish(env, packageDir);
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
expect(await exists(join(packageDir, "node_modules", "publish-pkg-1", "package.json"))).toBeTrue();
});
test("can publish from a tarball", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("tarball");
const json = {
name: "publish-pkg-2",
version: "2.2.2",
dependencies: {
"publish-pkg-2": "2.2.2",
},
};
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-2"), { recursive: true, force: true }),
write(packageJson, JSON.stringify(json)),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
await pack(packageDir, env);
let { out, err, exitCode } = await publish(env, packageDir, "./publish-pkg-2-2.2.2.tgz");
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
expect(await exists(join(packageDir, "node_modules", "publish-pkg-2", "package.json"))).toBeTrue();
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-2"), { recursive: true, force: true }),
rm(join(packageDir, "bun.lockb"), { recursive: true, force: true }),
rm(join(packageDir, "node_modules"), { recursive: true, force: true }),
]);
// now with an absoute path
({ out, err, exitCode } = await publish(env, packageDir, join(packageDir, "publish-pkg-2-2.2.2.tgz")));
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir, { savesLockfile: false });
expect(await file(join(packageDir, "node_modules", "publish-pkg-2", "package.json")).json()).toEqual(json);
});
test("can publish scoped packages", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("scoped-pkg");
const json = {
name: "@scoped/pkg-1",
version: "1.1.1",
dependencies: {
"@scoped/pkg-1": "1.1.1",
},
};
await Promise.all([
rm(join(registry.packagesPath, "@scoped", "pkg-1"), { recursive: true, force: true }),
write(packageJson, JSON.stringify(json)),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
const { out, err, exitCode } = await publish(env, packageDir);
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
expect(await file(join(packageDir, "node_modules", "@scoped", "pkg-1", "package.json")).json()).toEqual(json);
});
for (const info of [
{ user: "bin1", bin: "bin1.js" },
{ user: "bin2", bin: { bin1: "bin1.js", bin2: "bin2.js" } },
{ user: "bin3", directories: { bin: "bins" } },
]) {
test(`can publish and install binaries with ${JSON.stringify(info)}`, async () => {
const { packageDir, packageJson } = await registry.createTestDir({ saveTextLockfile: false });
const publishDir = tmpdirSync();
const bunfig = await registry.authBunfig("binaries-" + info.user);
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-" + info.user), { recursive: true, force: true }),
write(
join(publishDir, "package.json"),
JSON.stringify({
name: "publish-pkg-" + info.user,
version: "1.1.1",
...info,
}),
),
write(join(publishDir, "bunfig.toml"), bunfig),
write(join(publishDir, "bin1.js"), `#!/usr/bin/env bun\nconsole.log("bin1!")`),
write(join(publishDir, "bin2.js"), `#!/usr/bin/env bun\nconsole.log("bin2!")`),
write(join(publishDir, "bins", "bin3.js"), `#!/usr/bin/env bun\nconsole.log("bin3!")`),
write(join(publishDir, "bins", "moredir", "bin4.js"), `#!/usr/bin/env bun\nconsole.log("bin4!")`),
write(
packageJson,
JSON.stringify({
name: "foo",
dependencies: {
["publish-pkg-" + info.user]: "1.1.1",
},
}),
),
]);
const { out, err, exitCode } = await publish(env, publishDir);
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(out).toContain(`+ publish-pkg-${info.user}@1.1.1`);
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
const results = await Promise.all([
exists(join(packageDir, "node_modules", ".bin", isWindows ? "bin1.bunx" : "bin1")),
exists(join(packageDir, "node_modules", ".bin", isWindows ? "bin2.bunx" : "bin2")),
exists(join(packageDir, "node_modules", ".bin", isWindows ? "bin3.js.bunx" : "bin3.js")),
exists(join(packageDir, "node_modules", ".bin", isWindows ? "bin4.js.bunx" : "bin4.js")),
exists(join(packageDir, "node_modules", ".bin", isWindows ? "moredir" : "moredir/bin4.js")),
exists(
join(
packageDir,
"node_modules",
".bin",
isWindows ? `publish-pkg-${info.user}.bunx` : "publish-pkg-" + info.user,
),
),
]);
switch (info.user) {
case "bin1": {
expect(results).toEqual([false, false, false, false, false, true]);
break;
}
case "bin2": {
expect(results).toEqual([true, true, false, false, false, false]);
break;
}
case "bin3": {
expect(results).toEqual([false, false, true, true, !isWindows, false]);
break;
}
}
});
}
test("dependencies are installed", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const publishDir = tmpdirSync();
const bunfig = await registry.authBunfig("manydeps");
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-deps"), { recursive: true, force: true }),
write(
join(publishDir, "package.json"),
JSON.stringify(
{
name: "publish-pkg-deps",
version: "1.1.1",
dependencies: {
"no-deps": "1.0.0",
},
peerDependencies: {
"a-dep": "1.0.1",
},
optionalDependencies: {
"basic-1": "1.0.0",
},
},
null,
2,
),
),
write(join(publishDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "foo",
dependencies: {
"publish-pkg-deps": "1.1.1",
},
}),
),
]);
let { out, err, exitCode } = await publish(env, publishDir);
expect(err).not.toContain("error:");
expect(err).not.toContain("warn:");
expect(out).toContain("+ publish-pkg-deps@1.1.1");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
const results = await Promise.all([
exists(join(packageDir, "node_modules", "no-deps", "package.json")),
exists(join(packageDir, "node_modules", "a-dep", "package.json")),
exists(join(packageDir, "node_modules", "basic-1", "package.json")),
]);
expect(results).toEqual([true, true, true]);
});
test("can publish workspace package", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("workspace");
const pkgJson = {
name: "publish-pkg-3",
version: "3.3.3",
dependencies: {
"publish-pkg-3": "3.3.3",
},
};
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-3"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "root",
workspaces: ["packages/*"],
}),
),
write(join(packageDir, "packages", "publish-pkg-3", "package.json"), JSON.stringify(pkgJson)),
]);
await publish(env, join(packageDir, "packages", "publish-pkg-3"));
await write(packageJson, JSON.stringify({ name: "root", "dependencies": { "publish-pkg-3": "3.3.3" } }));
await runBunInstall(env, packageDir);
expect(await file(join(packageDir, "node_modules", "publish-pkg-3", "package.json")).json()).toEqual(pkgJson);
});
describe("--dry-run", async () => {
test("does not publish", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("dryrun");
await Promise.all([
rm(join(registry.packagesPath, "dry-run-1"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "dry-run-1",
version: "1.1.1",
dependencies: {
"dry-run-1": "1.1.1",
},
}),
),
]);
const { out, err, exitCode } = await publish(env, packageDir, "--dry-run");
expect(exitCode).toBe(0);
expect(await exists(join(registry.packagesPath, "dry-run-1"))).toBeFalse();
});
test("does not publish from tarball path", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("dryruntarball");
await Promise.all([
rm(join(registry.packagesPath, "dry-run-2"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "dry-run-2",
version: "2.2.2",
dependencies: {
"dry-run-2": "2.2.2",
},
}),
),
]);
await pack(packageDir, env);
const { out, err, exitCode } = await publish(env, packageDir, "./dry-run-2-2.2.2.tgz", "--dry-run");
expect(exitCode).toBe(0);
expect(await exists(join(registry.packagesPath, "dry-run-2"))).toBeFalse();
});
});
describe("lifecycle scripts", async () => {
const script = `const fs = require("fs");
fs.writeFileSync(process.argv[2] + ".txt", \`
prepublishOnly: \${fs.existsSync("prepublishOnly.txt")}
publish: \${fs.existsSync("publish.txt")}
postpublish: \${fs.existsSync("postpublish.txt")}
prepack: \${fs.existsSync("prepack.txt")}
prepare: \${fs.existsSync("prepare.txt")}
postpack: \${fs.existsSync("postpack.txt")}\`)`;
const json = {
name: "publish-pkg-4",
version: "4.4.4",
scripts: {
// should happen in this order
"prepublishOnly": `${bunExe()} script.js prepublishOnly`,
"prepack": `${bunExe()} script.js prepack`,
"prepare": `${bunExe()} script.js prepare`,
"postpack": `${bunExe()} script.js postpack`,
"publish": `${bunExe()} script.js publish`,
"postpublish": `${bunExe()} script.js postpublish`,
},
dependencies: {
"publish-pkg-4": "4.4.4",
},
};
for (const arg of [[], ["--dry-run"]]) {
test(`should run in order${arg.length > 0 ? " (--dry-run)" : ""}`, async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("lifecycle" + (arg.length > 0 ? "dry" : ""));
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-4"), { recursive: true, force: true }),
write(packageJson, JSON.stringify(json)),
write(join(packageDir, "script.js"), script),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
const { out, err, exitCode } = await publish(env, packageDir, ...arg);
expect(exitCode).toBe(0);
const results = await Promise.all([
file(join(packageDir, "prepublishOnly.txt")).text(),
file(join(packageDir, "prepack.txt")).text(),
file(join(packageDir, "prepare.txt")).text(),
file(join(packageDir, "postpack.txt")).text(),
file(join(packageDir, "publish.txt")).text(),
file(join(packageDir, "postpublish.txt")).text(),
]);
expect(results).toEqual([
"\nprepublishOnly: false\npublish: false\npostpublish: false\nprepack: false\nprepare: false\npostpack: false",
"\nprepublishOnly: true\npublish: false\npostpublish: false\nprepack: false\nprepare: false\npostpack: false",
"\nprepublishOnly: true\npublish: false\npostpublish: false\nprepack: true\nprepare: false\npostpack: false",
"\nprepublishOnly: true\npublish: false\npostpublish: false\nprepack: true\nprepare: true\npostpack: false",
"\nprepublishOnly: true\npublish: false\npostpublish: false\nprepack: true\nprepare: true\npostpack: true",
"\nprepublishOnly: true\npublish: true\npostpublish: false\nprepack: true\nprepare: true\npostpack: true",
]);
});
}
test("--ignore-scripts", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("ignorescripts");
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-5"), { recursive: true, force: true }),
write(packageJson, JSON.stringify(json)),
write(join(packageDir, "script.js"), script),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
const { out, err, exitCode } = await publish(env, packageDir, "--ignore-scripts");
expect(exitCode).toBe(0);
const results = await Promise.all([
exists(join(packageDir, "prepublishOnly.txt")),
exists(join(packageDir, "prepack.txt")),
exists(join(packageDir, "prepare.txt")),
exists(join(packageDir, "postpack.txt")),
exists(join(packageDir, "publish.txt")),
exists(join(packageDir, "postpublish.txt")),
]);
expect(results).toEqual([false, false, false, false, false, false]);
});
});
test("attempting to publish a private package should fail", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("privatepackage");
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-6"), { recursive: true, force: true }),
write(
packageJson,
JSON.stringify({
name: "publish-pkg-6",
version: "6.6.6",
private: true,
dependencies: {
"publish-pkg-6": "6.6.6",
},
}),
),
write(join(packageDir, "bunfig.toml"), bunfig),
]);
// should fail
let { out, err, exitCode } = await publish(env, packageDir);
expect(exitCode).toBe(1);
expect(err).toContain("error: attempted to publish a private package");
expect(await exists(join(registry.packagesPath, "publish-pkg-6-6.6.6.tgz"))).toBeFalse();
// try tarball
await pack(packageDir, env);
({ out, err, exitCode } = await publish(env, packageDir, "./publish-pkg-6-6.6.6.tgz"));
expect(exitCode).toBe(1);
expect(err).toContain("error: attempted to publish a private package");
expect(await exists(join(packageDir, "publish-pkg-6-6.6.6.tgz"))).toBeTrue();
});
describe("access", async () => {
test("--access", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("accessflag");
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-7"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(
packageJson,
JSON.stringify({
name: "publish-pkg-7",
version: "7.7.7",
}),
),
]);
// should fail
let { out, err, exitCode } = await publish(env, packageDir, "--access", "restricted");
expect(exitCode).toBe(1);
expect(err).toContain("error: unable to restrict access to unscoped package");
({ out, err, exitCode } = await publish(env, packageDir, "--access", "public"));
expect(exitCode).toBe(0);
expect(await exists(join(registry.packagesPath, "publish-pkg-7"))).toBeTrue();
});
for (const access of ["restricted", "public"]) {
test(`access ${access}`, async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("access" + access);
const pkgJson = {
name: "@secret/publish-pkg-8",
version: "8.8.8",
dependencies: {
"@secret/publish-pkg-8": "8.8.8",
},
publishConfig: {
access,
},
};
await Promise.all([
rm(join(registry.packagesPath, "@secret", "publish-pkg-8"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(packageJson, JSON.stringify(pkgJson)),
]);
let { out, err, exitCode } = await publish(env, packageDir);
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
expect(await file(join(packageDir, "node_modules", "@secret", "publish-pkg-8", "package.json")).json()).toEqual(
pkgJson,
);
});
}
});
describe("tag", async () => {
test("can publish with a tag", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
const bunfig = await registry.authBunfig("simpletag");
const pkgJson = {
name: "publish-pkg-9",
version: "9.9.9",
dependencies: {
"publish-pkg-9": "simpletag",
},
};
await Promise.all([
rm(join(registry.packagesPath, "publish-pkg-9"), { recursive: true, force: true }),
write(join(packageDir, "bunfig.toml"), bunfig),
write(packageJson, JSON.stringify(pkgJson)),
]);
let { out, err, exitCode } = await publish(env, packageDir, "--tag", "simpletag");
expect(exitCode).toBe(0);
await runBunInstall(env, packageDir);
expect(await file(join(packageDir, "node_modules", "publish-pkg-9", "package.json")).json()).toEqual(pkgJson);
});
});
it("$npm_command is accurate during publish", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
await write(
packageJson,
JSON.stringify({
name: "publish-pkg-10",
version: "1.0.0",
scripts: {
publish: "echo $npm_command",
},
}),
);
await write(join(packageDir, "bunfig.toml"), await registry.authBunfig("npm_command"));
await rm(join(registry.packagesPath, "publish-pkg-10"), { recursive: true, force: true });
let { out, err, exitCode } = await publish(env, packageDir, "--tag", "simpletag");
expect(err).toBe(`$ echo $npm_command\n`);
expect(out.split("\n")).toEqual([
`bun publish ${Bun.version_with_sha}`,
``,
`packed 95B package.json`,
``,
`Total files: 1`,
expect.stringContaining(`Shasum: `),
expect.stringContaining(`Integrity: sha512-`),
`Unpacked size: 95B`,
expect.stringContaining(`Packed size: `),
`Tag: simpletag`,
`Access: default`,
`Registry: http://localhost:${registry.port}/`,
``,
` + publish-pkg-10@1.0.0`,
`publish`,
``,
]);
expect(exitCode).toBe(0);
});
it("$npm_lifecycle_event is accurate during publish", async () => {
const { packageDir, packageJson } = await registry.createTestDir();
await write(
packageJson,
`{
"name": "publish-pkg-11",
"version": "1.0.0",
"scripts": {
"prepublish": "echo 1 $npm_lifecycle_event",
"publish": "echo 2 $npm_lifecycle_event",
"postpublish": "echo 3 $npm_lifecycle_event",
},
}
`,
);
await write(join(packageDir, "bunfig.toml"), await registry.authBunfig("npm_lifecycle_event"));
await rm(join(registry.packagesPath, "publish-pkg-11"), { recursive: true, force: true });
let { out, err, exitCode } = await publish(env, packageDir, "--tag", "simpletag");
expect(err).toBe(`$ echo 2 $npm_lifecycle_event\n$ echo 3 $npm_lifecycle_event\n`);
expect(out.split("\n")).toEqual([
`bun publish ${Bun.version_with_sha}`,
``,
`packed 256B package.json`,
``,
`Total files: 1`,
expect.stringContaining(`Shasum: `),
expect.stringContaining(`Integrity: sha512-`),
`Unpacked size: 256B`,
expect.stringContaining(`Packed size: `),
`Tag: simpletag`,
`Access: default`,
`Registry: http://localhost:${registry.port}/`,
``,
` + publish-pkg-11@1.0.0`,
`2 publish`,
`3 postpublish`,
``,
]);
expect(exitCode).toBe(0);
});