Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add json output to ls and updated commands #824

Merged
merged 3 commits into from
May 21, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 37 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,24 @@ Lerna determines the last git tag created and runs `git diff --name-only v6.8.1`
**Note that configuration for the `publish` command _also_ affects the
`updated` command. For example `config.publish.ignore`**

#### --json

```sh
$ lerna updated --json
```

When run with this flag, `updated` will return an array of objects in the following format:

```json
[
{
"name": "package",
"version": "1.0.0",
"private": false
}
]
```

### clean

```sh
Expand Down Expand Up @@ -437,7 +455,25 @@ $ lerna ls

List all of the public packages in the current Lerna repo.

`lerna ls` respects the `--ignore` and `--scope` flags (see [Flags](#flags)).
`lerna ls` respects the `--ignore`, `--scope`, and `--json` flags (see [Flags](#flags)).

#### --json

```sh
$ lerna ls --json
```

When run with this flag, `ls` will return an array of objects in the following format:

```json
[
{
"name": "package",
"version": "1.0.0",
"private": false
}
]
```

### run

Expand Down
13 changes: 13 additions & 0 deletions src/Command.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ export const builder = {
describe: "Set max-buffer(bytes) for Command execution",
type: "number",
requiresArg: true
},
"json": {
describe: dedent`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move the json option descriptor into LsCommand and UpdatedCommand directly. It's an acceptable amount of duplication to maintain the benefit of targeted, relevant --help output. The description could be shorter, like "Show information in JSON format". (when in doubt, i copy npm's docs)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in ceb1fe0

