Skip to content

Commit f8b71c7

Browse files
authored
Pass options to handler (#8)
* Pass options to handler function * Update README.md for options in handler function * Update promise handling * General rewriting * Update JS module exports
1 parent 5c8f6f0 commit f8b71c7

File tree

9 files changed

+119
-76
lines changed

9 files changed

+119
-76
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ custom:
3636
Based on the configuration above the plugin will search for a file `scripts/output.js` with the following content:
3737

3838
```js
39-
function handler (data, serverless) {
39+
function handler (data, serverless, options) {
4040
console.log('Received Stack Output', data)
4141
}
4242

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
"description": "Serverless plugin to process AWS CloudFormation Stack Output",
44
"license": "MIT",
55
"author": "Sebastian Müller <[email protected]>",
6-
"main": "dist/plugin.js",
6+
"main": "dist",
77
"scripts": {
8+
"clean": "rimraf dist",
89
"test": "jest",
910
"test:cover": "jest --coverage",
1011
"coveralls": "cat ./coverage/lcov.info | coveralls",
1112
"lint": "tslint {src,test}/**/*.ts",
13+
"prebuild": "yarn clean",
1214
"build": "tsc"
1315
},
1416
"repository": {
@@ -32,13 +34,14 @@
3234
"yamljs": "^0.3.0"
3335
},
3436
"devDependencies": {
35-
"sinon": "^2.3.6",
36-
"jasmine-data-provider": "^2.2.0",
3737
"@types/jest": "^20.0.5",
3838
"@types/node": "^8.0.19",
3939
"coveralls": "^2.13.1",
4040
"dot-json": "^1.0.3",
41+
"jasmine-data-provider": "^2.2.0",
4142
"jest": "^20.0.4",
43+
"rimraf": "^2.6.2",
44+
"sinon": "^2.3.6",
4245
"ts-jest": "^20.0.7",
4346
"tslint": "^5.5.0",
4447
"typescript": "^2.4.2"

src/file.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import * as fs from 'fs'
22

33
export default class StackOutputFile {
4-
constructor (private path: string) { }
4+
constructor (
5+
public path: string
6+
) { }
57

6-
public format (data: {}) {
8+
public format (data: object) {
79
const ext = this.path.split('.').pop() || ''
810

911
switch (ext.toUpperCase()) {
@@ -19,13 +21,15 @@ export default class StackOutputFile {
1921
}
2022
}
2123

22-
public save (data: {}) {
24+
public save (data: object) {
2325
const content = this.format(data)
2426

2527
try {
2628
fs.writeFileSync(this.path, content)
2729
} catch (e) {
2830
throw new Error('Cannot write to file: ' + this.path)
2931
}
32+
33+
return Promise.resolve()
3034
}
3135
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Plugin from './plugin'
2+
3+
module.exports = Plugin

src/plugin.ts

Lines changed: 61 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
1-
import * as assert from 'assert'
2-
import * as util from 'util'
1+
import * as assert from 'assert'
2+
import * as util from 'util'
33

44
import StackOutputFile from './file'
55

6-
class StackOutputPlugin {
6+
export default class StackOutputPlugin {
77
public hooks: {}
88
private output: OutputConfig
99

10-
constructor (private serverless: Serverless, private options: Serverless.Options) {
10+
constructor (
11+
private serverless: Serverless,
12+
private options: Serverless.Options
13+
) {
1114
this.hooks = {
1215
'after:deploy:deploy': this.process.bind(this)
1316
}
@@ -24,7 +27,10 @@ class StackOutputPlugin {
2427
}
2528

2629
get stackName () {
27-
return this.serverless.service.getServiceName() + '-' + this.serverless.getProvider('aws').getStage()
30+
return util.format('%s-%s',
31+
this.serverless.service.getServiceName(),
32+
this.serverless.getProvider('aws').getStage()
33+
)
2834
}
2935

3036
private hasConfig (key: string) {
@@ -40,76 +46,84 @@ class StackOutputPlugin {
4046
}
4147

4248
private getConfig (key: string) {
43-
return this.serverless.config.servicePath + '/' + this.output[key]
49+
return util.format('%s/%s',
50+
this.serverless.config.servicePath,
51+
this.output[key]
52+
)
4453
}
4554

46-
private callHandler (data: {}) {
55+
private callHandler (data: object) {
4756
const splits = this.handler.split('.')
4857
const func = splits.pop() || ''
58+
const file = splits.join('.')
4959

50-
return new Promise((resolve) => {
51-
require(splits.join('.'))[func](data, this.serverless)
60+
require(file)[func](
61+
data,
62+
this.serverless,
63+
this.options
64+
)
5265

53-
resolve()
54-
})
66+
return Promise.resolve()
5567
}
5668

57-
private saveFile (data: {}) {
69+
private saveFile (data: object) {
5870
const f = new StackOutputFile(this.file)
5971

60-
return new Promise((resolve) => {
61-
f.save(data)
62-
63-
resolve()
64-
})
72+
return f.save(data)
6573
}
6674

6775
private fetch (): Promise<StackDescriptionList> {
6876
return this.serverless.getProvider('aws').request(
6977
'CloudFormation',
7078
'describeStacks',
71-
{
72-
StackName: this.stackName
73-
},
79+
{ StackName: this.stackName },
7480
this.serverless.getProvider('aws').getStage(),
7581
this.serverless.getProvider('aws').getRegion()
7682
)
7783
}
7884

79-
private beautify (data: {Stacks: Array<{ Outputs: Array<{}> }>}) {
85+
private beautify (data: {Stacks: Array<{ Outputs: StackOutputPair[] }>}) {
8086
const stack = data.Stacks.pop() || { Outputs: [] }
8187
const output = stack.Outputs || []
8288

8389
return output.reduce(
84-
(obj: {}, item: StackOutputPair) => Object.assign(obj, {[item.OutputKey]: item.OutputValue}),
85-
{}
90+
(obj, item: StackOutputPair) => (
91+
Object.assign(obj, { [item.OutputKey]: item.OutputValue })
92+
), {}
8693
)
8794
}
8895

89-
private handle (data: {}) {
90-
const promises = []
96+
private handle (data: object) {
97+
return Promise.all(
98+
[
99+
this.handleHandler(data),
100+
this.handleFile(data)
101+
]
102+
)
103+
}
91104

92-
if (this.hasHandler()) {
93-
promises.push(
94-
this.callHandler(data).then(
95-
() => this.serverless.cli.log(
96-
util.format('Stack Output processed with handler: %s', this.output.handler)
97-
)
105+
private handleHandler(data: object) {
106+
return this.hasHandler() ? (
107+
this.callHandler(
108+
data
109+
).then(
110+
() => this.serverless.cli.log(
111+
util.format('Stack Output processed with handler: %s', this.output.handler)
98112
)
99113
)
100-
}
114+
) : Promise.resolve()
115+
}
101116

102-
if (this.hasFile()) {
103-
promises.push(
104-
this.saveFile(data).then(
105-
() => this.serverless.cli.log(
106-
util.format('Stack Output saved to file: %s', this.output.file)
107-
)
117+
private handleFile(data: object) {
118+
return this.hasFile() ? (
119+
this.saveFile(
120+
data
121+
).then(
122+
() => this.serverless.cli.log(
123+
util.format('Stack Output saved to file: %s', this.output.file)
108124
)
109125
)
110-
}
111-
112-
return Promise.all(promises)
126+
) : Promise.resolve()
113127
}
114128

115129
private validate () {
@@ -123,20 +137,19 @@ class StackOutputPlugin {
123137
}
124138

125139
private process () {
126-
console.log('running stack-output-plugin')
127-
128-
return Promise.resolve().then(
140+
Promise.resolve()
141+
.then(
129142
() => this.validate()
130143
).then(
131144
() => this.fetch()
132145
).then(
133-
(res: StackDescriptionList) => this.beautify(res)
146+
(res) => this.beautify(res)
134147
).then(
135148
(res) => this.handle(res)
136149
).catch(
137-
(err) => this.serverless.cli.log(util.format('Cannot process Stack Output: %s!', err.message))
150+
(err) => this.serverless.cli.log(
151+
util.format('Cannot process Stack Output: %s!', err.message)
152+
)
138153
)
139154
}
140155
}
141-
142-
module.exports = StackOutputPlugin

test/file.spec.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
'use strict'
1+
import using from 'jasmine-data-provider'
2+
import util from 'util'
23

3-
import * as using from 'jasmine-data-provider'
44
import File from '../src/file'
55

66
describe('File', () => {
@@ -21,13 +21,20 @@ describe('File', () => {
2121
{file: 'test.zip', valid: false}
2222
],
2323
(data) => {
24-
it('detects' + (data.valid ? ' valid ' : ' invalid ') + data.file, () => {
24+
const name = util.format(
25+
'detects %s %s',
26+
data.valid ? 'valid' : 'invalid',
27+
data.file
28+
)
29+
30+
it(name, () => {
2531
const f = new File(data.file)
32+
const output = { foo: 'bar' }
2633

2734
if (data.valid) {
28-
expect(f.format({ foo: 'bar' })).toBe(data.data)
35+
expect(f.format(output)).toBe(data.data)
2936
} else {
30-
expect(() => f.format()).toThrow()
37+
expect(() => f.format(output)).toThrow()
3138
}
3239
})
3340
}

test/plugin.spec.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
'use strict'
1+
import sinon from 'sinon'
22

3-
import * as sinon from 'sinon'
4-
import * as Plugin from '../src/plugin'
3+
import Plugin from '../src/plugin'
54

65
describe('Plugin', () => {
76
let providerMock = null
@@ -43,7 +42,7 @@ describe('Plugin', () => {
4342
}
4443
}
4544

46-
const test = new Plugin(config)
45+
const test = new Plugin(config, { serverless: true }, { options: true })
4746

4847
expect(test.hasHandler()).toBe(true)
4948
expect(test.hasFile()).toBe(false)

tsconfig.json

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
{
22
"compilerOptions": {
3-
"experimentalDecorators": true,
4-
"forceConsistentCasingInFileNames": true,
53
"module": "commonjs",
4+
"target": "es5",
5+
"sourceMap": false,
6+
"allowJs": false,
67
"moduleResolution": "node",
7-
"noImplicitAny": true,
8+
"rootDir": "./src",
9+
"outDir": "./dist",
10+
"forceConsistentCasingInFileNames": true,
811
"noImplicitReturns": true,
912
"noImplicitThis": true,
10-
"noUnusedLocals": true,
11-
"outDir": "dist",
12-
"sourceMap": true,
13-
"strictNullChecks": true,
13+
"noImplicitAny": true,
14+
"strict": true,
1415
"suppressImplicitAnyIndexErrors": true,
15-
"target": "esnext"
16+
"noUnusedLocals": true,
17+
"allowSyntheticDefaultImports": true,
18+
"lib": [
19+
"es2015",
20+
"es2016"
21+
],
22+
"declaration": false
1623
},
1724
"include": [
1825
"src/**/*",
1926
"vendor/**/*"
2027
],
2128
"exclude": [
22-
"node_modules/**/*"
29+
"node_modules/**/*",
30+
"src/**/*.spec.ts"
2331
]
24-
}
32+
}

yarn.lock

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1989,6 +1989,12 @@ rimraf@^2.6.1:
19891989
dependencies:
19901990
glob "^7.0.5"
19911991

1992+
rimraf@^2.6.2:
1993+
version "2.6.2"
1994+
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
1995+
dependencies:
1996+
glob "^7.0.5"
1997+
19921998
safe-buffer@^5.0.1:
19931999
version "5.1.1"
19942000
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
@@ -2291,8 +2297,8 @@ type-detect@^4.0.0:
22912297
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.3.tgz#0e3f2670b44099b0b46c284d136a7ef49c74c2ea"
22922298

22932299
typescript@^2.4.2:
2294-
version "2.4.2"
2295-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.4.2.tgz#f8395f85d459276067c988aa41837a8f82870844"
2300+
version "2.6.1"
2301+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.6.1.tgz#ef39cdea27abac0b500242d6726ab90e0c846631"
22962302

22972303
uglify-js@^2.6:
22982304
version "2.8.29"

0 commit comments

Comments
 (0)