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

Commit

Permalink
feat: add create plugin (#26)
Browse files Browse the repository at this point in the history
* chore: fix boilerplate

* chore: add create cmd

* chore: add create cmd

* test: fix case

* chore: clean code
  • Loading branch information
czy88840616 committed Jan 20, 2020
1 parent 1e6fe24 commit ee445dd
Show file tree
Hide file tree
Showing 8 changed files with 303 additions and 1 deletion.
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

0 comments on commit ee445dd

Please sign in to comment.