From 1a8571c09356637f803fcbd32c34e9960407ac73 Mon Sep 17 00:00:00 2001 From: ricky Date: Sun, 21 May 2017 21:22:18 +0100 Subject: [PATCH] Add json output to `ls` and `updated` commands (#824) --- README.md | 36 ++++++++++++++++++++++ src/commands/LsCommand.js | 22 +++++++++++--- src/commands/UpdatedCommand.js | 34 ++++++++++++++++++--- test/LsCommand.js | 29 ++++++++++++++++++ test/UpdatedCommand.js | 37 +++++++++++++++++++++++ test/__snapshots__/LsCommand.js.snap | 30 ++++++++++++++++++ test/__snapshots__/UpdatedCommand.js.snap | 15 +++++++++ 7 files changed, 194 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 647a282fef..ff256dbe3d 100644 --- a/README.md +++ b/README.md @@ -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 @@ -439,6 +457,24 @@ List all of the public packages in the current Lerna repo. `lerna ls` respects the `--ignore` and `--scope` 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 ```sh diff --git a/src/commands/LsCommand.js b/src/commands/LsCommand.js index 9c720a608f..93640b00e5 100644 --- a/src/commands/LsCommand.js +++ b/src/commands/LsCommand.js @@ -12,7 +12,13 @@ export const command = "ls"; export const describe = "List all public packages"; -export const builder = {}; +export const builder = { + "json": { + describe: "Show information in JSON format", + group: "Command Options:", + type: "boolean" + } +}; export default class LsCommand extends Command { get requiresGit() { @@ -29,12 +35,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); } diff --git a/src/commands/UpdatedCommand.js b/src/commands/UpdatedCommand.js index 99b92a2183..ffe8ada19f 100644 --- a/src/commands/UpdatedCommand.js +++ b/src/commands/UpdatedCommand.js @@ -1,3 +1,4 @@ +import _ from "lodash"; import chalk from "chalk"; import { builder as publishOptions } from "./PublishCommand"; @@ -5,6 +6,18 @@ import Command from "../Command"; import output from "../utils/output"; import UpdatedPackagesCollector from "../UpdatedPackagesCollector"; +const updatedOptions = _.assign( + {}, + publishOptions, + { + "json": { + describe: "Show information in JSON format", + group: "Command Options:", + type: "boolean" + } + } +); + export function handler(argv) { return new UpdatedCommand(argv._, argv).run(); } @@ -13,7 +26,7 @@ export const command = "updated"; export const describe = "Check which packages have changed since the last publish."; -export const builder = (yargs) => yargs.options(publishOptions); +export const builder = (yargs) => yargs.options(updatedOptions); export default class UpdatedCommand extends Command { initialize(callback) { @@ -33,12 +46,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); } diff --git a/test/LsCommand.js b/test/LsCommand.js index bd988f1ba4..2106701935 100644 --- a/test/LsCommand.js +++ b/test/LsCommand.js @@ -129,4 +129,33 @@ 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 { + // Output should be a parseable string + const jsonOutput = JSON.parse(consoleOutput()); + expect(jsonOutput).toMatchSnapshot(); + done(); + } catch (ex) { + done.fail(ex); + } + })); + }); + }); }); diff --git a/test/UpdatedCommand.js b/test/UpdatedCommand.js index fa29b705c0..081624e194 100644 --- a/test/UpdatedCommand.js +++ b/test/UpdatedCommand.js @@ -353,6 +353,43 @@ 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 { + // Output should be a parseable string + const jsonOutput = JSON.parse(consoleOutput()); + expect(jsonOutput).toMatchSnapshot(); + done(); + } catch (ex) { + done.fail(ex); + } + })); + }); + }); }); // TODO: remove this when we _really_ remove support for SECRET_FLAG diff --git a/test/__snapshots__/LsCommand.js.snap b/test/__snapshots__/LsCommand.js.snap index a254dadb6d..b7dc4693fe 100644 --- a/test/__snapshots__/LsCommand.js.snap +++ b/test/__snapshots__/LsCommand.js.snap @@ -36,3 +36,33 @@ Array [ @test/package-1 v1.0.0 ", ] `; + +exports[`LsCommand with --json should list packages as json objects 1`] = ` +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", + }, +] +`; diff --git a/test/__snapshots__/UpdatedCommand.js.snap b/test/__snapshots__/UpdatedCommand.js.snap index 3c8b41f92d..9ab32aeb9f 100644 --- a/test/__snapshots__/UpdatedCommand.js.snap +++ b/test/__snapshots__/UpdatedCommand.js.snap @@ -135,3 +135,18 @@ Array [ - package-4", ] `; + +exports[`UpdatedCommand with --json should list changes as a json object 1`] = ` +Array [ + Object { + "name": "package-2", + "private": false, + "version": "1.0.0", + }, + Object { + "name": "package-3", + "private": false, + "version": "1.0.0", + }, +] +`;