Skip to content

Commit fecb6da

Browse files
committed
Add more commands and cleanup
1 parent c714487 commit fecb6da

10 files changed

+287
-103
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
node_modules
2+
.vscode

.prettierrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"singleQuote": true}

Readme.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Twilio Runtime Serverless Plugin
2+
3+
This plugin enables Twilio Functions and Assets support within the Serverless Framework.
4+
5+
## Getting started
6+
7+
### Pre-requisites
8+
9+
- Node.js v8.10.0 (this is the runtime version supported by Azure Functions)
10+
- Serverless CLI v1.48.0+. You can run npm i -g serverless if you don't already have it.
11+
- A Twilio account. If you don't have one you can [sign up quickly](https://www.twilio.com/try-twilio).
12+
13+
### Create a new Twilio service
14+
15+
- Create a new service using the standard Node.js template, specifying a unique name for your app: `serverless create -t azure-nodejs -p <appName>`
16+
- `cd` into the generated app directory: `cd <appName>`
17+
- Install the app's NPM dependencies, which includes this plugin: `npm install`
18+
19+
### Deploy, test, and diagnose your Twilio runtime
20+
21+
1. Now that you have the service on your local machine you can deploy your service using the credentials you find in [the Twilio Console](https://www.twilio.com/console/).
22+
23+
### Supported commands
24+
25+
#### `serverless deploy`
26+
27+
Deploy all functions and assets defined in your `serverless.yml`
28+
29+
```
30+
serverless deploy
31+
```
32+
33+
Deploying of a single function is also supported using the `--function` or `-f` parameter.
34+
35+
```
36+
serverless deploy --function hello-world
37+
```
38+
39+
#### `serverless deploy`
40+
41+
Get information about the currently deployed runtime
42+
43+
```
44+
serverless info
45+
```

deploy/twilio-deploy-function.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const { logDeployedResources } = require('../util/log');
4+
const { getTwilioClient, getTwilioDeployConfig } = require('../util/util');
5+
const { validateIfFunctionExists } = require('../util/validate');
6+
7+
class TwilioDeploy {
8+
constructor(serverless, options) {
9+
this.serverless = serverless;
10+
this.options = options;
11+
12+
this.hooks = {
13+
'deploy:function:deploy': this.deployFunction.bind(this)
14+
};
15+
}
16+
17+
async deployFunction() {
18+
const serverless = this.serverless;
19+
const functionName = this.options.f || this.options.function;
20+
const twilioServerlessClient = getTwilioClient(serverless);
21+
22+
validateIfFunctionExists(serverless, functionName);
23+
24+
const config = await getTwilioDeployConfig(serverless, {
25+
deploySingleFunction: functionName
26+
});
27+
const result = await twilioServerlessClient.deployProject(config);
28+
29+
logDeployedResources(serverless, result);
30+
}
31+
}
32+
33+
module.exports = TwilioDeploy;

deploy/twilio-deploy.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
const { logDeployedResources } = require('../util/log');
4+
const { getTwilioClient, getTwilioDeployConfig } = require('../util/util');
5+
6+
class TwilioDeploy {
7+
constructor(serverless, options) {
8+
this.serverless = serverless;
9+
10+
this.hooks = {
11+
'deploy:deploy': this.deploy.bind(this)
12+
};
13+
}
14+
15+
async deploy() {
16+
const serverless = this.serverless;
17+
const twilioServerlessClient = getTwilioClient(serverless);
18+
const config = await getTwilioDeployConfig(serverless, { deployAll: true });
19+
const result = await twilioServerlessClient.deployProject(config);
20+
21+
logDeployedResources(serverless, result);
22+
}
23+
}
24+
25+
module.exports = TwilioDeploy;

index.js

Lines changed: 9 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,20 @@
11
'use strict';
22

33
const TwilioProvider = require('./provider/twilioProvider');
4-
const path = require('path');
5-
const {
6-
TwilioServerlessApiClient,
7-
utils
8-
} = require('@twilio-labs/serverless-api');
9-
const { readFile } = utils;
4+
const TwilioDeploy = require('./deploy/twilio-deploy');
5+
const TwilioDeployFunction = require('./deploy/twilio-deploy-function');
6+
const TwilioInfo = require('./info/twilio-info');
7+
const TwilioInvoke = require('./invoke/twilio-invoke');
108

119
class ServerlessPlugin {
12-
constructor(serverless, options) {
10+
constructor(serverless) {
1311
this.serverless = serverless;
14-
this.options = options;
1512
this.provider = this.serverless.setProvider('twilio', TwilioProvider);
1613

17-
this.commands = {
18-
deploy: {
19-
usage: 'Deploy Twilio functions and assets',
20-
lifecycleEvents: [],
21-
options: {
22-
sid: {
23-
usage:
24-
'Specify the environment you want to deploy ' +
25-
'(e.g. "--sid \'AC....\'" or "-s \'AC....\'")',
26-
required: true,
27-
shortcut: 's'
28-
},
29-
token: {
30-
usage:
31-
'Specify your Twilio auth token to deploy' +
32-
'(e.g. "--token \'a86....\'" or "-t \'a86....\'")',
33-
required: true,
34-
shortcut: 'auth'
35-
},
36-
env: {
37-
usage:
38-
'Specify the environment you want to deploy ' +
39-
'(e.g. "--env \'staging\'")'
40-
}
41-
}
42-
}
43-
};
44-
45-
this.hooks = {
46-
'deploy:deploy': this.deploy.bind(this)
47-
};
48-
}
49-
50-
async deploy() {
51-
const serverless = this.serverless;
52-
const { sid: accountSid, token: authToken } = serverless.variables.options;
53-
const twilioServerlessClient = new TwilioServerlessApiClient({
54-
accountSid,
55-
authToken
56-
});
57-
58-
const config = {
59-
env: serverless.service.provider.environmentVars,
60-
pkgJson: {
61-
dependencies: serverless.service.provider.dependencies
62-
},
63-
serviceName: serverless.service.service,
64-
functionsEnv: serverless.service.provider.environment || 'dev',
65-
assets: [],
66-
functions: [],
67-
overrideExistingService: true
68-
};
69-
70-
config.functions = await Promise.all(
71-
Object.entries(serverless.service.functions).map(
72-
async ([name, fnConfig]) => {
73-
let { access = 'public', path: fnPath, handler } = fnConfig;
74-
let content = await readFile(
75-
path.join(serverless.config.servicePath, `${handler}.js`)
76-
);
77-
78-
return { access, content, name, path: fnPath };
79-
}
80-
)
81-
);
82-
83-
config.assets = await Promise.all(
84-
Object.entries(serverless.service.resources.assets).map(
85-
async ([name, assetConfig]) => {
86-
let { access = 'public', path: assetPath } = assetConfig;
87-
let content = await readFile(
88-
path.join(serverless.config.servicePath, assetPath)
89-
);
90-
91-
return { access, content, name, path: assetPath };
92-
}
93-
)
94-
);
95-
96-
twilioServerlessClient.on('status-update', evt => {
97-
this.serverless.cli.log(evt.message);
98-
});
99-
100-
const result = await twilioServerlessClient.deployProject(config);
101-
102-
result.functionResources.forEach(fn =>
103-
this.serverless.cli.log(
104-
`Function available at: ${result.domain}${fn.path}`
105-
)
106-
);
107-
result.assetResources.forEach(asset =>
108-
this.serverless.cli.log(
109-
`Asset available at: ${result.domain}${asset.path}`
110-
)
111-
);
14+
this.serverless.pluginManager.addPlugin(TwilioDeploy);
15+
this.serverless.pluginManager.addPlugin(TwilioDeployFunction);
16+
this.serverless.pluginManager.addPlugin(TwilioInfo);
17+
this.serverless.pluginManager.addPlugin(TwilioInvoke);
11218
}
11319
}
11420

info/twilio-info.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
const { logMessage } = require('../util/log');
4+
5+
class TwilioInfo {
6+
constructor(serverless, options) {
7+
this.serverless = serverless;
8+
this.options = options;
9+
10+
this.hooks = {
11+
'info:info': this.logInfo.bind(this)
12+
};
13+
}
14+
15+
async logInfo() {
16+
logMessage(this.serverless, `'serverless info' is not yet implemented...`);
17+
}
18+
}
19+
20+
module.exports = TwilioInfo;

util/log.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
'use strict';
2+
3+
function logDeployedResources(serverless, result) {
4+
if (result.functionResources.length) {
5+
result.functionResources.forEach(fn =>
6+
logMessage(
7+
serverless,
8+
`Function available at: ${result.domain}${fn.path}`
9+
)
10+
);
11+
}
12+
13+
if (result.assetResources.length) {
14+
result.assetResources.forEach(asset =>
15+
logMessage(
16+
serverless,
17+
`Asset available at: ${result.domain}/${asset.path}`
18+
)
19+
);
20+
}
21+
}
22+
23+
function logMessage(serverless, message) {
24+
serverless.cli.log(`twilio-runtime: ${message}`);
25+
}
26+
27+
module.exports = {
28+
logDeployedResources,
29+
logMessage
30+
};

util/util.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
'use strict';
2+
3+
const {
4+
TwilioServerlessApiClient,
5+
utils
6+
} = require('@twilio-labs/serverless-api');
7+
const path = require('path');
8+
const { readFile } = utils;
9+
const { logMessage } = require('./log');
10+
11+
/**
12+
*
13+
* @param {*} serverless
14+
*/
15+
function getTwilioClient(serverless) {
16+
const { accountSid, authToken } = serverless.service.provider.config;
17+
18+
const client = new TwilioServerlessApiClient({
19+
accountSid,
20+
authToken
21+
});
22+
23+
client.on('status-update', evt => {
24+
logMessage(serverless, evt.message);
25+
});
26+
27+
return client;
28+
}
29+
30+
/**
31+
*
32+
* @param {*} serverless
33+
* @param {*} options
34+
*/
35+
async function getTwilioDeployConfig(serverless, options = {}) {
36+
const config = {
37+
env: serverless.service.provider.environmentVars,
38+
pkgJson: {
39+
dependencies: serverless.service.provider.dependencies
40+
},
41+
serviceName: serverless.service.service,
42+
functionsEnv: serverless.service.provider.environment || 'dev',
43+
assets: [],
44+
functions: [],
45+
overrideExistingService: true
46+
};
47+
48+
if (options.deployAll) {
49+
config.functions = await Promise.all(
50+
Object.entries(serverless.service.functions).map(
51+
async ([name, config]) =>
52+
await getFunctionResource(serverless, { name, config })
53+
)
54+
);
55+
56+
config.assets = await Promise.all(
57+
Object.entries(serverless.service.resources.assets).map(
58+
async ([name, config]) =>
59+
await getAssetResource(serverless, { name, config })
60+
)
61+
);
62+
} else if (options.deploySingleFunction) {
63+
config.functions = [
64+
await getFunctionResource(serverless, {
65+
name: options.deploySingleFunction,
66+
config: serverless.service.functions[options.deploySingleFunction]
67+
})
68+
];
69+
}
70+
71+
return config;
72+
}
73+
74+
/**
75+
*
76+
* @param {*} serverless
77+
* @param {*} param1
78+
*/
79+
async function getFunctionResource(serverless, { name, config }) {
80+
let { access = 'public', path: fnPath, handler } = config;
81+
let content = await readFile(
82+
path.join(serverless.config.servicePath, `${handler}.js`)
83+
);
84+
85+
return { access, content, name, path: fnPath };
86+
}
87+
88+
/**
89+
*
90+
* @param {*} serverless
91+
* @param {*} param1
92+
*/
93+
async function getAssetResource(serverless, { name, config }) {
94+
let { access = 'public', path: assetPath } = config;
95+
let content = await readFile(
96+
path.join(serverless.config.servicePath, assetPath)
97+
);
98+
99+
return { access, content, name, path: assetPath };
100+
}
101+
102+
module.exports = {
103+
getTwilioClient,
104+
getTwilioDeployConfig,
105+
readFile
106+
};

0 commit comments

Comments
 (0)