Returns output as a machine-readable json object
(Only for 'ls' and 'updated' commands)
`,
type: "boolean",
default: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This default is implicit for boolean options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
};

Expand All @@ -70,6 +78,11 @@ export default class Command {
log.pause();
log.heading = "lerna";

// Default to silent log level for JSON output
if (flags.json) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't necessary, actually, as all logging is emitted to stderr and only the JSON string is emitted to stdout. When you pipe the output, it only includes stdout (unless you do fancy stdio redirects, of course).

It's too bad I didn't write a lerna ls integration test that could demonstrate this :/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in ceb1fe0

log.level = "silent";
}

if (flags.loglevel) {
log.level = flags.loglevel;
}
Expand Down
14 changes: 11 additions & 3 deletions src/commands/LsCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,20 @@ export default class LsCommand extends Command {
.map((pkg) => {
return {
name: pkg.name,
version: chalk.grey(`v${pkg.version}`),
private: pkg.isPrivate() ? `(${chalk.red("private")})` : ""
version: pkg.version,
private: pkg.isPrivate()
};
});

output(columnify(formattedPackages, { showHeaders: false }));
if (this.options.json) {
output(JSON.stringify(formattedPackages, null, 2));
} else {
formattedPackages.forEach((pkg) => {
pkg.version = chalk.grey(`v${pkg.version}`);
pkg.private = pkg.private ? `(${chalk.red("private")})` : "";
});
output(columnify(formattedPackages, { showHeaders: false }));
}

callback(null, true);
}
Expand Down
19 changes: 15 additions & 4 deletions src/commands/UpdatedCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,23 @@ export default class UpdatedCommand extends Command {
}

execute(callback) {
const formattedUpdates = this.updates.map((update) => update.package).map((pkg) =>
`- ${pkg.name}${pkg.isPrivate() ? ` (${chalk.red("private")})` : ""}`
).join("\n");
const updatedPackages = this.updates.map((update) => update.package).map((pkg) => {
return {
name: pkg.name,
version: pkg.version,
private: pkg.isPrivate()
};
});

this.logger.info("result");
output(formattedUpdates);
if (this.options.json) {
output(JSON.stringify(updatedPackages, null, 2));
} else {
const formattedUpdates = updatedPackages.map((pkg) =>
`- ${pkg.name}${pkg.private ? ` (${chalk.red("private")})` : ""}`
).join("\n");
output(formattedUpdates);
}

callback(null, true);
}
Expand Down
31 changes: 31 additions & 0 deletions test/LsCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,35 @@ describe("LsCommand", () => {
}));
});
});

describe("with --json", () => {
let testDir;

beforeEach(() => initFixture("LsCommand/basic").then((dir) => {
testDir = dir;
}));

it("should list packages as json objects", (done) => {
const lsCommand = new LsCommand([], {
json: true
}, testDir);

lsCommand.runValidations();
lsCommand.runPreparations();

lsCommand.runCommand(exitWithCode(0, (err) => {
if (err) return done.fail(err);
try {
const outputStr = consoleOutput();
expect(outputStr).toMatchSnapshot();
// Output should be a parseable string
const jsonOutput = JSON.parse(outputStr);
expect(jsonOutput).toMatchSnapshot();
done();
} catch (ex) {
done.fail(ex);
}
}));
});
});
});
39 changes: 39 additions & 0 deletions test/UpdatedCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,45 @@ describe("UpdatedCommand", () => {
updatedCommand.runCommand(exitWithCode(1, done));
});
});

/** =========================================================================
* JSON Output
* ======================================================================= */

describe("with --json", () => {
let testDir;

beforeEach(() => initFixture("UpdatedCommand/basic").then((dir) => {
testDir = dir;
}));

it("should list changes as a json object", (done) => {
setupGitChanges(testDir, [
"packages/package-2/random-file",
]);

const updatedCommand = new UpdatedCommand([], {
json: true
}, testDir);

updatedCommand.runValidations();
updatedCommand.runPreparations();

updatedCommand.runCommand(exitWithCode(0, (err) => {
if (err) return done.fail(err);
try {
const outputStr = consoleOutput();
expect(outputStr).toMatchSnapshot();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can just skip straight to the JSON.parse(consoleOutput()) snapshot, as we really shouldn't be testing whether or not JSON.stringify() is working correctly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 73f492a

// Output should be a parseable string
const jsonOutput = JSON.parse(outputStr);
expect(jsonOutput).toMatchSnapshot();
done();
} catch (ex) {
done.fail(ex);
}
}));
});
});
});

// TODO: remove this when we _really_ remove support for SECRET_FLAG
Expand Down
62 changes: 62 additions & 0 deletions test/__snapshots__/LsCommand.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,65 @@ Array [
@test/package-1 v1.0.0 ",
]
`;

exports[`LsCommand with --json should list packages as json objects 1`] = `
Array [
"[
{
\\"name\\": \\"package-1\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
},
{
\\"name\\": \\"package-2\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
},
{
\\"name\\": \\"package-3\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
},
{
\\"name\\": \\"package-4\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
},
{
\\"name\\": \\"package-5\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": true
}
]",
]
`;

exports[`LsCommand with --json should list packages as json objects 2`] = `
Array [
Object {
"name": "package-1",
"private": false,
"version": "1.0.0",
},
Object {
"name": "package-2",
"private": false,
"version": "1.0.0",
},
Object {
"name": "package-3",
"private": false,
"version": "1.0.0",
},
Object {
"name": "package-4",
"private": false,
"version": "1.0.0",
},
Object {
"name": "package-5",
"private": true,
"version": "1.0.0",
},
]
`;
32 changes: 32 additions & 0 deletions test/__snapshots__/UpdatedCommand.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,35 @@ Array [
- package-4",
]
`;

exports[`UpdatedCommand with --json should list changes as a json object 1`] = `
Array [
"[
{
\\"name\\": \\"package-2\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
},
{
\\"name\\": \\"package-3\\",
\\"version\\": \\"1.0.0\\",
\\"private\\": false
}
]",
]
`;

exports[`UpdatedCommand with --json should list changes as a json object 2`] = `
Array [
Object {
"name": "package-2",
"private": false,
"version": "1.0.0",
},
Object {
"name": "package-3",
"private": false,
"version": "1.0.0",
},
]
`;