Add logged-in check for balena 'env' commands

Change-type: patch
Signed-off-by: Paulo Castro <paulo@balena.io>
This commit is contained in:
Paulo Castro 2019-12-05 15:34:35 +00:00
parent b1eda160e8
commit 630d53311a
8 changed files with 125 additions and 45 deletions

View File

@ -19,6 +19,7 @@ import { Command, flags } from '@oclif/command';
import { stripIndent } from 'common-tags';
import * as _ from 'lodash';
import { ExpectedError } from '../../errors';
import * as cf from '../../utils/common-flags';
import { CommandHelp } from '../../utils/oclif-utils';
@ -85,7 +86,9 @@ export default class EnvAddCmd extends Command {
);
const cmd = this;
const balena = (await import('balena-sdk')).fromSharedOptions();
const { exitWithExpectedError } = await import('../../utils/patterns');
const { checkLoggedIn } = await import('../../utils/patterns');
await checkLoggedIn();
if (params.value == null) {
params.value = process.env[params.name];
@ -120,7 +123,7 @@ export default class EnvAddCmd extends Command {
params.value,
);
} else {
exitWithExpectedError('You must specify an application or device');
throw new ExpectedError('You must specify an application or device');
}
}
}

View File

@ -82,6 +82,9 @@ export default class EnvRenameCmd extends Command {
EnvRenameCmd,
);
const balena = (await import('balena-sdk')).fromSharedOptions();
const { checkLoggedIn } = await import('../../utils/patterns');
await checkLoggedIn();
await balena.pine.patch({
resource: options.device

View File

@ -18,6 +18,7 @@
import { Command, flags } from '@oclif/command';
import { stripIndent } from 'common-tags';
import { ExpectedError } from '../../errors';
import { CommandHelp } from '../../utils/oclif-utils';
interface FlagsDef {
@ -91,15 +92,15 @@ export default class EnvRmCmd extends Command {
EnvRmCmd,
);
const balena = (await import('balena-sdk')).fromSharedOptions();
const patterns = await import('../../utils/patterns');
const { checkLoggedIn, confirm } = await import('../../utils/patterns');
await checkLoggedIn();
if (isNaN(params.id) || !Number.isInteger(Number(params.id))) {
patterns.exitWithExpectedError(
'The environment variable id must be an integer',
);
throw new ExpectedError('The environment variable id must be an integer');
}
await patterns.confirm(
await confirm(
options.yes || false,
'Are you sure you want to delete the environment variable?',
undefined,

View File

@ -19,6 +19,7 @@ import { ApplicationVariable, DeviceVariable } from 'balena-sdk';
import { stripIndent } from 'common-tags';
import * as _ from 'lodash';
import { ExpectedError } from '../errors';
import * as cf from '../utils/common-flags';
import { CommandHelp } from '../utils/oclif-utils';
@ -68,10 +69,12 @@ export default class EnvsCmd extends Command {
const { flags: options } = this.parse<FlagsDef, {}>(EnvsCmd);
const balena = (await import('balena-sdk')).fromSharedOptions();
const visuals = await import('resin-cli-visuals');
const { exitWithExpectedError } = await import('../utils/patterns');
const { checkLoggedIn } = await import('../utils/patterns');
const cmd = this;
let environmentVariables: ApplicationVariable[] | DeviceVariable[];
await checkLoggedIn();
if (options.application) {
environmentVariables = await balena.models.application[
options.config ? 'configVar' : 'envVar'
@ -81,11 +84,11 @@ export default class EnvsCmd extends Command {
options.config ? 'configVar' : 'envVar'
].getAllByDevice(options.device);
} else {
return exitWithExpectedError('You must specify an application or device');
throw new ExpectedError('You must specify an application or device');
}
if (_.isEmpty(environmentVariables)) {
return exitWithExpectedError('No environment variables found');
throw new ExpectedError('No environment variables found');
}
cmd.log(

View File

@ -51,6 +51,18 @@ class BalenaAPIMock {
nock.restore();
}
public expectTestDevice() {
this.scope.get(/\/v\d+\/device($|\?)/).reply(200, { d: [{ id: 7654321 }] });
}
public expectDeviceEnvVars() {
this.scope.post(/\/v\d+\/device_environment_variable($|\?)/).reply(201, {
id: 120203,
name: 'var3',
value: 'var3-val',
});
}
public expectConfigVars() {
this.scope.get('/config/vars').reply(200, {
reservedNames: [],
@ -65,8 +77,8 @@ class BalenaAPIMock {
// User details are cached in the SDK
// so often we don't know if we can expect the whoami request
public expectOptionalWhoAmI() {
this.scope
public expectOptionalWhoAmI(persist = false) {
(persist ? this.scope.persist() : this.scope)
.get('/user/v1/whoami')
.optionally()
.reply(200, {
@ -76,10 +88,10 @@ class BalenaAPIMock {
});
}
public expectMixpanel() {
this.scope.get(/^\/mixpanel\/track/).reply(200, {});
public expectMixpanel(optional = false) {
const get = this.scope.get(/^\/mixpanel\/track/);
(optional ? get.optionally() : get).reply(200, {});
}
protected handleUnexpectedRequest(req: any) {
console.error(`Unexpected http request!: ${req.path}`);
// Errors thrown here are not causing the tests to fail for some reason.

View File

@ -1,29 +1,48 @@
/**
* @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 { expect } from 'chai';
import { balenaAPIMock, runCommand } from '../../helpers';
import { BalenaAPIMock } from '../../balena-api-mock';
import { runCommand } from '../../helpers';
describe('balena env add', function() {
let api: BalenaAPIMock;
beforeEach(() => {
api = new BalenaAPIMock();
api.expectOptionalWhoAmI(true);
api.expectMixpanel(true);
});
afterEach(() => {
// Check all expected api calls have been made and clean up.
api.done();
});
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');
api.expectTestDevice();
api.expectConfigVars();
api.expectDeviceEnvVars();
const { out, err } = await runCommand(`env add TEST 1 -d ${deviceId}`);
expect(out.join('')).to.equal('');
expect(err.join('')).to.equal('');
// @ts-ignore
mock.remove();
});
});

View File

@ -16,19 +16,30 @@
*/
import { expect } from 'chai';
import { balenaAPIMock, runCommand } from '../../helpers';
import { BalenaAPIMock } from '../../balena-api-mock';
import { runCommand } from '../../helpers';
describe('balena env rename', function() {
let api: BalenaAPIMock;
beforeEach(() => {
api = new BalenaAPIMock();
api.expectOptionalWhoAmI(true);
api.expectMixpanel(true);
});
afterEach(() => {
// Check all expected api calls have been made and clean up.
api.done();
});
it('should successfully rename an environment variable', async () => {
const mock = balenaAPIMock();
mock.patch(/device_environment_variable\(376\)/).reply(200, 'OK');
api.scope.patch(/device_environment_variable\(376\)/).reply(200, 'OK');
const { out, err } = await runCommand('env rename 376 emacs --device');
expect(out.join('')).to.equal('');
expect(err.join('')).to.equal('');
// @ts-ignore
mock.remove();
});
});

View File

@ -1,17 +1,45 @@
/**
* @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 { expect } from 'chai';
import { balenaAPIMock, runCommand } from '../../helpers';
import { BalenaAPIMock } from '../../balena-api-mock';
import { runCommand } from '../../helpers';
describe('balena env rm', function() {
let api: BalenaAPIMock;
beforeEach(() => {
api = new BalenaAPIMock();
api.expectOptionalWhoAmI(true);
api.expectMixpanel(true);
});
afterEach(() => {
// Check all expected api calls have been made and clean up.
api.done();
});
it('should successfully delete an environment variable', async () => {
const mock = balenaAPIMock();
mock.delete(/device_environment_variable/).reply(200, 'OK');
api.scope.delete(/device_environment_variable/).reply(200, 'OK');
const { out, err } = await runCommand('env rm 144690 -d -y');
expect(out.join('')).to.equal('');
expect(err.join('')).to.equal('');
// @ts-ignore
mock.remove();
});
});