From 323c9191b6541285cbb44855b43acf01c5866d30 Mon Sep 17 00:00:00 2001 From: Paulo Castro Date: Thu, 26 Dec 2019 22:59:44 +0000 Subject: [PATCH] Add --verbose and --json options to the 'devices supported' command The command was also converted to oclif. Resolves: #467 Change-type: minor Signed-off-by: Paulo Castro --- automation/capitanodoc/capitanodoc.ts | 5 +- doc/cli.markdown | 30 +++++- lib/actions-oclif/devices/supported.ts | 118 ++++++++++++++++++++++++ lib/actions/device.coffee | 1 - lib/actions/device_ts.ts | 25 ----- lib/app-capitano.coffee | 1 - lib/preparser.ts | 1 + tests/commands/device/supported.spec.ts | 12 +-- tests/commands/help.spec.ts | 2 +- 9 files changed, 154 insertions(+), 41 deletions(-) create mode 100644 lib/actions-oclif/devices/supported.ts diff --git a/automation/capitanodoc/capitanodoc.ts b/automation/capitanodoc/capitanodoc.ts index 2dce82c4..48a95d09 100644 --- a/automation/capitanodoc/capitanodoc.ts +++ b/automation/capitanodoc/capitanodoc.ts @@ -44,7 +44,10 @@ const capitanoDoc = { }, { title: 'Device', - files: ['build/actions/device.js'], + files: [ + 'build/actions/device.js', + 'build/actions-oclif/devices/supported.js', + ], }, { title: 'Environment Variables', diff --git a/doc/cli.markdown b/doc/cli.markdown index fb5992e5..5d64968d 100644 --- a/doc/cli.markdown +++ b/doc/cli.markdown @@ -576,11 +576,39 @@ confirm non interactively ## devices supported -Use this command to get the list of all supported devices. +List the supported device types (like 'raspberrypi3' or 'intel-nuc'). + +The --verbose option adds extra columns/fields to the output, including the +"STATE" column whose values are one of 'beta', 'release' or 'discontinued'. +However, 'discontinued' device types are only listed if the '--discontinued' +option is used. + +The --json option is recommended when scripting the output of this command +(perhaps in combination with the [jq +utility](https://stedolan.github.io/jq/manual/)), as it is more parser +friendly (e.g. the ALIASES column contains a list of zero or more values) +and also more "stable" in relation to added or reordered columns in tabular +output (which is intended for "human eyes"). Examples: $ balena devices supported + $ balena devices supported --verbose + $ balena devices supported -vj + +### Options + +#### --discontinued + +include "discontinued" device types + +#### -j, --json + +produce JSON output instead of tabular output + +#### -v, --verbose + +add extra columns in the tabular output (ALIASES, ARCH, STATE) # Environment Variables diff --git a/lib/actions-oclif/devices/supported.ts b/lib/actions-oclif/devices/supported.ts new file mode 100644 index 00000000..2f825209 --- /dev/null +++ b/lib/actions-oclif/devices/supported.ts @@ -0,0 +1,118 @@ +/** + * @license + * Copyright 2016-2019 Balena Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { Command, flags } from '@oclif/command'; +import * as SDK from 'balena-sdk'; +import { stripIndent } from 'common-tags'; +import * as _ from 'lodash'; + +import * as cf from '../../utils/common-flags'; +import { CommandHelp } from '../../utils/oclif-utils'; + +interface FlagsDef { + discontinued: boolean; + help: void; + json?: boolean; + verbose?: boolean; +} + +interface DeviceTypeWithAliases extends SDK.DeviceType { + aliases?: string[]; +} + +export default class DevicesSupportedCmd extends Command { + public static description = stripIndent` + List the supported device types (like 'raspberrypi3' or 'intel-nuc'). + + List the supported device types (like 'raspberrypi3' or 'intel-nuc'). + + The --verbose option adds extra columns/fields to the output, including the + "STATE" column whose values are one of 'beta', 'release' or 'discontinued'. + However, 'discontinued' device types are only listed if the '--discontinued' + option is used. + + The --json option is recommended when scripting the output of this command + (perhaps in combination with the [jq + utility](https://stedolan.github.io/jq/manual/)), as it is more parser + friendly (e.g. the ALIASES column contains a list of zero or more values) + and also more "stable" in relation to added or reordered columns in tabular + output (which is intended for "human eyes"). +`; + public static examples = [ + '$ balena devices supported', + '$ balena devices supported --verbose', + '$ balena devices supported -vj', + ]; + + public static usage = ( + 'devices supported ' + + new CommandHelp({ args: DevicesSupportedCmd.args }).defaultUsage() + ).trim(); + + public static flags: flags.Input = { + discontinued: flags.boolean({ + description: 'include "discontinued" device types', + }), + help: cf.help, + json: flags.boolean({ + char: 'j', + description: 'produce JSON output instead of tabular output', + }), + verbose: flags.boolean({ + char: 'v', + description: + 'add extra columns in the tabular output (ALIASES, ARCH, STATE)', + }), + }; + + public async run() { + const { flags: options } = this.parse(DevicesSupportedCmd); + const sdk = SDK.fromSharedOptions(); + let deviceTypes: Array< + Partial + > = await sdk.models.config.getDeviceTypes(); + if (!options.discontinued) { + deviceTypes = deviceTypes.filter(dt => dt.state !== 'DISCONTINUED'); + } + const fields = ['slug', 'name']; + if (options.verbose) { + fields.splice(1, 0, 'aliases', 'arch', 'state'); + deviceTypes = deviceTypes.map(d => { + if (d.aliases && d.aliases.length) { + d.aliases = d.aliases.filter((alias: string) => alias !== d.slug); + if (!options.json) { + // stringify the aliases array with commas and spaces + d.aliases = [d.aliases.join(', ')]; + } + } else { + d.aliases = []; + } + return d; + }); + } + deviceTypes = _.sortBy( + deviceTypes.map(d => _.pick(d, fields) as Partial), + fields, + ); + if (options.json) { + console.log(JSON.stringify(deviceTypes, null, 4)); + } else { + const visuals = await import('resin-cli-visuals'); + const output = await visuals.table.horizontal(deviceTypes, fields); + console.log(output); + } + } +} diff --git a/lib/actions/device.coffee b/lib/actions/device.coffee index 7f121560..6ed21821 100644 --- a/lib/actions/device.coffee +++ b/lib/actions/device.coffee @@ -452,4 +452,3 @@ exports.init = tsActions = require('./device_ts') exports.osUpdate = tsActions.osUpdate -exports.supported = tsActions.supported diff --git a/lib/actions/device_ts.ts b/lib/actions/device_ts.ts index a93e3980..2aa67a76 100644 --- a/lib/actions/device_ts.ts +++ b/lib/actions/device_ts.ts @@ -19,31 +19,6 @@ import { stripIndent } from 'common-tags'; import { normalizeUuidProp } from '../utils/normalization'; import * as commandOptions from './command-options'; -export const supported: CommandDefinition<{}, {}> = { - signature: 'devices supported', - description: 'list all supported devices', - help: stripIndent` - Use this command to get the list of all supported devices. - - Examples: - - $ balena devices supported - `, - async action(_params, _options) { - const sdk = (await import('balena-sdk')).fromSharedOptions(); - const visuals = await import('resin-cli-visuals'); - const _ = await import('lodash'); - - let deviceTypes = await sdk.models.config.getDeviceTypes(); - const fields = ['slug', 'name']; - deviceTypes = _.sortBy(deviceTypes, fields).filter( - dt => dt.state !== 'DISCONTINUED', - ); - const output = await visuals.table.horizontal(deviceTypes, fields); - console.log(output); - }, -}; - // tslint:disable-next-line:no-namespace namespace OsUpdate { export interface Args { diff --git a/lib/app-capitano.coffee b/lib/app-capitano.coffee index 85e2b59c..f1ec4561 100644 --- a/lib/app-capitano.coffee +++ b/lib/app-capitano.coffee @@ -59,7 +59,6 @@ capitano.command(actions.auth.whoami) # ---------- Device Module ---------- capitano.command(actions.device.list) -capitano.command(actions.device.supported) capitano.command(actions.device.rename) capitano.command(actions.device.init) capitano.command(actions.device.remove) diff --git a/lib/preparser.ts b/lib/preparser.ts index 42fb6d87..e2a3ca9b 100644 --- a/lib/preparser.ts +++ b/lib/preparser.ts @@ -128,6 +128,7 @@ function checkDeletedCommand(argvSlice: string[]): void { } export const convertedCommands = [ + 'devices:supported', 'envs', 'env:add', 'env:rename', diff --git a/tests/commands/device/supported.spec.ts b/tests/commands/device/supported.spec.ts index 0fbdac45..a2487586 100644 --- a/tests/commands/device/supported.spec.ts +++ b/tests/commands/device/supported.spec.ts @@ -2,16 +2,6 @@ import { expect } from 'chai'; import { BalenaAPIMock } from '../../balena-api-mock'; import { cleanOutput, runCommand } from '../../helpers'; -const HELP_RESPONSE = ` -Usage: devices supported - -Use this command to get the list of all supported devices. - -Examples: - -\t$ balena devices supported -`; - describe('balena devices supported', function() { let api: BalenaAPIMock; @@ -30,7 +20,7 @@ describe('balena devices supported', function() { const { out, err } = await runCommand('devices supported -h'); - expect(cleanOutput(out)).to.deep.equal(cleanOutput([HELP_RESPONSE])); + expect(cleanOutput(out)).to.contain('$ balena devices supported'); expect(err).to.eql([]); }); diff --git a/tests/commands/help.spec.ts b/tests/commands/help.spec.ts index 24cfc80a..d2d8777b 100644 --- a/tests/commands/help.spec.ts +++ b/tests/commands/help.spec.ts @@ -57,7 +57,7 @@ Additional commands: device rename [newName] rename a balena device device rm remove a device device shutdown shutdown a device - devices supported list all supported devices + devices supported list the supported device types (like 'raspberrypi3' or 'intel-nuc') env add [value] add an environment or config variable to an application, device or service env rename change the value of a config or env var for an app, device or service env rm remove a config or env var from an application, device or service