Merge pull request #1398 from balena-io/oclif-args

Fix incorrect arguments passed to oclif bootstrap function
This commit is contained in:
Lucian Buzzo 2019-08-16 07:49:09 +01:00 committed by GitHub
commit b4c99dc03a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 252 additions and 14 deletions

View File

@ -146,7 +146,7 @@ capitano.command(actions.join.join)
capitano.command(actions.leave.leave)
exports.run = (argv) ->
cli = capitano.parse(argv)
cli = capitano.parse(argv.slice(2))
runCommand = ->
capitanoExecuteAsync = Promise.promisify(capitano.execute)
if cli.global?.help

View File

@ -57,24 +57,25 @@ function routeCliFramework(argv: string[], options: AppOptions): void {
}
const [isOclif, isTopic] = isOclifCommand(cmdSlice);
if (isOclif) {
let oclifArgs = cmdSlice;
if (isTopic) {
// convert space-separated commands to oclif's topic:command syntax
argv = [
argv[0],
argv[1],
cmdSlice[0] + ':' + cmdSlice[1],
...cmdSlice.slice(2),
];
} else {
argv = [argv[0], argv[1], ...cmdSlice];
oclifArgs = [cmdSlice[0] + ':' + cmdSlice[1], ...cmdSlice.slice(2)];
}
if (process.env.DEBUG) {
console.log(`[debug] new argv=[${argv}] length=${argv.length}`);
console.log(
`[debug] new argv=[${[
argv[0],
argv[1],
...oclifArgs,
]}] length=${oclifArgs.length + 2}`,
);
}
return require('./app-oclif').run(cmdSlice, options);
return require('./app-oclif').run(oclifArgs, options);
} else {
return require('./app-capitano').run(cmdSlice);
return require('./app-capitano').run(argv);
}
}

32
npm-shrinkwrap.json generated
View File

@ -575,6 +575,15 @@
"@types/node": "*"
}
},
"@types/nock": {
"version": "10.0.3",
"resolved": "https://registry.npmjs.org/@types/nock/-/nock-10.0.3.tgz",
"integrity": "sha512-OthuN+2FuzfZO3yONJ/QVjKmLEuRagS9TV9lEId+WHL9KhftYG+/2z+pxlr0UgVVXSpVD8woie/3fzQn8ft/Ow==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/node": {
"version": "10.14.5",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.5.tgz",
@ -12390,6 +12399,23 @@
}
}
},
"nock": {
"version": "10.0.6",
"resolved": "https://registry.npmjs.org/nock/-/nock-10.0.6.tgz",
"integrity": "sha512-b47OWj1qf/LqSQYnmokNWM8D88KvUl2y7jT0567NB3ZBAZFz2bWp2PC81Xn7u8F2/vJxzkzNZybnemeFa7AZ2w==",
"dev": true,
"requires": {
"chai": "^4.1.2",
"debug": "^4.1.0",
"deep-equal": "^1.0.0",
"json-stringify-safe": "^5.0.1",
"lodash": "^4.17.5",
"mkdirp": "^0.5.0",
"propagate": "^1.0.0",
"qs": "^6.5.1",
"semver": "^5.5.0"
}
},
"node-abi": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz",
@ -13466,6 +13492,12 @@
"resolved": "https://registry.npmjs.org/promise-memoize/-/promise-memoize-1.2.1.tgz",
"integrity": "sha1-cflVSpic9r+Jh7Q6UhMtXHkxJlc="
},
"propagate": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/propagate/-/propagate-1.0.0.tgz",
"integrity": "sha1-AMLa7t2iDofjeCs0Stuhzd1q1wk=",
"dev": true
},
"proper-lockfile": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-1.2.0.tgz",

View File

@ -96,6 +96,7 @@
"@types/mocha": "^5.2.7",
"@types/mz": "0.0.32",
"@types/net-keepalive": "^0.4.0",
"@types/nock": "^10.0.3",
"@types/node": "10.14.5",
"@types/prettyjson": "0.0.28",
"@types/raven": "2.5.1",
@ -118,6 +119,7 @@
"gulp-inline-source": "^2.1.0",
"gulp-shell": "^0.5.2",
"mocha": "^6.2.0",
"nock": "^10.0.6",
"pkg": "^4.4.0",
"prettier": "1.17.0",
"publish-release": "^1.6.0",

29
tests/commands/env/add.spec.ts vendored Normal file
View File

@ -0,0 +1,29 @@
import * as chai from 'chai';
import { balenaAPIMock, runCommand } from '../../helpers';
describe('balena env add', function() {
it('should successfully add an environment variable', async () => {
const deviceId = 'f63fd7d7812c34c4c14ae023fdff05f5';
const mock = balenaAPIMock();
mock
.get(/device/)
.reply(201, {
d: [
{
id: 1031543,
__metadata: { uri: '/resin/device(@id)?@id=1031543' },
},
],
})
.post(/device_environment_variable/)
.reply(200, 'OK');
const { out, err } = await runCommand(`env add TEST 1 -d ${deviceId}`);
chai.expect(out.join('')).to.equal('');
chai.expect(err.join('')).to.equal('');
// @ts-ignore
mock.remove();
});
});

17
tests/commands/env/rm.spec.ts vendored Normal file
View File

@ -0,0 +1,17 @@
import * as chai from 'chai';
import { balenaAPIMock, runCommand } from '../../helpers';
describe('balena env rm', function() {
it('should successfully delete an environment variable', async () => {
const mock = balenaAPIMock();
mock.delete(/device_environment_variable/).reply(200, 'OK');
const { out, err } = await runCommand('env rm 144690 -d -y');
chai.expect(out.join('')).to.equal('');
chai.expect(err.join('')).to.equal('');
// @ts-ignore
mock.remove();
});
});

