Add options to 'balena version' to show Node.js version

Change-type: minor
Signed-off-by: Paulo Castro <paulo@balena.io>
This commit is contained in:
Paulo Castro 2019-06-24 16:51:07 +01:00
parent 236dce37da
commit 9d5ecb5f9c
11 changed files with 168 additions and 75 deletions

View File

@ -58,12 +58,8 @@ const capitanoDoc = {
files: ['build/actions/tags.js'],
},
{
title: 'Help',
files: ['build/actions/help.js'],
},
{
title: 'Information',
files: ['build/actions/info.js'],
title: 'Help and Version',
files: ['build/actions/help.js', 'build/actions-oclif/version.js'],
},
{
title: 'Keys',

View File

@ -119,12 +119,9 @@ If you come across any problems or would like to get in touch:
- [tag set &#60;tagKey&#62; [value]](#tag-set-tagkey-value)
- [tag rm &#60;tagKey&#62;](#tag-rm-tagkey)
- Help
- Help and Version
- [help [command...]](#help-command)
- Information
- [version](#version)
- Keys
@ -779,7 +776,7 @@ device uuid
release id
# Help
# Help and Version
## help [command...]
@ -796,11 +793,27 @@ Examples:
show additional commands
# Information
## version
Display the balena CLI version.
Display version information for the balena CLI and/or Node.js.
If you intend to parse the output, please use the -j option for
JSON output, as its format is more stable.
Examples:
$ balena version
$ balena version -a
$ balena version -j
### Options
#### -a, --all
include version information for additional components (Node.js)
#### -j, --json
output version information in JSON format for programmatic use
# Keys

View File

@ -0,0 +1,79 @@
/**
* @license
* Copyright 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 { stripIndent } from 'common-tags';
interface FlagsDef {
all?: boolean;
json?: boolean;
}
export default class VersionCmd extends Command {
public static description = stripIndent`
Display version information for the balena CLI and/or Node.js.
Display version information for the balena CLI and/or Node.js.
If you intend to parse the output, please use the -j option for
JSON output, as its format is more stable.
`;
public static examples = [
'$ balena version',
'$ balena version -a',
'$ balena version -j',
];
public static usage = 'version';
public static flags = {
all: flags.boolean({
char: 'a',
default: false,
description:
'include version information for additional components (Node.js)',
}),
json: flags.boolean({
char: 'j',
default: false,
description:
'output version information in JSON format for programmatic use',
}),
help: flags.help({ char: 'h' }),
};
public async run() {
const { flags: options } = this.parse<FlagsDef, {}>(VersionCmd);
const versions = {
'balena-cli': (await import('../../package.json')).version,
'Node.js':
process.version && process.version.startsWith('v')
? process.version.slice(1)
: process.version,
};
if (options.json) {
console.log(JSON.stringify(versions, null, 4));
} else {
if (options.all) {
console.log(`balena-cli version "${versions['balena-cli']}"`);
console.log(`Node.js version "${versions['Node.js']}"`);
} else {
// backwards compatibility
console.log(versions['balena-cli']);
}
}
}
}

View File

@ -18,10 +18,14 @@
import { Command } from '@oclif/command';
import * as _ from 'lodash';
import EnvAddCmd from '../actions-oclif/env/add';
export function getOclifHelpLinePairs(): [[string, string]] {
return [getCmdUsageDescriptionLinePair(EnvAddCmd)];
export function getOclifHelpLinePairs(): Array<[string, string]> {
// Although it's tempting to have these oclif commands 'require'd in a
// central place, it would impact on performance (CLI start time). An
// improvement would probably be to automatically scan the actions-oclif
// folder.
const EnvAddCmd = require('../actions-oclif/env/add').default;
const VersionCmd = require('../actions-oclif/version').default;
return [EnvAddCmd, VersionCmd].map(getCmdUsageDescriptionLinePair);
}
function getCmdUsageDescriptionLinePair(cmd: typeof Command): [string, string] {

View File

@ -18,7 +18,6 @@ module.exports =
apiKey: require('./api-key')
app: require('./app')
auth: require('./auth')
info: require('./info')
device: require('./device')
env: require('./environment-variables')
tags: require('./tags')

View File

@ -1,30 +0,0 @@
/*
Copyright 2016-2017 Balena
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 { CommandDefinition } from 'capitano';
export const version: CommandDefinition = {
signature: 'version',
description: 'output the version number',
help: `\
Display the balena CLI version.\
`,
async action(_params, _options, done) {
const packageJSON = await import('../../package.json');
console.log(packageJSON.version);
return done();
},
};

View File

@ -33,8 +33,10 @@ capitano.globalOption
boolean: true
alias: 'h'
# ---------- Info Module ----------
capitano.command(actions.info.version)
capitano.globalOption
signature: 'version'
boolean: true
alias: 'v'
# ---------- Help Module ----------
capitano.command(actions.help.help)

View File

@ -15,23 +15,34 @@
* limitations under the License.
*/
import { Main } from '@oclif/command';
import { ExitError } from '@oclif/errors';
import { handleError } from './errors';
class CustomMain extends Main {
protected _helpOverride(): boolean {
// Disable oclif's default handler for the 'version' command
if (['-v', '--version', 'version'].includes(this.argv[0])) {
return false;
} else {
return super._helpOverride();
}
}
}
/**
* oclif CLI entrypoint
*/
export function run(argv: string[]) {
process.argv = argv;
require('@oclif/command')
.run()
.then(require('@oclif/command/flush'))
.catch((error: Error) => {
CustomMain.run(argv.slice(2)).then(
require('@oclif/command/flush'),
(error: Error) => {
// oclif sometimes exits with ExitError code 0 (not an error)
if (error instanceof ExitError && error.oclif.exit === 0) {
return;
}
handleError(error);
});
},
);
}

View File

@ -31,21 +31,29 @@ function routeCliFramework(argv: string[]): void {
);
}
const cmdSlice = argv.slice(2);
let isOclif = false;
// Look for commands that have been deleted, to print a notice
checkDeletedCommand(cmdSlice);
if (cmdSlice.length > 1) {
if (cmdSlice.length > 0) {
// convert 'balena --version' or 'balena -v' to 'balena version'
if (['--version', '-v'].includes(cmdSlice[0])) {
cmdSlice[0] = 'version';
}
// convert 'balena --help' or 'balena -h' to 'balena help'
else if (['--help', '-h'].includes(cmdSlice[0])) {
cmdSlice[0] = 'help';
}
// convert e.g. 'balena help env add' to 'balena env add --help'
if (cmdSlice[0] === 'help') {
if (cmdSlice.length > 1 && cmdSlice[0] === 'help') {
cmdSlice.shift();
cmdSlice.push('--help');
}
}
// Look for commands that have been transitioned to oclif
isOclif = isOclifCommand(cmdSlice);
if (isOclif) {
const [isOclif, isTopic] = isOclifCommand(cmdSlice);
if (isOclif) {
if (isTopic) {
// convert space-separated commands to oclif's topic:command syntax
argv = [
argv[0],
@ -53,11 +61,11 @@ function routeCliFramework(argv: string[]): void {
cmdSlice[0] + ':' + cmdSlice[1],
...cmdSlice.slice(2),
];
} else {
argv = [argv[0], argv[1], ...cmdSlice];
}
}
if (isOclif) {
if (process.env.DEBUG) {
console.log(`Debug: oclif new argv=[${argv}] length=${argv.length}`);
console.log(`Debug: new argv=[${argv}] length=${argv.length}`);
}
require('./app-oclif').run(argv);
} else {
@ -113,18 +121,28 @@ function checkDeletedCommand(argvSlice: string[]): void {
}
/**
* Determine whether the CLI command has been converted from Capitano to ocif.
* Determine whether the CLI command has been converted from Capitano to oclif.
* Return an array of two boolean values:
* r[0] : whether the CLI command is implemented with oclif
* r[1] : if r[0] is true, whether the CLI command is implemented with
* oclif "topics" (colon-separated subcommands like `env:add`)
* @param argvSlice process.argv.slice(2)
*/
function isOclifCommand(argvSlice: string[]): boolean {
function isOclifCommand(argvSlice: string[]): [boolean, boolean] {
// Look for commands that have been transitioned to oclif
if (argvSlice.length > 1) {
// balena env add
if (argvSlice[0] === 'env' && argvSlice[1] === 'add') {
return true;
if (argvSlice.length > 0) {
// balena version
if (argvSlice[0] === 'version') {
return [true, false];
}
if (argvSlice.length > 1) {
// balena env add
if (argvSlice[0] === 'env' && argvSlice[1] === 'add') {
return [true, true];
}
}
}
return false;
return [false, false];
}
/**

View File

@ -27,7 +27,7 @@ export const convertedCommands = {
* command help output.
*/
export class CommandHelp {
constructor(public command: { args: any[] }) {}
constructor(public command: { args?: any[] }) {}
protected arg(arg: Config.Command['args'][0]): string {
const name = arg.name.toUpperCase();
@ -40,7 +40,7 @@ export class CommandHelp {
public defaultUsage(): string {
return CommandHelp.compact([
// this.command.id,
this.command.args
(this.command.args || [])
.filter(a => !a.hidden)
.map(a => this.arg(a))
.join(' '),

View File

@ -26,6 +26,7 @@
"node_modules/raven/lib/instrumentation/*.js"
],
"assets": [
"build/actions-oclif",
"build/auth/pages/*.ejs",
"node_modules/resin-discoverable-services/services/**/*"
]