Skip to content

Commit 6be7f2d

Browse files
committed
add project structure and create function logic
0 parents  commit 6be7f2d

7 files changed

+351
-0
lines changed

.gitignore

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Created by .ignore support plugin (hsz.mobi)
2+
### Node template
3+
# Logs
4+
logs
5+
*.log
6+
npm-debug.log*
7+
8+
# Runtime data
9+
pids
10+
*.pid
11+
*.seed
12+
*.pid.lock
13+
14+
# Directory for instrumented libs generated by jscoverage/JSCover
15+
lib-cov
16+
17+
# Coverage directory used by tools like istanbul
18+
coverage
19+
20+
# nyc test coverage
21+
.nyc_output
22+
23+
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24+
.grunt
25+
26+
# node-waf configuration
27+
.lock-wscript
28+
29+
# Compiled binary addons (http://nodejs.org/api/addons.html)
30+
build/Release
31+
32+
# Dependency directories
33+
node_modules
34+
jspm_packages
35+
36+
# Optional npm cache directory
37+
.npm
38+
39+
# Optional eslint cache
40+
.eslintcache
41+
42+
# Optional REPL history
43+
.node_repl_history
44+
45+
# Output of 'npm pack'
46+
*.tgz
47+
48+
# Yarn Integrity file
49+
.yarn-integrity
50+
51+

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2017 SC5 Online Ltd
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

create-function.js

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const path = require('path');
5+
const fse = require('fs-extra');
6+
const yamlEdit = require('yaml-edit');
7+
const ejs = require('ejs');
8+
const functionTemplateFile = path.join('templates', 'function-template.ejs');
9+
10+
11+
const validFunctionRuntimes = [
12+
'aws-nodejs4.3',
13+
];
14+
15+
const createFunction = (serverless, options) => {
16+
serverless.cli.log('Generating function...');
17+
const functionName = options.function;
18+
const handler = options.handler;
19+
20+
const serverlessYmlFilePath = path
21+
.join(serverless.config.servicePath, 'serverless.yml');
22+
23+
const serverlessYmlFileContent = fse
24+
.readFileSync(serverlessYmlFilePath).toString();
25+
26+
return serverless.yamlParser.parse(serverlessYmlFilePath)
27+
.then((config) => {
28+
const runtime = [config.provider.name, config.provider.runtime].join('-');
29+
30+
if (validFunctionRuntimes.indexOf(runtime) < 0) {
31+
const errorMessage = [
32+
`Provider / Runtime "${runtime}" is not supported.`,
33+
` Supported runtimes are: ${humanReadableFunctionRuntimes}.`,
34+
].join('');
35+
throw new serverless.classes.Error(errorMessage);
36+
}
37+
38+
const ymlEditor = yamlEdit(serverlessYmlFileContent);
39+
40+
if (ymlEditor.hasKey(`functions.${functionName}`)) {
41+
const errorMessage = [
42+
`Function "${functionName}" already exists. Cannot create function.`,
43+
].join('');
44+
throw new serverless.classes.Error(errorMessage);
45+
}
46+
47+
const funcDoc = {};
48+
funcDoc[functionName] = serverless.service.functions[functionName] = {
49+
handler,
50+
};
51+
52+
if (ymlEditor.insertChild('functions', funcDoc)) {
53+
const errorMessage = [
54+
`Could not find functions in ${serverlessYmlFilePath}`,
55+
].join('');
56+
throw new serverless.classes.Error(errorMessage);
57+
}
58+
59+
fse.writeFileSync(serverlessYmlFilePath, ymlEditor.dump());
60+
61+
if (runtime === 'aws-nodejs4.3') {
62+
return createAWSNodeJSFuncFile(serverless, handler);
63+
}
64+
65+
return BbPromise.resolve();
66+
});
67+
};
68+
69+
const createAWSNodeJSFuncFile = (serverless, handlerPath) => {
70+
const handlerInfo = path.parse(handlerPath);
71+
const handlerDir = path.join(serverless.config.servicePath, handlerInfo.dir);
72+
const handlerFile = `${handlerInfo.name}.js`;
73+
const handlerFunction = handlerInfo.ext.replace(/^\./, '');
74+
let templateFile = path.join(__dirname, functionTemplateFile);
75+
76+
if (serverless.service.custom &&
77+
serverless.service.custom['serverless-mocha-plugin'] &&
78+
serverless.service.custom['serverless-mocha-plugin'].functionTemplate) {
79+
templateFile = path.join(serverless.config.servicePath,
80+
serverless.service.custom['serverless-mocha-plugin'].functionTemplate);
81+
}
82+
83+
const templateText = fse.readFileSync(templateFile).toString();
84+
const jsFile = ejs.render(templateText, {
85+
handlerFunction,
86+
});
87+
88+
const filePath = path.join(handlerDir, handlerFile);
89+
90+
serverless.utils.writeFileDir(filePath);
91+
if (serverless.utils.fileExistsSync(filePath)) {
92+
const errorMessage = [
93+
`File "${filePath}" already exists. Cannot create function.`,
94+
].join('');
95+
throw new serverless.classes.Error(errorMessage);
96+
}
97+
fse.writeFileSync(path.join(handlerDir, handlerFile), jsFile);
98+
99+
serverless.cli.log(`Created function file "${path.join(handlerDir, handlerFile)}"`);
100+
return BbPromise.resolve();
101+
}
102+
103+
module.exports = createFunction;

