Skip to content
This repository has been archived by the owner on Jul 2, 2020. It is now read-only.

feat: add create plugin #26

Merged
merged 5 commits into from
Jan 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions packages/faas-cli-plugin-create/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "@midwayjs/fcli-plugin-create",
"version": "0.2.10",
"main": "dist/index",
"typings": "dist/index.d.ts",
"dependencies": {
"@midwayjs/fcli-command-core": "^0.2.10",
"enquirer": "^2.3.4",
"light-generator": "^1.3.2"
},
"devDependencies": {
"midway-bin": "1"
},
"files": [
"src",
"dist"
],
"scripts": {
"build": "npm run lint && midway-bin build -c",
"lint": "../../node_modules/.bin/tslint --format prose -c ../../tslint.json src/**/*.ts test/**/*.ts",
"test": "NODE_ENV=test midway-bin test --ts --full-trace",
"debug": "npm run lint && NODE_ENV=test midway-bin test --ts --full-trace --inspect-brk=9229",
"cov": "NODE_ENV=unittest midway-bin cov --ts",
"clean": "midway-bin clean",
"autod": "midway-bin autod"
},
"gitHead": "b67e2753cbdcc91813067ba2a1bb1ce7e85a3dff"
}
162 changes: 162 additions & 0 deletions packages/faas-cli-plugin-create/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { BasePlugin } from '@midwayjs/fcli-command-core';
import { join } from 'path';
const templateList = require('./list');
const { LightGenerator } = require('light-generator');
const { Select, Input, Form } = require('enquirer');

async function sleep(timeout) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, timeout);
});
}

// class wide constants
const validTemplates = Object.keys(templateList);
const humanReadableTemplateList = `${validTemplates
.slice(0, -1)
.map(template => `"${template}"`)
.join(', ')} and "${validTemplates.slice(-1)}"`;

export class CreatePlugin extends BasePlugin {
core: any;
options: any;
servicePath = this.core.config.servicePath;
showPrompt = true;
npmClient = 'npm';
_innerPrompt;

set prompt(value) {
const originRun = value.run;
value.run = async () => {
await this.beforePromptSubmit();
return originRun.call(value);
};
this._innerPrompt = value;
}

get prompt() {
return this._innerPrompt;
}

commands = {
create: {
usage: 'Create new Ali FaaS service',
lifecycleEvents: ['create'],
options: {
template: {
usage: `Template for the service. Available templates: ${humanReadableTemplateList}`,
shortcut: 't',
},
path: {
usage:
'The path where the service should be created (e.g. --path my-service)',
shortcut: 'p',
},
},
},
};

hooks = {
'create:create': this.create.bind(this),
};

async beforePromptSubmit() {}

async create() {
this.core.cli.log('Generating boilerplate...');

if (this.options['template']) {
await this.createFromTemplate();
} else {
this.prompt = new Select({
name: 'templateName',
message: 'Hello, traveller.\n Which template do you like?',
choices: Object.keys(templateList).map(template => {
return `${template} - ${templateList[template].desc}`;
}),
result: value => {
return value.split(' - ')[0];
},
show: this.showPrompt,
});

this.options.template = await this.prompt.run();
await this.createFromTemplate();
}
// done
this.printUsage();
}

async createFromTemplate() {
if (!this.options.path) {
this.prompt = new Input({
message: `The directory where the service should be created`,
initial: 'my_new_serverless',
show: this.showPrompt,
});
const targetPath = await this.prompt.run();
this.options.path = targetPath;
}

const boilerplatePath = this.options.path || '';
const newPath = join(this.servicePath, boilerplatePath);
const lightGenerator = new LightGenerator();
const generator = lightGenerator.defineNpmPackage({
npmClient: this.npmClient,
npmPackage: templateList[this.options.template].package,
targetPath: newPath,
});

const args = await generator.getParameterList();
const argsKeys = Object.keys(args);
if (argsKeys && argsKeys.length) {
this.prompt = new Form({
name: 'user',
message: 'Please provide the following information:',
choices: argsKeys.map(argsKey => {
return {
name: `${argsKey}`,
message: `${args[argsKey].desc}`,
initial: `${args[argsKey].default}`,
};
}),
show: this.showPrompt,
});
const parameters = await this.prompt.run();
await this.readyGenerate();
await generator.run(parameters);
} else {
await this.readyGenerate();
await generator.run();
}
this.core.cli.log(
`Successfully generated boilerplate for template: "${this.options.template}"`
);
this.core.cli.log();
}

async readyGenerate() {
this.core.cli.log();
await sleep(1000);
this.core.cli.log('1...');
await sleep(1000);
this.core.cli.log('2...');
await sleep(1000);
this.core.cli.log('3...');
await sleep(1000);
this.core.cli.log('Enjoy it...');
this.core.cli.log();
}

printUsage() {
this.core.cli.log(`Usage:
- cd ${this.options.path}
- ${this.npmClient} install
- ${this.npmClient} run test
- and read README.md
`);
this.core.cli.log('Document: https://midwayjs.org/faas');
}
}
10 changes: 10 additions & 0 deletions packages/faas-cli-plugin-create/src/list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"faas-standard": {
"desc": "A serverless boilerplate for aliyun fc, tecent scf and so on",
"package": "@midwayjs/faas-boilerplate-standard"
},
"faas-layer": {
"desc": "A serverless runtime layer boilerplate",
"package": "@midwayjs/faas-boilerplate-layer"
}
}
43 changes: 43 additions & 0 deletions packages/faas-cli-plugin-create/test/create.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { CommandHookCore, loadSpec } from '@midwayjs/fcli-command-core';
import { join } from 'path';
import { remove, existsSync, readFileSync } from 'fs-extra';
import { TestCreatePlugin } from './helper';
import * as assert from 'assert';

