Convert command note to oclif

Add oclif support for piped input

Change-type: patch
Signed-off-by: Scott Lowe <scott@balena.io>
This commit is contained in:
Scott Lowe 2020-03-25 18:07:17 +01:00
parent 49b00e18ae
commit fcad35402a
10 changed files with 169 additions and 78 deletions

View File

@ -84,7 +84,7 @@ const capitanoDoc = {
},
{
title: 'Notes',
files: ['build/actions/notes.js'],
files: ['build/actions-oclif/note.js'],
},
{
title: 'OS',

View File

@ -68,6 +68,9 @@ function importCapitanoCommands(jsFilename: string): CapitanoCommand[] {
}
function importOclifCommands(jsFilename: string): OclifCommand[] {
// TODO: Currently oclif commands with no `usage` overridden will cause
// an error when parsed. This should be improved so that `usage` does not have
// to be overridden if not necessary.
const command: OclifCommand = require(path.join(process.cwd(), jsFilename))
.default as OclifCommand;
return [command];

View File

@ -229,6 +229,10 @@ If you come across any problems or would like to get in touch:
- [push &#60;applicationOrDevice&#62;](#push-applicationordevice)
- Settings
- [settings](#settings)
- Local
- [local configure &#60;target&#62;](#local-configure-target)
@ -1248,22 +1252,35 @@ The mapping of remote to local ports.
## note &#60;|note&#62;
Use this command to set or update a device note.
Set or update a device note. If the note argument is not provided,
it will be read from stdin.
If note command isn't passed, the tool attempts to read from `stdin`.
To view the notes, use $ balena device <uuid>.
To view device notes, use the `balena device <uuid>` command.
Examples:
$ balena note "My useful note" --device 7cf02a6
$ cat note.txt | balena note --device 7cf02a6
### Arguments
#### NOTE
note content
### Options
#### --device, -d, --dev &#60;device&#62;
#### -d, --device DEVICE
device UUID
#### --dev DEV
#### --stdin
device uuid
# OS
@ -1809,6 +1826,18 @@ left hand side of the = character will be treated as the variable name.
On Windows only, convert line endings from CRLF (Windows format) to LF (Unix format).
Source files are not modified.
# Settings
## settings
Use this command to display current balena CLI settings.
Examples:
$ balena settings
### Options
# Local
## local configure &#60;target&#62;

100
lib/actions-oclif/note.ts Normal file
View File

@ -0,0 +1,100 @@
/**
* @license
* Copyright 2016-2020 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 { flags } from '@oclif/command';
import { stripIndent } from 'common-tags';
import * as _ from 'lodash';
import Command from '../command';
import { ExpectedError } from '../errors';
import * as cf from '../utils/common-flags';
import { getBalenaSdk } from '../utils/lazy';
interface FlagsDef {
device?: string; // device UUID
dev?: string; // Alias for device.
stdin: boolean;
help: void;
}
interface ArgsDef {
note: string;
}
export default class NoteCmd extends Command {
public static description = stripIndent`
Set a device note.
Set or update a device note. If the note argument is not provided,
it will be read from stdin.
To view device notes, use the \`balena device <uuid>\` command.
`;
public static examples = [
'$ balena note "My useful note" --device 7cf02a6',
'$ cat note.txt | balena note --device 7cf02a6',
];
public static args = [
{
name: 'note',
// required: true,
description: 'note content',
},
];
public static usage = 'note <|note>';
public static flags: flags.Input<FlagsDef> = {
device: { exclusive: ['dev'], ...cf.device },
dev: flags.string({
exclusive: ['device'],
hidden: true,
}),
// Hack to read stdin with oclif
stdin: flags.boolean({
hidden: true,
}),
help: cf.help,
};
public static authenticated = true;
public static readStdin = true;
public async run() {
const { args: params, flags: options } = this.parse<FlagsDef, ArgsDef>(
NoteCmd,
);
params.note = params.note || this.stdin;
if (_.isEmpty(params.note)) {
throw new ExpectedError('Missing note content');
}
options.device = options.device || options.dev;
delete options.dev;
if (_.isEmpty(options.device)) {
throw new ExpectedError('Missing device UUID (--device)');
}
const balena = getBalenaSdk();
return balena.models.device.note(options.device!, params.note);
}
}

View File

@ -1,6 +1,6 @@
/**
* @license
* Copyright 2020 Balena Ltd.
* Copyright 2016-2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.

View File

@ -24,7 +24,6 @@ module.exports =
logs: require('./logs')
local: require('./local')
scan: require('./scan')
notes: require('./notes')
help: require('./help')
os: require('./os')
config: require('./config')

View File

@ -1,58 +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';
import { getBalenaSdk } from '../utils/lazy';
export const set: CommandDefinition<{ note: string }, { device: string }> = {
signature: 'note <|note>',
description: 'set a device note',
help: `\
Use this command to set or update a device note.
If note command isn't passed, the tool attempts to read from \`stdin\`.
To view the notes, use $ balena device <uuid>.
Examples:
$ balena note "My useful note" --device 7cf02a6
$ cat note.txt | balena note --device 7cf02a6\
`,
options: [
{
signature: 'device',
parameter: 'device',
description: 'device uuid',
alias: ['d', 'dev'],
required: 'You have to specify a device',
},
],
permission: 'user',
async action(params, options) {
const { normalizeUuidProp } = await import('../utils/normalization');
normalizeUuidProp(options, 'device');
const _ = await import('lodash');
const balena = getBalenaSdk();
if (_.isEmpty(params.note)) {
const { exitWithExpectedError } = await import('../utils/patterns');
exitWithExpectedError('Missing note content');
}
return balena.models.device.note(options.device!, params.note);
},
};

View File

@ -74,9 +74,6 @@ capitano.command(actions.device.move)
capitano.command(actions.device.osUpdate)
capitano.command(actions.device.info)
# ---------- Notes Module ----------
capitano.command(actions.notes.set)
# ---------- Keys Module ----------
capitano.command(actions.keys.list)
capitano.command(actions.keys.add)

View File

@ -40,6 +40,15 @@ export default abstract class BalenaCommand extends Command {
*/
public static authenticated = false;
/**
* Accept piped input.
* When set to true, command will read from stdin during init
* and make contents available on member `stdin`.
*/
public static readStdin = false;
public stdin: string;
/**
* Throw InsufficientPrivilegesError if not root on Mac/Linux
* or non-Administrator on Windows.
@ -74,18 +83,29 @@ export default abstract class BalenaCommand extends Command {
await (await import('./utils/patterns')).checkLoggedIn();
}
protected async init() {
const requireElevatedPrivileges = (this.constructor as typeof BalenaCommand)
.root;
const requireAuthentication = (this.constructor as typeof BalenaCommand)
.authenticated;
/**
* Read stdin contents and make available to command.
*
* This approach could be improved in the future to automatically set argument
* values from stdin based in configuration, minimising command implementation.
*/
protected async getStdin() {
this.stdin = await (await import('get-stdin'))();
}
if (requireElevatedPrivileges) {
protected async init() {
const ctr = this.constructor as typeof BalenaCommand;
if (ctr.root) {
await BalenaCommand.checkElevatedPrivileges();
}
if (requireAuthentication) {
if (ctr.authenticated) {
await BalenaCommand.checkLoggedIn();
}
if (ctr.readStdin) {
await this.getStdin();
}
}
}

View File

@ -131,9 +131,10 @@ export const convertedCommands = [
'env:add',
'env:rename',
'env:rm',
'note',
'os:configure',
'version',
'settings',
'version',
];
/**