Skip to content

Commit

Permalink
feat(deps): execa@^4.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
evocateur committed Nov 17, 2020
1 parent 2f6f4e0 commit 9051dca
Show file tree
Hide file tree
Showing 41 changed files with 628 additions and 604 deletions.
7 changes: 5 additions & 2 deletions commands/create/__tests__/create-command.test.js
Expand Up @@ -24,13 +24,16 @@ expect.addSnapshotSerializer(require("@lerna-test/serialize-git-sha"));
const addRemote = (cwd, remote = "origin", url = "git@github.com:test/test.git") =>
execa("git", ["remote", "add", remote, url], { cwd });

const diffStaged = (cwd, ...args) => execa.stdout("git", ["diff", "--cached", ...args], { cwd });
const diffStaged = (cwd, ...args) =>
execa("git", ["diff", "--cached", ...args], { cwd }).then((result) => result.stdout);

const initRemoteFixture = (fixtureName) =>
initFixture(fixtureName).then((cwd) => addRemote(cwd).then(() => cwd));

const gitLsOthers = (cwd, ...args) =>
execa.stdout("git", ["ls-files", "--others", "--exclude-standard", ...args], { cwd });
execa("git", ["ls-files", "--others", "--exclude-standard", ...args], { cwd }).then(
(result) => result.stdout
);

