Skip to content

Commit

Permalink
Merge pull request #704 from particle-iot/feature/sc-124023/get-refactor
Browse files Browse the repository at this point in the history
Feature/sc 124023/get refactor
  • Loading branch information
hugomontero committed Dec 21, 2023
2 parents d5b4d3a + 4c248ff commit dd2dd19
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 44 deletions.
1 change: 1 addition & 0 deletions src/cli/logic-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module.exports = ({ commandProcessor, root }) => {
});

commandProcessor.createCommand(logicFunction, 'get', 'Downloads the logic function', {
params: '[filepath]',
options: {
'org': {
description: 'Specify the organization',
Expand Down
43 changes: 24 additions & 19 deletions src/cmd/logic-function.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,29 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {
// We assume at least one trigger
this.ui.stdout.write(`- ${item.name} (${item.enabled ? this.ui.chalk.cyanBright('enabled') : this.ui.chalk.cyan('disabled')})${os.EOL}`);
this.ui.stdout.write(` - ID: ${item.id}${os.EOL}`);
this.ui.stdout.write(` - ${item.logic_triggers[0].type} based trigger ${os.EOL}`);
this.ui.stdout.write(` - ${item.triggers[0].type} based trigger ${os.EOL}`);
});
this.ui.stdout.write(`${os.EOL}To view a Logic Function's code, see ${this.ui.chalk.yellow('particle logic-function get')}.${os.EOL}`);
}

async get({ org, name, id }) {
async get({ org, name, id, params : { filepath } } = { params: { } }) {
this._setOrg(org);
const logicFunctions = await LogicFunction.listFromCloud({ org, api: this.api });
if (!name && !id) {
name = await this._selectLogicFunctionName(logicFunctions);
}
const logicFunction = await LogicFunction.getByIdOrName({ org, id, name, list: logicFunctions });
logicFunction.path = filepath;

await this._getLogicFunctionList();

({ name, id } = await this._getLogicFunctionIdAndName(name, id));

const logicFunctionData = await this._getLogicFunctionData(id);

const { logicFunctionConfigData, logicFunctionCode } = this._serializeLogicFunction(logicFunctionData);

const { jsonPath, jsPath } = await this._generateFiles({ logicFunctionConfigData, logicFunctionCode, name });

this._printGetOutput({ jsonPath, jsPath });
// check if the files already exists
await this._confirmOverwriteIfNeeded({
filePaths: [logicFunction.configurationPath, logicFunction.sourcePath],
});
await logicFunction.saveToDisk();
this._printGetOutput({
jsonPath: logicFunction.configurationPath,
jsPath: logicFunction.sourcePath
});
this._printGetHelperOutput();
}

Expand Down Expand Up @@ -168,9 +172,9 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {

// Prompts the user to overwrite if any files exist
// If user says no, we exit the process
async _validatePaths({ jsonPath, jsPath, _exit = () => process.exit(0) }) {
async _confirmOverwriteIfNeeded({ filePaths, _exit = () => process.exit(0) }) {
let exists = false;
const pathsToCheck = [jsonPath, jsPath];
const pathsToCheck = filePaths;
for (const p of pathsToCheck) {
if (await fs.pathExists(p)) {
exists = true;
Expand Down Expand Up @@ -452,7 +456,7 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {
async _overwriteIfLFExistsLocally(name, id) {
const { jsonPath, jsPath } = this._getLocalLFPathNames(name);

const exist = await this._validatePaths({ jsonPath, jsPath });
const exist = await this._confirmOverwriteIfNeeded({ filePaths: { jsonPath, jsPath } });

if (!exist) {
return;
Expand Down Expand Up @@ -551,7 +555,7 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {
async _generateFiles({ logicFunctionConfigData, logicFunctionCode, name }) {
const { jsonPath, jsPath } = this._getLocalLFPathNames(name);

await this._validatePaths({ jsonPath, jsPath });
await this._confirmOverwriteIfNeeded({ filePaths: { jsonPath, jsPath } });

await fs.writeFile(jsonPath, JSON.stringify(logicFunctionConfigData, null, 2));
await fs.writeFile(jsPath, logicFunctionCode);
Expand All @@ -569,7 +573,7 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {

async _getLogicFunctionIdAndName(name, id) {
if (!id && !name) {
name = await this._selectLogicFunction(this.logicFuncList);
name = await this._selectLogicFunctionName(this.logicFuncList);
id = this._getIdFromName(name, this.logicFuncList);
} else if (!id && name) {
id = this._getIdFromName(name, this.logicFuncList);
Expand All @@ -580,8 +584,9 @@ module.exports = class LogicFunctionsCommand extends CLICommandBase {
return { name, id };
}

async _selectLogicFunction(list) {
async _selectLogicFunctionName(list) {
if (list.length === 0) {
this._printListHelperOutput();
throw new Error('No logic functions found');
}
const answer = await this._prompt({
Expand Down
93 changes: 86 additions & 7 deletions src/cmd/logic-function.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ describe('LogicFunctionCommands', () => {
});

describe('list', () => {
beforeEach(() => {
logicFunc1.logic_functions.forEach((lf) => {
lf.triggers = lf.logic_triggers;
});
});

it('lists logic functions in Sandbox account', async () => {

const logicListStub = sinon.stub(LogicFunction, 'listFromCloud').resolves(logicFunc1.logic_functions);
await logicFunctionCommands.list({});
expect(logicListStub.calledWith({ api: logicFunctionCommands.api, org: undefined })).to.be.true;
Expand Down Expand Up @@ -95,6 +102,75 @@ describe('LogicFunctionCommands', () => {

});

describe('get', () => {
let lf;

beforeEach(() => {
lf = new LogicFunction({
name: 'LF1',
description: 'Logic Function 1',
id: '0021e8f4-64ee-416d-83f3-898aa909fb1b',
});
lf.fileNames = {
sourceCode: 'code.js',
configuration: 'config.json'
};
});

it('gets a logic function with an specific name from Sandbox account', async () => {
const logicGetStub = sinon.stub(LogicFunction, 'getByIdOrName').resolves(lf);
lf.saveToDisk = sinon.stub().resolves(true);
sinon.stub(LogicFunction, 'listFromCloud').resolves(logicFunc1.logic_functions);
await logicFunctionCommands.get({ name: 'LF1', params: {} });
expect(logicGetStub.calledWith({ org: undefined, id: undefined, name: 'LF1', list: logicFunc1.logic_functions })).to.be.true;
expect(logicGetStub.calledOnce).to.be.true;
expect(lf.saveToDisk.calledOnce).to.be.true;
expect(logicFunctionCommands.ui.stdout.write.callCount).to.equal(6);
expect(logicFunctionCommands.ui.stdout.write.getCall(2).args[0]).to.equal(` - ${lf.fileNames.configuration}${os.EOL}`);
expect(logicFunctionCommands.ui.stdout.write.getCall(3).args[0]).to.equal(` - ${lf.fileNames.sourceCode}${os.EOL}`);
});
it('gets a logic function with an specific id from Sandbox account', async () => {
const logicGetStub = sinon.stub(LogicFunction, 'getByIdOrName').resolves(lf);
lf.saveToDisk = sinon.stub().resolves(true);
sinon.stub(LogicFunction, 'listFromCloud').resolves(logicFunc1.logic_functions);
await logicFunctionCommands.get({ id: '0021e8f4-64ee-416d-83f3-898aa909fb1b', params: {} });
expect(logicGetStub.calledWith({ org: undefined, id: '0021e8f4-64ee-416d-83f3-898aa909fb1b', name: undefined, list: logicFunc1.logic_functions })).to.be.true;
expect(logicGetStub.calledOnce).to.be.true;
expect(lf.saveToDisk.calledOnce).to.be.true;
expect(logicFunctionCommands.ui.stdout.write.callCount).to.equal(6);
expect(logicFunctionCommands.ui.stdout.write.getCall(2).args[0]).to.equal(` - ${lf.fileNames.configuration}${os.EOL}`);
expect(logicFunctionCommands.ui.stdout.write.getCall(3).args[0]).to.equal(` - ${lf.fileNames.sourceCode}${os.EOL}`);

});
it('shows error if logic function is not found', async () => {
const logicGetStub = sinon.stub(LogicFunction, 'getByIdOrName').rejects(new Error('Logic function not found'));
lf.saveToDisk = sinon.stub().resolves(true);
sinon.stub(LogicFunction, 'listFromCloud').resolves(logicFunc1.logic_functions);
let error;
try {
await logicFunctionCommands.get({ name: 'LF3', params: {} });
} catch (e) {
error = e;
}
expect(logicGetStub.calledWith({ org: undefined, id: undefined, name: 'LF3', list: logicFunc1.logic_functions })).to.be.true;
expect(error).to.be.an.instanceOf(Error);
expect(error.message).to.equal('Logic function not found');
});

it('gets a logic function with an specific name from an org', async () => {
const logicGetStub = sinon.stub(LogicFunction, 'getByIdOrName').resolves(lf);
lf.saveToDisk = sinon.stub().resolves(true);
sinon.stub(LogicFunction, 'listFromCloud').resolves(logicFunc1.logic_functions);
await logicFunctionCommands.get({ name: 'LF1', org: 'particle', params: {} });
expect(logicGetStub.calledWith({ org: 'particle', id: undefined, name: 'LF1', list: logicFunc1.logic_functions })).to.be.true;
expect(logicGetStub.calledOnce).to.be.true;
expect(lf.saveToDisk.calledOnce).to.be.true;
expect(logicFunctionCommands.ui.stdout.write.callCount).to.equal(6);
expect(logicFunctionCommands.ui.stdout.write.getCall(2).args[0]).to.equal(` - ${lf.fileNames.configuration}${os.EOL}`);
expect(logicFunctionCommands.ui.stdout.write.getCall(3).args[0]).to.equal(` - ${lf.fileNames.sourceCode}${os.EOL}`);
});
});

describe('_getLogicFunctionList', () => {
it('lists logic functions in Sandbox', async () => {
nock('https://api.particle.io/v1', )
Expand Down Expand Up @@ -207,7 +283,7 @@ describe('LogicFunctionCommands', () => {
const data = { logic_function : logicFunc1.logic_functions[0] };
const logicFunctionCode = data.logic_function.source.code;
const logicFunctionConfigData = data.logic_function;
sinon.stub(logicFunctionCommands, '_validatePaths').resolves(true);
sinon.stub(logicFunctionCommands, '_confirmOverwriteIfNeeded').resolves(true);
const name = 'LF1';
const slugName = slugify(name);

Expand Down Expand Up @@ -376,7 +452,10 @@ describe('LogicFunctionCommands', () => {
it('returns if paths do not exist', async () => {
sinon.stub(fs, 'pathExists').resolves(false);

const res = await logicFunctionCommands._validatePaths({ jsonPath: 'dir/path/to/file', _exit: sinon.stub() });
const res = await logicFunctionCommands._confirmOverwriteIfNeeded({
filePaths: ['dir/path/to/file'],
_exit: sinon.stub()
});

expect(res).to.eql(false);

Expand All @@ -387,7 +466,7 @@ describe('LogicFunctionCommands', () => {
sinon.stub(fs, 'pathExists').resolves(true);
sinon.stub(logicFunctionCommands, '_promptOverwrite').resolves(false);

await logicFunctionCommands._validatePaths({ jsonPath: 'dir/path/to/file', _exit: exitStub });
await logicFunctionCommands._confirmOverwriteIfNeeded({ filePaths: ['dir/path/to/file'], _exit: exitStub });

expect(logicFunctionCommands._promptOverwrite.callCount).to.eql(1);
expect(exitStub.callCount).to.eql(1);
Expand All @@ -398,7 +477,7 @@ describe('LogicFunctionCommands', () => {
sinon.stub(logicFunctionCommands, '_promptOverwrite').resolves(true);
const paths = ['dir/', 'dir/path/to/file'];

const res = await logicFunctionCommands._validatePaths({ paths });
const res = await logicFunctionCommands._confirmOverwriteIfNeeded({ filePaths: paths });

expect(res).to.eql(true);

Expand Down Expand Up @@ -555,14 +634,14 @@ describe('LogicFunctionCommands', () => {

});

describe('_selectLogicFunction', () => {
describe('_selectLogicFunctionName', () => {
it('selects logic function from a list', async () => {
const logicFunctions = ['logicFunc1', 'logicFunc2'];
const selectedLF = 'logicFunc2';
const promptStub = sinon.stub(logicFunctionCommands, '_prompt');
promptStub.resolves({ logic_function: selectedLF });

const res = await logicFunctionCommands._selectLogicFunction(logicFunctions);
const res = await logicFunctionCommands._selectLogicFunctionName(logicFunctions);

expect(res).to.eql(selectedLF);
sinon.assert.calledOnceWithExactly(promptStub, {
Expand All @@ -579,7 +658,7 @@ describe('LogicFunctionCommands', () => {

let error;
try {
await logicFunctionCommands._selectLogicFunction(logicFunctions);
await logicFunctionCommands._selectLogicFunctionName(logicFunctions);
} catch (_e) {
error = _e;
}
Expand Down
Loading

0 comments on commit dd2dd19

Please sign in to comment.