Skip to content

Commit 61902e1

Browse files
authored
Merge pull request nicka#2 from nicka/release/1.0.0
Release/1.0.1
2 parents d96db89 + 81f31d0 commit 61902e1

File tree

10 files changed

+404
-3
lines changed

10 files changed

+404
-3
lines changed

.eslintignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.tmp/
2+
build/
3+
coverage/
4+
docs/
5+
node_modules/
6+
results/
7+
.serverless

.eslintrc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"extends": "airbnb-base",
3+
"globals": {
4+
"afterAll": true,
5+
"applyToAll": true,
6+
"afterEach": true,
7+
"beforeAll": true,
8+
"beforeEach": true,
9+
"describe": true,
10+
"expect": true,
11+
"jest": true,
12+
"register": true,
13+
"it": true,
14+
"test": true
15+
},
16+
"rules": {
17+
"no-console": 0,
18+
"strict": 0,
19+
"import/prefer-default-export": 0,
20+
"import/no-extraneous-dependencies": [
21+
"error", {
22+
"devDependencies": ["**/*.test.js", "**/*.spec.js"]
23+
}
24+
]
25+
}
26+
}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ build
66
dist
77
logs
88
pids
9+
*.tgz
910

1011
# OS
1112
.DS_Store

.npmignore

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
__snapshots__
2+
.env
3+
.eslintignore
4+
.eslintrc
5+
.serverless
6+
.tgz
7+
.tmp
8+
.travis.yml
9+
*.env
10+
*.log
11+
*.pid
12+
*.seed
13+
*.test.js
14+
build
15+
coverage
16+
dist
17+
jspm_packages
18+
logs
19+
node_modules
20+
pids
21+
results