const listUntracked = async (cwd) => {
const list = await gitLsOthers(cwd, "-z");
Expand Down
2 changes: 1 addition & 1 deletion commands/diff/__tests__/diff-command.test.js
Expand Up @@ -104,7 +104,7 @@ describe("DiffCommand", () => {

ChildProcessUtilities.spawn.mockImplementationOnce(() => {
const nonZero = new Error("An actual non-zero, not git diff pager SIGPIPE");
nonZero.code = 1;
nonZero.exitCode = 1;

throw nonZero;
});
Expand Down
2 changes: 1 addition & 1 deletion commands/diff/index.js
Expand Up @@ -50,7 +50,7 @@ class DiffCommand extends Command {

execute() {
return ChildProcessUtilities.spawn("git", this.args, this.execOpts).catch((err) => {
if (err.code) {
if (err.exitCode) {
// quitting the diff viewer is not an error
throw err;
}
Expand Down
12 changes: 6 additions & 6 deletions commands/exec/__tests__/exec-command.test.js
Expand Up @@ -28,8 +28,8 @@ const execInPackagesStreaming = (testDir) =>

describe("ExecCommand", () => {
// TODO: it's very suspicious that mockResolvedValue() doesn't work here
ChildProcessUtilities.spawn = jest.fn(() => Promise.resolve({ code: 0 }));
ChildProcessUtilities.spawnStreaming = jest.fn(() => Promise.resolve({ code: 0 }));
ChildProcessUtilities.spawn = jest.fn(() => Promise.resolve({ exitCode: 0 }));
ChildProcessUtilities.spawnStreaming = jest.fn(() => Promise.resolve({ exitCode: 0 }));

afterEach(() => {
process.exitCode = undefined;
Expand All @@ -54,8 +54,8 @@ describe("ExecCommand", () => {
const boom = new Error("execution error");

boom.failed = true;
boom.code = 123;
boom.cmd = [cmd].concat(args).join(" ");
boom.exitCode = 123;
boom.command = [cmd].concat(args).join(" ");

throw boom;
});
Expand All @@ -65,7 +65,7 @@ describe("ExecCommand", () => {
await expect(command).rejects.toThrow(
expect.objectContaining({
message: "execution error",
cmd: "boom",
command: "boom",
})
);
expect(process.exitCode).toBe(123);
Expand All @@ -76,7 +76,7 @@ describe("ExecCommand", () => {
const boom = new Error(pkg.name);

boom.failed = true;
boom.code = 456;
boom.exitCode = 456;
boom.cmd = [cmd].concat(args).join(" ");

// --no-bail passes { reject: false } to execa, so throwing is inappropriate
Expand Down
4 changes: 2 additions & 2 deletions commands/exec/index.js
Expand Up @@ -74,7 +74,7 @@ class ExecCommand extends Command {
if (this.bail) {
// only the first error is caught
chain = chain.catch((err) => {
process.exitCode = err.code;
process.exitCode = err.exitCode;

// rethrow to halt chain and log properly
throw err;
Expand All @@ -85,7 +85,7 @@ class ExecCommand extends Command {
/* istanbul ignore else */
if (results.some((result) => result.failed)) {
// propagate "highest" error code, it's probably the most useful
const codes = results.filter((result) => result.failed).map((result) => result.code);
const codes = results.filter((result) => result.failed).map((result) => result.exitCode);
const exitCode = Math.max(...codes, 1);

this.logger.error("", "Received non-zero exit code %d during execution", exitCode);
Expand Down
3 changes: 2 additions & 1 deletion commands/import/__tests__/import-command.test.js
Expand Up @@ -21,7 +21,8 @@ const updateLernaConfig = require("@lerna-test/update-lerna-config");
const lernaImport = require("@lerna-test/command-runner")(require("../command"));

// assertion helpers
const lastCommitInDir = (cwd) => execa.stdout("git", ["log", "-1", "--format=%s"], { cwd });
const lastCommitInDir = (cwd) =>
execa("git", ["log", "-1", "--format=%s"], { cwd }).then((result) => result.stdout);

describe("ImportCommand", () => {
PromptUtilities.confirm.mockResolvedValue(true);
Expand Down
4 changes: 2 additions & 2 deletions commands/publish/__tests__/git-checkout.test.js
Expand Up @@ -13,7 +13,7 @@ test("gitCheckout files", async () => {
await Promise.all(files.map((fp) => fs.writeJSON(path.join(cwd, fp), { foo: "bar" })));
await gitCheckout(files, { granularPathspec: true }, { cwd });

const modified = await execa.stdout("git", ["ls-files", "--modified"], { cwd });
const { stdout: modified } = await execa("git", ["ls-files", "--modified"], { cwd });
expect(modified).toBe("");
});

Expand All @@ -29,6 +29,6 @@ test("gitCheckout files with .gitignored files", async () => {
await Promise.all(files.map((fp) => fs.outputJSON(path.join(cwd, fp), { foo: "bar" })));
await gitCheckout(files, { granularPathspec: false }, { cwd });

const modified = await execa.stdout("git", ["ls-files", "--others"], { cwd });
const { stdout: modified } = await execa("git", ["ls-files", "--others"], { cwd });
expect(modified).toBe("packages/package-3/package.json");
});
2 changes: 1 addition & 1 deletion commands/publish/index.js
Expand Up @@ -296,7 +296,7 @@ class PublishCommand extends Command {
.then(() => this.verifyWorkingTreeClean())
.catch((err) => {
// an execa error is thrown when git suffers a fatal error (such as no git repository present)
if (err.failed && /git describe/.test(err.cmd)) {
if (err.failed && /git describe/.test(err.command)) {
// (we tried)
this.logger.silly("EWORKINGTREE", err.message);
this.logger.notice("FYI", "Unable to verify working tree, proceed at your own risk");
Expand Down
8 changes: 4 additions & 4 deletions commands/run/__tests__/run-command.test.js
Expand Up @@ -27,8 +27,8 @@ const ranInPackagesStreaming = (testDir) =>
}, []);

describe("RunCommand", () => {
npmRunScript.mockImplementation((script, { pkg }) => Promise.resolve({ code: 0, stdout: pkg.name }));
npmRunScript.stream.mockImplementation(() => Promise.resolve({ code: 0 }));
npmRunScript.mockImplementation((script, { pkg }) => Promise.resolve({ exitCode: 0, stdout: pkg.name }));
npmRunScript.stream.mockImplementation(() => Promise.resolve({ exitCode: 0 }));

afterEach(() => {
process.exitCode = undefined;
Expand Down Expand Up @@ -117,7 +117,7 @@ describe("RunCommand", () => {
const err = new Error(pkg.name);

err.failed = true;
err.code = 123;
err.exitCode = 123;

return Promise.reject(err);
});
Expand All @@ -133,7 +133,7 @@ describe("RunCommand", () => {
const err = new Error(pkg.name);

err.failed = true;
err.code = 456;
err.exitCode = 456;
err.stdout = pkg.name;

return Promise.resolve(err);
Expand Down
4 changes: 2 additions & 2 deletions commands/run/index.js
Expand Up @@ -84,7 +84,7 @@ class RunCommand extends Command {
if (this.bail) {
// only the first error is caught
chain = chain.catch((err) => {
process.exitCode = err.code;
process.exitCode = err.exitCode;

// rethrow to halt chain and log properly
throw err;
Expand All @@ -95,7 +95,7 @@ class RunCommand extends Command {
/* istanbul ignore else */
if (results.some((result) => result.failed)) {
// propagate "highest" error code, it's probably the most useful
const codes = results.filter((result) => result.failed).map((result) => result.code);
const codes = results.filter((result) => result.failed).map((result) => result.exitCode);
const exitCode = Math.max(...codes, 1);

this.logger.error("", "Received non-zero exit code %d during execution", exitCode);
Expand Down
2 changes: 1 addition & 1 deletion commands/version/__tests__/get-current-branch.test.js
Expand Up @@ -12,5 +12,5 @@ test("getCurrentBranch", async () => {
test("getCurrentBranch without commit", async () => {
const cwd = await initFixture("root-manifest-only", false);

expect(() => getCurrentBranch({ cwd })).toThrow(/Command failed: git rev-parse --abbrev-ref HEAD.*/);
expect(() => getCurrentBranch({ cwd })).toThrow(/Command failed.*: git rev-parse --abbrev-ref HEAD.*/);
});
15 changes: 7 additions & 8 deletions commands/version/__tests__/git-add.test.js
Expand Up @@ -7,15 +7,17 @@ const slash = require("slash");
const initFixture = require("@lerna-test/init-fixture")(__dirname);
const gitAdd = require("../lib/git-add");

const getStagedFile = async (cwd) =>
execa("git", ["diff", "--cached", "--name-only"], { cwd }).then((result) => slash(result.stdout));

test("relative files", async () => {
const cwd = await initFixture("root-manifest-only");
const file = path.join("packages", "pkg-1", "index.js");

await fs.outputFile(path.join(cwd, file), "hello");
await gitAdd([file], { granularPathspec: true }, { cwd });

const list = await execa.stdout("git", ["diff", "--cached", "--name-only"], { cwd });
expect(slash(list)).toBe("packages/pkg-1/index.js");
await expect(getStagedFile(cwd)).resolves.toBe("packages/pkg-1/index.js");
});

test("absolute files", async () => {
Expand All @@ -25,8 +27,7 @@ test("absolute files", async () => {
await fs.outputFile(file, "hello");
await gitAdd([file], { granularPathspec: true }, { cwd });

const list = await execa.stdout("git", ["diff", "--cached", "--name-only"], { cwd });
expect(slash(list)).toBe("packages/pkg-2/index.js");
await expect(getStagedFile(cwd)).resolves.toBe("packages/pkg-2/index.js");
});

test(".gitignore", async () => {
Expand All @@ -42,8 +43,7 @@ test(".gitignore", async () => {

await gitAdd([file3, file4], { granularPathspec: false }, { cwd });

const list = await execa.stdout("git", ["diff", "--cached", "--name-only"], { cwd });
expect(slash(list)).toBe("packages/version-3/package.json");
await expect(getStagedFile(cwd)).resolves.toBe("packages/version-3/package.json");
});

test(".gitignore without naming files", async () => {
Expand All @@ -59,6 +59,5 @@ test(".gitignore without naming files", async () => {

await gitAdd([], { granularPathspec: false }, { cwd });

const list = await execa.stdout("git", ["diff", "--cached", "--name-only"], { cwd });
expect(slash(list)).toBe("packages/version-5/package.json");
await expect(getStagedFile(cwd)).resolves.toBe("packages/version-5/package.json");
});
2 changes: 1 addition & 1 deletion commands/version/__tests__/git-push.test.js
Expand Up @@ -6,7 +6,7 @@ const cloneFixture = require("@lerna-test/clone-fixture")(__dirname);
const gitPush = require("../lib/git-push");

async function listRemoteTags(cwd) {
return execa.stdout("git", ["ls-remote", "--tags", "--refs", "--quiet"], { cwd });
return execa("git", ["ls-remote", "--tags", "--refs", "--quiet"], { cwd }).then((result) => result.stdout);
}

beforeEach(() => {
Expand Down
21 changes: 7 additions & 14 deletions commands/version/__tests__/version-command.test.js
Expand Up @@ -298,6 +298,9 @@ describe("VersionCommand", () => {

// TODO: (major) make --no-granular-pathspec the default
describe("--no-granular-pathspec", () => {
const getLeftover = (cwd) =>
execa("git", ["ls-files", "--others"], { cwd }).then((result) => result.stdout);

it("adds changed files globally", async () => {
const cwd = await initFixture("normal");
await fs.outputFile(path.join(cwd, ".gitignore"), "packages/dynamic");
Expand All @@ -308,7 +311,7 @@ describe("VersionCommand", () => {
// a "dynamic", intentionally unversioned package must _always_ be forced
await lernaVersion(cwd)("--force-publish=dynamic", "--no-granular-pathspec");

const leftover = await execa.stdout("git", ["ls-files", "--others"], { cwd });
const leftover = await getLeftover(cwd);
expect(leftover).toBe("packages/dynamic/package.json");
});

Expand All @@ -326,7 +329,7 @@ describe("VersionCommand", () => {
// a "dynamic", intentionally unversioned package must _always_ be forced
await lernaVersion(cwd)("--force-publish=dynamic");

const leftover = await execa.stdout("git", ["ls-files", "--others"], { cwd });
const leftover = await getLeftover(cwd);
expect(leftover).toBe("packages/dynamic/package.json");
});
});
Expand Down Expand Up @@ -585,12 +588,12 @@ describe("VersionCommand", () => {
describe("working on a detached HEAD", () => {
const detachedHEAD = async (fixture = "normal") => {
const cwd = await initFixture(fixture);
const sha = await execa.stdout("git", ["rev-parse", "HEAD"], { cwd });
const { stdout: sha } = await execa("git", ["rev-parse", "HEAD"], { cwd });
await execa("git", ["checkout", sha], { cwd });
return cwd;
};

it("throws for version", async () => {
it("throws by default", async () => {
const cwd = await detachedHEAD();
const command = lernaVersion(cwd)();

Expand Down Expand Up @@ -643,16 +646,6 @@ describe("VersionCommand", () => {
);
});

it("exits with an error when git HEAD is detached", async () => {
const cwd = await initFixture("no-interdependencies");
const sha = await execa.stdout("git", ["rev-parse", "HEAD"], { cwd });

await execa("git", ["checkout", sha], { cwd }); // detach head

const command = lernaVersion(cwd)();
await expect(command).rejects.toThrow("Detached git HEAD, please checkout a branch to choose versions.");
});

it("exits early when no changes found", async () => {
const cwd = await initFixture("normal");

Expand Down
10 changes: 5 additions & 5 deletions core/child-process/__tests__/child-process.test.js
Expand Up @@ -52,7 +52,7 @@ describe("ChildProcessUtilities", () => {

await expect(result).rejects.toThrow(
expect.objectContaining({
code: os.constants.errno.ENOENT,
exitCode: os.constants.errno.ENOENT,
pkg: { name: "hamilton" },
})
);
Expand All @@ -64,9 +64,9 @@ describe("ChildProcessUtilities", () => {
const child = ChildProcessUtilities.spawn("echo", ["-n"]);
expect(child.stdio).toEqual([null, null, null]);

const { code, signal } = await child;
expect(code).toBe(0);
expect(signal).toBe(null);
const { exitCode, signal } = await child;
expect(exitCode).toBe(0);
expect(signal).toBe(undefined);
});

it("decorates opts.pkg on error if caught", async () => {
Expand All @@ -77,7 +77,7 @@ describe("ChildProcessUtilities", () => {

await expect(result).rejects.toThrow(
expect.objectContaining({
code: 123,
exitCode: 123,
pkg: { name: "shelled" },
})
);
Expand Down
29 changes: 17 additions & 12 deletions core/child-process/index.js
Expand Up @@ -70,30 +70,38 @@ function getChildProcessCount() {
}

function getExitCode(result) {
if (result.exitCode) {
return result.exitCode;
}

// https://nodejs.org/docs/latest-v6.x/api/child_process.html#child_process_event_close
if (typeof result.code === "number") {
return result.code;
}

// https://nodejs.org/docs/latest-v6.x/api/errors.html#errors_error_code
// istanbul ignore else
if (typeof result.code === "string") {
return os.constants.errno[result.code];
}

// istanbul ignore next: extremely weird
throw new TypeError(`Received unexpected exit code value ${JSON.stringify(result.code)}`);
// we tried
return process.exitCode;
}

function spawnProcess(command, args, opts) {
const child = execa(command, args, opts);
const drain = (code, signal) => {
const drain = (exitCode, signal) => {
children.delete(child);

// don't run repeatedly if this is the error event
if (signal === undefined) {
child.removeListener("exit", drain);
}

// propagate exit code, if any
if (exitCode) {
process.exitCode = exitCode;
}
};

child.once("exit", drain);
Expand All @@ -111,14 +119,11 @@ function spawnProcess(command, args, opts) {
function wrapError(spawned) {
if (spawned.pkg) {
return spawned.catch((err) => {
// istanbul ignore else
if (err.code) {
// ensure code is always a number
err.code = getExitCode(err);

// log non-lerna error cleanly
err.pkg = spawned.pkg;
}
// ensure exit code is always a number
err.exitCode = getExitCode(err);

// log non-lerna error cleanly
err.pkg = spawned.pkg;

throw err;
});
Expand Down

0 comments on commit 9051dca

Please sign in to comment.