mirror of
https://github.com/serverless/serverless.git
synced 2026-01-25 15:07:39 +00:00
Refactored event.json loading code to be a call to a central function as opposed to duplicating the same code. See _loadTestEvent on line 159 and line 72 Referenced absolute path to event.json file in order to correctly load the file. See 162.
201 lines
5.0 KiB
JavaScript
201 lines
5.0 KiB
JavaScript
'use strict';
|
||
|
||
/**
|
||
* Action: FunctionRun
|
||
* - Runs the function in the CWD for local testing
|
||
*/
|
||
|
||
const SPlugin = require('../ServerlessPlugin'),
|
||
SError = require('../ServerlessError'),
|
||
SUtils = require('../utils'),
|
||
BbPromise = require('bluebird'),
|
||
path = require('path'),
|
||
fs = require('fs');
|
||
|
||
BbPromise.promisifyAll(fs);
|
||
|
||
/**
|
||
* FunctionRun Class
|
||
*/
|
||
|
||
class FunctionRun extends SPlugin {
|
||
|
||
constructor(S, config) {
|
||
super(S, config);
|
||
}
|
||
|
||
static getName() {
|
||
return 'serverless.core.' + FunctionRun.name;
|
||
}
|
||
|
||
registerActions() {
|
||
this.S.addAction(this.functionRun.bind(this), {
|
||
handler: 'functionRun',
|
||
description: `Runs the service locally. Reads the service’s runtime and passes it off to a runtime-specific runner`,
|
||
context: 'function',
|
||
contextAction: 'run',
|
||
options: [
|
||
{
|
||
option: 'name',
|
||
shortcut: 'n',
|
||
description: 'Optional - Run a specific function by name in the current working directory'
|
||
}, {
|
||
option: 'path',
|
||
shortcut: 'p',
|
||
description: 'Optional - Run a specific function by path in the current working directory'
|
||
}
|
||
],
|
||
});
|
||
return BbPromise.resolve();
|
||
}
|
||
|
||
/**
|
||
* Action
|
||
*/
|
||
|
||
functionRun(evt) {
|
||
|
||
let _this = this;
|
||
|
||
// If CLI, parse options
|
||
if (_this.S.cli) {
|
||
|
||
// Options
|
||
evt = JSON.parse(JSON.stringify(this.S.cli.options)); // Important: Clone objects, don't refer to them
|
||
|
||
// Option - Non-interactive
|
||
if (_this.S.cli.options.nonInteractive) _this.S._interactive = false
|
||
}
|
||
|
||
return _this._loadFunction(evt)
|
||
.bind(_this)
|
||
.then(_this._loadTestEvent)
|
||
.then(_this._runFunction)
|
||
.then(function(evt) {
|
||
return evt;
|
||
})
|
||
}
|
||
|
||
/**
|
||
* Load Function
|
||
*/
|
||
|
||
_loadFunction(evt) {
|
||
|
||
let _this = this,
|
||
cwd = process.cwd();
|
||
|
||
// If "path" is provided, find function by path
|
||
if (evt.path) {
|
||
|
||
return SUtils.getFunctions(_this.S._projectRootPath, [evt.path])
|
||
.then(function(functions) {
|
||
|
||
// If no functions found, throw error
|
||
if (!functions.length) {
|
||
throw new SError(`Could not find a function with the path: ${evt.path}`);
|
||
}
|
||
|
||
// Load event object
|
||
evt.function = functions[0];
|
||
|
||
// Return
|
||
return evt;
|
||
});
|
||
}
|
||
|
||
// If "name" is provided, find function by name
|
||
if (evt.name) {
|
||
|
||
return SUtils.getFunctions(_this.S._projectRootPath, null)
|
||
.then(function(functions) {
|
||
|
||
// If no functions found, throw error
|
||
if (!functions.length) {
|
||
throw new SError(`Your project has no functions`);
|
||
}
|
||
|
||
// Add function to evt
|
||
for (let i = 0; i < functions.length; i++) {
|
||
SUtils.sDebug(functions[i].name+" :: "+evt.name);
|
||
|
||
if (functions[i].name === evt.name || functions[i].name.toLowerCase() === evt.name) {
|
||
evt.function = functions[i];
|
||
}
|
||
}
|
||
if (!evt.function) throw new SError(`Could not find a function with the name ${evt.name}`);
|
||
|
||
// Return
|
||
return evt;
|
||
});
|
||
}
|
||
|
||
// If interactive and no function name or path provided, show select screen
|
||
if (_this.S.cli && _this.S._interactive) {
|
||
|
||
// Otherwise show select screen
|
||
return _this.cliPromptSelectFunctions(cwd, 'Select a function to run: ', false, true)
|
||
.then(function (selected) {
|
||
|
||
// If no functions found, throw error
|
||
if (!selected.length) {
|
||
throw new SError(`Could not find any functions.`);
|
||
}
|
||
|
||
evt.function = selected[0];
|
||
|
||
return evt;
|
||
});
|
||
}
|
||
|
||
// Otherwise, through error
|
||
throw new SError(`No function specified`);
|
||
}
|
||
|
||
/**
|
||
* Populate the test event from the correct event.json file
|
||
*/
|
||
|
||
_loadTestEvent(evt) {
|
||
|
||
let _this = this,
|
||
eventPath = path.join(_this.S._projectRootPath, evt.function.pathFunction.replace('s-function.json', ''), 'event.json');
|
||
|
||
if (fs.existsSync(eventPath)) {
|
||
evt.function.event = SUtils.readAndParseJsonSync(eventPath);
|
||
} else {
|
||
evt.function.event = {};
|
||
}
|
||
|
||
return evt;
|
||
}
|
||
|
||
/**
|
||
* Run Function By Runtime
|
||
*/
|
||
|
||
_runFunction(evt) {
|
||
|
||
let _this = this;
|
||
|
||
// Look for a property named after the function in the event object
|
||
if (evt.function.event[evt.function.name]) evt.function.event = evt.function.event[evt.function.name];
|
||
|
||
// Run by runtime
|
||
if (evt.function.module.runtime === 'nodejs') {
|
||
|
||
// Fire NodeJs subaction
|
||
let newEvent = {
|
||
function: evt.function,
|
||
};
|
||
|
||
return _this.S.actions.functionRunLambdaNodeJs(newEvent)
|
||
.then(function(evt) {
|
||
return evt;
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = FunctionRun;
|