.travis.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
language: node_js
2+
node_js:
3+
- '4'
4+
cache:
5+
directories:
6+
- node_modules
7+
branches:
8+
only:
9+
- develop
10+
- master
11+
- "/^feature\\/.*$/"
12+
- "/^release\\/.*$/"
13+
install:
14+
- travis_retry npm install
15+
after_success:
16+
- cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
[![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com)
2+
[![Coverage-Status](https://coveralls.io/repos/github/nicka/serverless-plugin-diff/badge.svg?branch=master)](https://coveralls.io/github/nicka/serverless-plugin-diff?branch=master)
3+
[![Build-Status](https://travis-ci.org/nicka/serverless-plugin-diff.svg?branch=master)](https://travis-ci.org/nicka/serverless-plugin-diff)
24

35
# Serverless CloudFormation Diff
46

5-
WIP
6-
77
## Overview
88

99
Plugin for Serverless Framework v1.x which compares your locale AWS CloudFormation templates against deployed ones.
1010

1111
## Usage
1212

1313
```bash
14-
serverless deploy --diff --noDeploy --stage REPLACEME --region REPLACEME
14+
serverless deploy diff --stage REPLACEME --region REPLACEME
1515
```
1616

17+
<img width="1255" alt="screen shot 2016-11-05 at 14 53 04" src="https://cloud.githubusercontent.com/assets/195404/20030536/9e1a552c-a367-11e6-8e6d-2043f2a5d038.png">
18+
1719
## Install
1820

1921
Execute npm install in your Serverless project.

lib/__snapshots__/index.test.js.snap

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
exports[`serverless-plugin-write-env-vars diff successfully triggers diff runs diff with custom diff tool 1`] = `
2+
"1c1
3+
< {\"foo\":\"bar\"}
4+
\\ No newline at end of file
5+
---
6+
> {\"foo\":\"foo\"}
7+
\\ No newline at end of file
8+
"
9+
`;
10+
11+
exports[`serverless-plugin-write-env-vars diff successfully triggers diff runs diff with custom localTemplate template 1`] = `
12+
"1c1
13+
< {\"foo\":\"custom\"}
14+
\\ No newline at end of file
15+
---
16+
> {\"foo\":\"foo\"}
17+
\\ No newline at end of file
18+
"
19+
`;
20+
21+
exports[`serverless-plugin-write-env-vars diff successfully triggers diff runs diff with defaults 1`] = `
22+
"1c1
23+
< {\"foo\":\"bar\"}
24+
\\ No newline at end of file
25+
---
26+
> {\"foo\":\"foo\"}
27+
\\ No newline at end of file
28+
"
29+
`;
30+
31+
exports[`serverless-plugin-write-env-vars diff unsuccessfully triggers diff could not find locally compiled template 1`] = `".serverless/cloudformation-template-update-stack.json could not be found: run \"sls deploy --noDeploy\" first."`;
32+
33+
exports[`serverless-plugin-write-env-vars downloadTemplate with successful CloudFormation call downloads currently deployed template 1`] = `
34+
"{
35+
\"foo\": \"bar\"
36+
}"
37+
`;
38+
39+
exports[`serverless-plugin-write-env-vars downloadTemplate with unsuccessful CloudFormation call could not download deployed template 1`] = `"Stack with id foo-foo does not exist"`;

lib/index.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
3+
const AWS = require('aws-sdk');
4+
const fs = require('fs-promise');
5+
const exec = require('child-process-promise').exec;
6+
const Q = require('q');
7+
8+
class ServerlessPlugin {
9+
constructor(serverless, options) {
10+
this.serverless = serverless;
11+
this.options = options;
12+
13+
this.commands = {
14+
diff: {
15+
usage: 'Helps you start your first Serverless plugin',
16+
lifecycleEvents: ['diff'],
17+
options: {
18+
diffTool: {
19+
usage:
20+
'Specify the diff tool you want to use '
21+
+ '(e.g. "--diffTool \'ksdiff\'")',
22+
required: false,
23+
shortcut: 'dt',
24+
},
25+
localTemplate: {
26+
usage:
27+
'Specify your locally compiled CloudFormation template'
28+
+ '(e.g. "--localTemplate \'./serverless/'
29+
+ 'cloudformation-template-update-stack.json\'")',
30+
required: false,
31+
shortcut: 'lt',
32+
},
33+
},
34+
},
35+
};
36+
37+
this.hooks = {
38+
'before:diff:diff': this.downloadTemplate.bind(this),
39+
'diff:diff': this.diff.bind(this),
40+
};
41+
42+
this.options.stage = this.options.stage
43+
|| (this.serverless.service.defaults && this.serverless.service.defaults.stage)
44+
|| 'dev';
45+
this.options.region = this.options.region
46+
|| (this.serverless.service.defaults && this.serverless.service.defaults.region)
47+
|| 'us-east-1';
48+
this.options.diffTool = this.options.diffTool
49+
|| 'diff';
50+
this.options.localTemplate = this.options.localTemplate
51+
|| '.serverless/cloudformation-template-update-stack.json';
52+
this.options.orgTemplate = this.options.localTemplate.replace('.json', '.org.json');
53+
54+
AWS.config.update({ region: this.options.region });
55+
56+
this.cloudFormation = new AWS.CloudFormation();
57+
}
58+
59+
downloadTemplate() {
60+
const deferred = Q.defer();
61+
const orgTemplate = this.options.orgTemplate;
62+
const params = {
63+
StackName: `${this.serverless.service.service}-${this.options.stage}`,
64+
TemplateStage: 'Processed',
65+
};
66+
67+
this.serverless.cli.log('Downloading currently deployed template');
68+
69+
this.cloudFormation.getTemplate(params, (err, data) => {
70+
if (err) {
71+
deferred.reject(err.message);
72+
} else {
73+
let templateBody = JSON.parse(data.TemplateBody);
74+
templateBody = JSON.stringify(templateBody, null, 2);
75+
76+
fs.writeFile(orgTemplate, templateBody)
77+
.then(() => deferred.resolve())
78+
.catch(fsErr => deferred.reject(fsErr.message));
79+
}
80+
});
81+
82+
return deferred.promise;
83+
}
84+
85+
diff() {
86+
const deferred = Q.defer();
87+
const diffTool = this.options.diffTool;
88+
const localTemplate = this.options.localTemplate;
89+
const orgTemplate = this.options.orgTemplate;
90+
91+
this.serverless.cli.log('Running diff against deployed template');
92+
93+
fs.stat(localTemplate)
94+
.then(() => {
95+
exec(`${diffTool} ${orgTemplate} ${localTemplate} || true`)
96+
.then((result) => {
97+
const diffData = result.stdout;
98+
console.log(diffData);
99+
deferred.resolve(diffData);
100+
})
101+
.catch(execErr => deferred.reject(execErr.message));
102+
})
103+
.catch((err) => {
104+
if (err.code === 'ENOENT') {
105+
const errorPrefix = `${localTemplate} could not be found:`;
106+
deferred.reject(`${errorPrefix} run "sls deploy --noDeploy" first.`);
107+
}
108+
});
109+
110+
return deferred.promise;
111+
}
112+
}
113+
114+
module.exports = ServerlessPlugin;

0 commit comments

Comments
 (0)