index.js

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
5+
const createFunction = require('./create-function');
6+
7+
class ServerlessJestPlugin {
8+
constructor(serverless, options) {
9+
this.serverless = serverless;
10+
this.options = options;
11+
this.commands = {
12+
create: {
13+
commands: {
14+
test: {
15+
usage: 'Create mocha tests for service / function',
16+
lifecycleEvents: [
17+
'test',
18+
],
19+
options: {
20+
function: {
21+
usage: 'Name of the function',
22+
shortcut: 'f',
23+
required: true,
24+
},
25+
path: {
26+
usage: 'Path for the tests',
27+
shortcut: 'p',
28+
},
29+
},
30+
},
31+
function: {
32+
usage: 'Create a function into the service',
33+
lifecycleEvents: [
34+
'create',
35+
],
36+
options: {
37+
function: {
38+
usage: 'Name of the function',
39+
shortcut: 'f',
40+
required: true,
41+
},
42+
handler: {
43+
usage: 'Handler for the function (e.g. --handler my-function/index.handler)',
44+
required: true,
45+
},
46+
path: {
47+
usage: 'Path for the tests (e.g. --path tests)',
48+
shortcut: 'p',
49+
},
50+
},
51+
},
52+
},
53+
},
54+
invoke: {
55+
usage: 'Invoke mocha tests for service / function',
56+
commands: {
57+
test: {
58+
usage: 'Invoke test(s)',
59+
lifecycleEvents: [
60+
'test',
61+
],
62+
options: {
63+
function: {
64+
usage: 'Name of the function',
65+
shortcut: 'f',
66+
},
67+
reporter: {
68+
usage: 'Mocha reporter to use',
69+
shortcut: 'R',
70+
},
71+
'reporter-options': {
72+
usage: 'Options for mocha reporter',
73+
shortcut: 'O',
74+
},
75+
path: {
76+
usage: 'Path for the tests for running tests in other than default "test" folder',
77+
},
78+
},
79+
},
80+
},
81+
},
82+
};
83+
84+
this.hooks = {
85+
'create:test:test': () => {
86+
BbPromise.bind(this)
87+
.then(this.createTest);
88+
},
89+
'invoke:test:test': () => {
90+
BbPromise.bind(this)
91+
.then(this.runTests);
92+
},
93+
'create:function:create': () => {
94+
BbPromise.bind(this)
95+
.then(() => createFunction(this.serverless, this.options))
96+
.then(this.createTest);
97+
},
98+
};
99+
}
100+
101+
runTests() {
102+
console.log('run tests');
103+
}
104+
105+
createTest() {
106+
console.log('create test');
107+
}
108+
}
109+
110+
module.exports = ServerlessJestPlugin;

package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "serverless-jest-plugin",
3+
"version": "0.1.0",
4+
"description": "Serverless plugin for test driven development using jest",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/laardee/serverless-jest-plugin.git"
12+
},
13+
"dependencies": {
14+
"bluebird": "^3.4.7",
15+
"ejs": "^2.5.5",
16+
"fs-extra": "^2.0.0",
17+
"yaml-edit": "^0.1.3"
18+
},
19+
"author": "",
20+
"license": "MIT",
21+
"bugs": {
22+
"url": "https://github.com/laardee/serverless-jest-plugin/issues"
23+
},
24+
"homepage": "https://github.com/laardee/serverless-jest-plugin#readme"
25+
}

templates/function-template.ejs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
module.exports.<%= handlerFunction %> = (event, context, callback) => {
4+
const response = {
5+
statusCode: 200,
6+
body: JSON.stringify({
7+
message: 'Go Serverless v1.0! Your function executed successfully!',
8+
input: event,
9+
}),
10+
};
11+
12+
callback(null, response);
13+
14+
// Use this code if you don't use the http event with the LAMBDA-PROXY integration
15+
// callback(null, { message: 'Go Serverless v1.0! Your function executed successfully!', event });
16+
};

templates/test-template.ejs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
// tests for <%= functionName %>
4+
// Generated by serverless-mocha-plugin
5+
6+
const mod = require('../<%= functionPath %>');
7+
const mochaPlugin = require('serverless-mocha-plugin');
8+
9+
const lambdaWrapper = mochaPlugin.lambdaWrapper;
10+
const expect = mochaPlugin.chai.expect;
11+
const wrapped = lambdaWrapper.wrap(mod, { handler: '<%= handlerName %>' });
12+
13+
describe('<%= functionName %>', () => {
14+
before((done) => {
15+
// lambdaWrapper.init(liveFunction); // Run the deployed lambda
16+
17+
done();
18+
});
19+
20+
it('implement tests here', () => {
21+
return wrapped.run({}).then((response) => {
22+
expect(response).to.not.be.empty;
23+
});
24+
});
25+
});

0 commit comments

Comments
 (0)