describe('/test/create.test.ts', () => {
const baseDir = join(__dirname, './tmp');
beforeEach(async () => {
if (existsSync(baseDir)) {
await remove(baseDir);
}
});
it('base create faas boilerplate', async () => {
const core = new CommandHookCore({
config: {
servicePath: baseDir,
},
commands: ['create'],
service: loadSpec(baseDir),
provider: 'aliyun',
options: {
template: 'faas-standard',
path: 'my_serverless',
},
log: console,
});
core.addPlugin(TestCreatePlugin);
await core.ready();
await core.invoke(['create']);
assert(existsSync(join(baseDir, 'my_serverless/f.yml')));
assert(existsSync(join(baseDir, 'my_serverless/src')));
assert(existsSync(join(baseDir, 'my_serverless/test')));
assert(existsSync(join(baseDir, 'my_serverless/tsconfig.json')));
assert(existsSync(join(baseDir, 'my_serverless/package.json')));
const contents = readFileSync(
join(baseDir, 'my_serverless/f.yml'),
'utf-8'
);
assert(/serverless-hello-world/.test(contents));
await remove(baseDir);
});
});
34 changes: 34 additions & 0 deletions packages/faas-cli-plugin-create/test/helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { CreatePlugin } from '../src';

export class TestCreatePlugin extends CreatePlugin {
// showPrompt = false;
promptAction;

mockPrompt(arr) {
this.promptAction = arr;
}

async beforePromptSubmit() {
this.prompt.once('prompt', async () => {
const value = this.promptAction.shift();
if (value) {
for (const flag of value) {
if (Array.isArray(flag)) {
await this.prompt.keypress.apply(this.prompt, flag);
} else if (typeof flag === 'string') {
try {
for (const key of flag.split('')) {
await this.prompt.keypress(key);
}
} catch (err) {
console.error(err);
}
}
}
}

await this.prompt.submit();
this.prompt.close();
});
}
}
22 changes: 22 additions & 0 deletions packages/faas-cli-plugin-create/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compileOnSave": true,
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"moduleResolution": "node",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"inlineSourceMap":true,
"noImplicitThis": true,
"noUnusedLocals": true,
"stripInternal": true,
"pretty": true,
"declaration": true,
"outDir": "dist"
},
"exclude": [
"dist",
"node_modules",
"test"
]
}
3 changes: 2 additions & 1 deletion packages/faas-cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
"@midwayjs/fcli-plugin-fc": "^0.2.10",
"@midwayjs/fcli-plugin-invoke": "^0.2.10",
"@midwayjs/fcli-plugin-package": "^0.2.10",
"@midwayjs/fcli-plugin-test": "^0.2.10"
"@midwayjs/fcli-plugin-test": "^0.2.10",
"@midwayjs/fcli-plugin-create": "^0.2.10"
},
"bin": {
"mf": "bin/fun.js",
Expand Down
2 changes: 2 additions & 0 deletions packages/faas-cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { InvokePlugin } from '@midwayjs/fcli-plugin-invoke';
import { PackagePlugin } from '@midwayjs/fcli-plugin-package';
import { DeployPlugin } from '@midwayjs/fcli-plugin-deploy';
import { AliyunFCPlugin } from '@midwayjs/fcli-plugin-fc';
import { CreatePlugin } from '@midwayjs/fcli-plugin-create';

export class CLI extends BaseCLI {
loadDefaultPlugin() {
this.core.addPlugin(CreatePlugin);
this.core.addPlugin(InvokePlugin);
this.core.addPlugin(TestPlugin);
this.core.addPlugin(PackagePlugin);
Expand Down