137
tests/commands/help.spec.ts Normal file
View File

@ -0,0 +1,137 @@
import * as chai from 'chai';
import * as _ from 'lodash';
import { runCommand } from '../helpers';
const SIMPLE_HELP = `
Usage: balena [COMMAND] [OPTIONS]
If you need help, or just want to say hi, don't hesitate in reaching out
through our discussion and support forums at https://forums.balena.io
For bug reports or feature requests, have a look at the GitHub issues or
create a new one at: https://github.com/balena-io/balena-cli/issues/
Primary commands:
help [command...] show help
login login to balena
push <applicationOrDevice> Start a remote build on the balena cloud build servers or a local mode device
logs <uuidOrDevice> show device logs
ssh <applicationOrDevice> [serviceName] SSH into the host or application container of a device
apps list all applications
app <name> list a single application
devices list all devices
device <uuid> list a single device
tunnel <deviceOrApplication> Tunnel local ports to your balenaOS device
preload <image> preload an app on a disk image (or Edison zip archive)
build [source] Build a single image or a multicontainer project locally
deploy <appName> [image] Deploy a single image or a multicontainer project to a balena application
join [deviceIp] Promote a local device running balenaOS to join an application on a balena server
leave [deviceIp] Detach a local device from its balena application
scan Scan for balenaOS devices in your local network
`;
const ADDITIONAL_HELP = `
Additional commands:
api-key generate <name> Generate a new API key with the given name
app create <name> create an application
app restart <name> restart an application
app rm <name> remove an application
config generate generate a config.json file
config inject <file> inject a device configuration file
config read read a device configuration
config reconfigure reconfigure a provisioned device
config write <key> <value> write a device configuration
device identify <uuid> identify a device with a UUID
device init initialise a device with balenaOS
device move <uuid> move a device to another application
device os-update <uuid> Start a Host OS update for a device
device public-url <uuid> gets the public URL of a device
device public-url disable <uuid> disable public URL for a device
device public-url enable <uuid> enable public URL for a device
device public-url status <uuid> Returns true if public URL is enabled for a device
device reboot <uuid> restart a device
device register <application> register a device
device rename <uuid> [newName] rename a balena device
device rm <uuid> remove a device
device shutdown <uuid> shutdown a device
devices supported list all supported devices
env add name [value] add an environment or config variable to an application or device
env rename <id> <value> rename an environment variable
env rm id remove an environment variable from an application or device
envs list all environment variables
key <id> list a single ssh key
key add <name> [path] add a SSH key to balena
key rm <id> remove a ssh key
keys list all ssh keys
local configure <target> (Re)configure a balenaOS drive or image
local flash <image> Flash an image to a drive
logout logout from balena
note <|note> set a device note
os build-config <image> <device-type> build the OS config and save it to the JSON file
os configure <image> configure an os image
os download <type> download an unconfigured os image
os initialize <image> initialize an os image
os versions <type> show the available balenaOS versions for the given device type
settings print current settings
tag rm <tagKey> remove a resource tag
tag set <tagKey> [value] set a resource tag
tags list all resource tags
util available-drives list available drives
version display version information for the balena CLI and/or Node.js
whoami get current username and email address
`;
const GLOBAL_OPTIONS = `
Global Options:
--help, -h
--version, -v
`;
const cleanOutput = (output: string[] | string) => {
return _(_.castArray(output))
.map(log => {
return log.split('\n').map(line => {
return line.trim();
});
})
.flatten()
.compact()
.value();
};
describe('balena help', function() {
it('should print simple help text', async () => {
const { out, err } = await runCommand('help');
chai
.expect(cleanOutput(out))
.to.deep.equal(
cleanOutput([
SIMPLE_HELP,
'Run `balena help --verbose` to list additional commands',
GLOBAL_OPTIONS,
]),
);
chai.expect(err.join('')).to.equal('');
});
it('should print additional commands with the -v flag', async () => {
const { out, err } = await runCommand('help -v');
chai
.expect(cleanOutput(out))
.to.deep.equal(
cleanOutput([SIMPLE_HELP, ADDITIONAL_HELP, GLOBAL_OPTIONS]),
);
chai.expect(err.join('')).to.equal('');
chai.expect(err.join('')).to.equal('');
});
});

View File

@ -1,6 +1,6 @@
import * as chai from 'chai';
import * as fs from 'fs';
import { runCommand } from './helpers';
import { runCommand } from '../helpers';
const packageJSON = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
const nodeVersion = process.version.startsWith('v')

View File

@ -1,3 +1,4 @@
import * as nock from 'nock';
import * as path from 'path';
import * as balenaCLI from '../build/app';
@ -21,7 +22,12 @@ export const runCommand = async (cmd: string) => {
// @ts-ignore
process.stderr.write = (log: string) => {
// Skip over debug messages
if (!log.startsWith('[debug]')) {
if (
!log.startsWith('[debug]') &&
// TODO stop this warning message from appearing when running
// sdk.setSharedOptions multiple times in the same process
!log.startsWith('Shared SDK options')
) {
err.push(log);
}
oldStdErr(log);
@ -46,3 +52,17 @@ export const runCommand = async (cmd: string) => {
throw err;
}
};
export const balenaAPIMock = () => {
return nock(/./)
.get('/config/vars')
.reply(200, {
reservedNames: [],
reservedNamespaces: [],
invalidRegex: '/^d|W/',
whiteListedNames: [],
whiteListedNamespaces: [],
blackListedNames: [],
configVarSchema: [],
});
};