awscfn 1.1.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -1
- package/bin/awscfn +19 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/cfn/executeChangeSet.d.ts +9 -2
- package/dist/lib/cfn/executeChangeSet.d.ts.map +1 -1
- package/dist/lib/cfn/executeChangeSet.js +20 -5
- package/dist/lib/cfn/executeChangeSet.js.map +1 -1
- package/dist/lib/cfn/index.d.ts +1 -0
- package/dist/lib/cfn/index.d.ts.map +1 -1
- package/dist/lib/cfn/index.js +1 -0
- package/dist/lib/cfn/index.js.map +1 -1
- package/dist/lib/cfn/previewChangeSet.d.ts +7 -0
- package/dist/lib/cfn/previewChangeSet.d.ts.map +1 -0
- package/dist/lib/cfn/previewChangeSet.js +97 -0
- package/dist/lib/cfn/previewChangeSet.js.map +1 -0
- package/dist/lib/formatChangeSet.d.ts +10 -0
- package/dist/lib/formatChangeSet.d.ts.map +1 -0
- package/dist/lib/formatChangeSet.js +81 -0
- package/dist/lib/formatChangeSet.js.map +1 -0
- package/dist/lib/formatChangeSet.spec.d.ts +2 -0
- package/dist/lib/formatChangeSet.spec.d.ts.map +1 -0
- package/dist/lib/formatChangeSet.spec.js +72 -0
- package/dist/lib/formatChangeSet.spec.js.map +1 -0
- package/dist/previewStack.d.ts +6 -0
- package/dist/previewStack.d.ts.map +1 -0
- package/dist/previewStack.js +61 -0
- package/dist/previewStack.js.map +1 -0
- package/dist/updateStack.d.ts +1 -1
- package/dist/updateStack.d.ts.map +1 -1
- package/dist/updateStack.js +9 -2
- package/dist/updateStack.js.map +1 -1
- package/package.json +1 -1
- package/dist/lib/placeholder.spec.d.ts +0 -2
- package/dist/lib/placeholder.spec.d.ts.map +0 -1
- package/dist/lib/placeholder.spec.js +0 -8
- package/dist/lib/placeholder.spec.js.map +0 -1
package/README.md
CHANGED
|
@@ -127,12 +127,34 @@ awscfn update-stack -n <STACK_NAME> -t <TEMPLATE_FILE> -p <PARAMS_FILE>
|
|
|
127
127
|
| `--name`, `-n` | Stack name |
|
|
128
128
|
| `--template`, `-t` | CloudFormation template file |
|
|
129
129
|
| `--params`, `-p` | Parameters file (YAML) |
|
|
130
|
+
| `--create` | If the stack doesn't exist, create it (instead of erroring) |
|
|
131
|
+
| `-m` | Shorthand for `--create` |
|
|
130
132
|
|
|
131
133
|
If there are no changes to apply, the command succeeds gracefully:
|
|
132
134
|
```
|
|
133
135
|
✓ Stack my-stack is up to date (no changes)
|
|
134
136
|
```
|
|
135
137
|
|
|
138
|
+
### 👁️ preview-stack
|
|
139
|
+
|
|
140
|
+
Builds a change set (same capabilities as deploy), prints a **table of planned resource-level changes**, then **deletes** the change set without executing it. If the stack exists, uses an **UPDATE** change set; otherwise **CREATE**.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
awscfn preview-stack -n <STACK_NAME> -t <TEMPLATE_FILE> -p <PARAMS_FILE>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Flag | Description |
|
|
147
|
+
|------|-------------|
|
|
148
|
+
| `--name`, `-n` | Stack name |
|
|
149
|
+
| `--template`, `-t` | CloudFormation template file |
|
|
150
|
+
| `--params`, `-p` | Parameters file (YAML) |
|
|
151
|
+
|
|
152
|
+
Use this to review Add / Modify / Remove actions (and replacement hints) before running **`create-stack`** or **`update-stack`**.
|
|
153
|
+
|
|
154
|
+
If the stack is **`ROLLBACK_COMPLETE`**, **`update-stack`** would delete and recreate it — **`preview-stack` cannot model that path** and exits with an error (delete the stack or run **`update-stack`** first).
|
|
155
|
+
|
|
156
|
+
Non-resource change-set entries (for example hooks) are counted and noted when they are not shown as table rows.
|
|
157
|
+
|
|
136
158
|
### ♻️ redeploy-stack
|
|
137
159
|
|
|
138
160
|
```bash
|
|
@@ -178,7 +200,7 @@ If the names don't match, the deletion will be aborted.
|
|
|
178
200
|
|
|
179
201
|
### Nested stacks and IAM
|
|
180
202
|
|
|
181
|
-
Change sets request **`CAPABILITY_NAMED_IAM`** and **`CAPABILITY_AUTO_EXPAND`**, so stacks that define named IAM resources or **nested stacks** (including templates from [`aws cloudformation package`](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html)) work with **`create-stack`** / **`update-stack`** and the SDK `createStack` / `updateStack` helpers.
|
|
203
|
+
Change sets request **`CAPABILITY_NAMED_IAM`** and **`CAPABILITY_AUTO_EXPAND`**, so stacks that define named IAM resources or **nested stacks** (including templates from [`aws cloudformation package`](https://docs.aws.amazon.com/cli/latest/reference/cloudformation/package.html)) work with **`create-stack`** / **`update-stack`** / **`preview-stack`** and the SDK `createStack` / `updateStack` / `previewChangeSet` helpers.
|
|
182
204
|
|
|
183
205
|
### 📋 `listStacks(): Promise<StackSummary[]>`
|
|
184
206
|
|
|
@@ -323,6 +345,25 @@ Reason: Resource handler returned message: "CannotPullContainerError: image not
|
|
|
323
345
|
|
|
324
346
|
> ✅ This function ensures safety by skipping updates for in-progress stacks and gracefully recovering from `ROLLBACK_COMPLETE` states.
|
|
325
347
|
|
|
348
|
+
### 👁️ `previewChangeSet(stackName, template, operation)` / `previewStack(...)`
|
|
349
|
+
|
|
350
|
+
**SDK:** Build a change set, print a colored table of planned resource changes (Add / Modify / Remove, replacement hints), then delete the change set — **without** executing it. Same capabilities as deploy (`CAPABILITY_NAMED_IAM`, `CAPABILITY_AUTO_EXPAND`).
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
import { initCloudFormationClient, previewChangeSet } from 'awscfn';
|
|
354
|
+
|
|
355
|
+
initCloudFormationClient();
|
|
356
|
+
|
|
357
|
+
await previewChangeSet('my-stack', {
|
|
358
|
+
body: templateString,
|
|
359
|
+
params: { Env: 'prod' },
|
|
360
|
+
}, 'UPDATE');
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**CLI:** Prefer `awscfn preview-stack -n … -t … -p …`, which picks **CREATE** vs **UPDATE** from whether the stack exists (same idea as deploy). Refuses **`ROLLBACK_COMPLETE`** stacks (same recovery path as **`update-stack`**: delete + create).
|
|
364
|
+
|
|
365
|
+
Table output lives in **`lib/formatChangeSet`** (shared formatting, not CLI-only).
|
|
366
|
+
|
|
326
367
|
## Contributing
|
|
327
368
|
|
|
328
369
|
- Open an [issue](https://github.com/mhweiner/awscfn/issues) for bugs or suggestions
|
package/bin/awscfn
CHANGED
|
@@ -7,6 +7,7 @@ const yargs = require('yargs');
|
|
|
7
7
|
const { createStack } = require('../dist/createStack');
|
|
8
8
|
const { deleteStack } = require('../dist/deleteStack');
|
|
9
9
|
const { listStacks } = require('../dist/listStacks');
|
|
10
|
+
const { previewStack } = require('../dist/previewStack');
|
|
10
11
|
const { redeployStack } = require('../dist/redeployStack');
|
|
11
12
|
const { updateStack } = require('../dist/updateStack');
|
|
12
13
|
const { getOutputConfig, setOutputConfig } = require('../dist/lib/output');
|
|
@@ -90,6 +91,15 @@ const templateOpt = {
|
|
|
90
91
|
const paramsOpt = {
|
|
91
92
|
params: { type: 'string', alias: 'p', describe: 'Parameters file (YAML). Optional; omit to use template defaults.', demandOption: false },
|
|
92
93
|
};
|
|
94
|
+
const createIfMissingOpt = {
|
|
95
|
+
create: {
|
|
96
|
+
type: 'boolean',
|
|
97
|
+
alias: 'm',
|
|
98
|
+
describe: 'Create the stack if it does not exist (update-stack only)',
|
|
99
|
+
demandOption: false,
|
|
100
|
+
default: false,
|
|
101
|
+
},
|
|
102
|
+
};
|
|
93
103
|
const confirmOpt = {
|
|
94
104
|
confirm: { type: 'string', alias: 'c', describe: 'Repeat stack name to confirm deletion', demandOption: true },
|
|
95
105
|
};
|
|
@@ -155,9 +165,17 @@ yargs
|
|
|
155
165
|
.command(
|
|
156
166
|
'update-stack',
|
|
157
167
|
'Update a CloudFormation stack',
|
|
168
|
+
(cmd) => cmd.options({ ...nameOpt, ...templateOpt, ...paramsOpt, ...createIfMissingOpt }),
|
|
169
|
+
({ name, template, params, create }) => {
|
|
170
|
+
runCommand(() => updateStack(name, template, params, Boolean(create)));
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
.command(
|
|
174
|
+
'preview-stack',
|
|
175
|
+
'Preview changes without deploying (change set only)',
|
|
158
176
|
(cmd) => cmd.options({ ...nameOpt, ...templateOpt, ...paramsOpt }),
|
|
159
177
|
({ name, template, params }) => {
|
|
160
|
-
runCommand(() =>
|
|
178
|
+
runCommand(() => previewStack(name, template, params));
|
|
161
179
|
}
|
|
162
180
|
)
|
|
163
181
|
.completion(
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAC,YAAY,EAAC,MAAM,gBAAgB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,9 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.previewStack = void 0;
|
|
17
18
|
__exportStar(require("./lib/cfn"), exports);
|
|
18
19
|
__exportStar(require("./lib/output"), exports);
|
|
20
|
+
var previewStack_1 = require("./previewStack");
|
|
21
|
+
Object.defineProperty(exports, "previewStack", { enumerable: true, get: function () { return previewStack_1.previewStack; } });
|
|
19
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,+CAA6B;AAC7B,+CAA4C;AAApC,4GAAA,YAAY,OAAA"}
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { Template, TemplateParams } from './index';
|
|
2
|
-
type ChangeSetOperation = 'UPDATE' | 'CREATE';
|
|
2
|
+
export type ChangeSetOperation = 'UPDATE' | 'CREATE';
|
|
3
|
+
/**
|
|
4
|
+
* Create a change set and return its ARN/id (does not wait).
|
|
5
|
+
*/
|
|
6
|
+
export declare function submitChangeSetRequest<P extends TemplateParams>(stackName: string, template: Template<P>, operation: ChangeSetOperation): Promise<string>;
|
|
7
|
+
/**
|
|
8
|
+
* Wait until the change set finishes building ({@link waitUntilChangeSetCreateComplete}) with spinner.
|
|
9
|
+
*/
|
|
10
|
+
export declare function waitForChangeSetBuild(changeSetId: string): Promise<void>;
|
|
3
11
|
export declare function createAndExecChangeSet<P extends TemplateParams>(stackName: string, template: Template<P>, operation: ChangeSetOperation): Promise<string>;
|
|
4
|
-
export {};
|
|
5
12
|
//# sourceMappingURL=executeChangeSet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executeChangeSet.d.ts","sourceRoot":"","sources":["../../../src/lib/cfn/executeChangeSet.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAG9D,
|
|
1
|
+
{"version":3,"file":"executeChangeSet.d.ts","sourceRoot":"","sources":["../../../src/lib/cfn/executeChangeSet.ts"],"names":[],"mappings":"AAKA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AAG9D,MAAM,MAAM,kBAAkB,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAoBrD;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,CAAC,SAAS,cAAc,EACjE,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,SAAS,EAAE,kBAAkB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAoBjB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoB9E;AAiBD,wBAAsB,sBAAsB,CAAC,CAAC,SAAS,cAAc,EACjE,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,SAAS,EAAE,kBAAkB,GAC9B,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.submitChangeSetRequest = submitChangeSetRequest;
|
|
4
|
+
exports.waitForChangeSetBuild = waitForChangeSetBuild;
|
|
3
5
|
exports.createAndExecChangeSet = createAndExecChangeSet;
|
|
4
6
|
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
|
|
5
7
|
const index_1 = require("./index");
|
|
@@ -16,8 +18,10 @@ function toCfnParameters(params) {
|
|
|
16
18
|
ParameterValue: String(value),
|
|
17
19
|
}));
|
|
18
20
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Create a change set and return its ARN/id (does not wait).
|
|
23
|
+
*/
|
|
24
|
+
async function submitChangeSetRequest(stackName, template, operation) {
|
|
21
25
|
const cf = (0, index_1.getCfClient)();
|
|
22
26
|
const changeSetName = `${stackName}-rev-${Date.now()}`;
|
|
23
27
|
const templateBody = typeof template === 'string' ? template : template.body;
|
|
@@ -32,25 +36,36 @@ async function createChangeSet(stackName, template, operation) {
|
|
|
32
36
|
Parameters: parameters,
|
|
33
37
|
Capabilities: ['CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'],
|
|
34
38
|
}));
|
|
39
|
+
return changeset.Id;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Wait until the change set finishes building ({@link waitUntilChangeSetCreateComplete}) with spinner.
|
|
43
|
+
*/
|
|
44
|
+
async function waitForChangeSetBuild(changeSetId) {
|
|
45
|
+
const cf = (0, index_1.getCfClient)();
|
|
35
46
|
const cfg = (0, output_1.getOutputConfig)();
|
|
36
47
|
const stopSpinner = cfg.ci ? null : (0, output_1.startSpinner)();
|
|
37
48
|
if (cfg.ci)
|
|
38
49
|
(0, output_1.dim)(` ${output_1.symbols.ellipsis} Waiting for changeset to be ready...`);
|
|
39
50
|
try {
|
|
40
51
|
await (0, client_cloudformation_1.waitUntilChangeSetCreateComplete)({ client: cf, maxWaitTime: 120 }, {
|
|
41
|
-
ChangeSetName:
|
|
52
|
+
ChangeSetName: changeSetId,
|
|
42
53
|
});
|
|
43
54
|
}
|
|
44
55
|
finally {
|
|
45
56
|
if (stopSpinner)
|
|
46
57
|
stopSpinner();
|
|
47
58
|
}
|
|
48
|
-
|
|
59
|
+
}
|
|
60
|
+
async function createChangeSetAndWait(stackName, template, operation) {
|
|
61
|
+
const changeSetId = await submitChangeSetRequest(stackName, template, operation);
|
|
62
|
+
await waitForChangeSetBuild(changeSetId);
|
|
63
|
+
return changeSetId;
|
|
49
64
|
}
|
|
50
65
|
async function createAndExecChangeSet(stackName, template, operation) {
|
|
51
66
|
(0, output_1.dim)(` ${output_1.symbols.bullet} Creating changeset ${(0, output_1.gray)(`(${operation.toLowerCase()})`)}`);
|
|
52
67
|
const cf = (0, index_1.getCfClient)();
|
|
53
|
-
const changeSetId = await
|
|
68
|
+
const changeSetId = await createChangeSetAndWait(stackName, template, operation);
|
|
54
69
|
(0, output_1.dim)(` ${output_1.symbols.bullet} Executing changeset...`);
|
|
55
70
|
await cf.send(new client_cloudformation_1.ExecuteChangeSetCommand({
|
|
56
71
|
ChangeSetName: changeSetId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executeChangeSet.js","sourceRoot":"","sources":["../../../src/lib/cfn/executeChangeSet.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"executeChangeSet.js","sourceRoot":"","sources":["../../../src/lib/cfn/executeChangeSet.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/cfn/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare function getCfClient(): CloudFormationClient;
|
|
|
9
9
|
export * from './createStack';
|
|
10
10
|
export * from './getStackByName';
|
|
11
11
|
export * from './listStacks';
|
|
12
|
+
export * from './previewChangeSet';
|
|
12
13
|
export * from './updateStack';
|
|
13
14
|
export * from './deleteStack';
|
|
14
15
|
export * from './validateTemplate';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/cfn/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,gCAAgC,CAAC;AAEpE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACjD,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,cAAc,IAAI;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,CAAC,CAAA;CACZ,GAAG,MAAM,CAAC;AAIX,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C;AAED,wBAAgB,WAAW,IAAI,oBAAoB,CAMlD;AAED,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/cfn/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,oBAAoB,EAAC,MAAM,gCAAgC,CAAC;AAEpE,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AACjD,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,cAAc,IAAI;IAC7C,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,CAAC,CAAA;CACZ,GAAG,MAAM,CAAC;AAIX,wBAAgB,wBAAwB,IAAI,IAAI,CAI/C;AAED,wBAAgB,WAAW,IAAI,oBAAoB,CAMlD;AAED,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC"}
|
package/dist/lib/cfn/index.js
CHANGED
|
@@ -29,6 +29,7 @@ function getCfClient() {
|
|
|
29
29
|
__exportStar(require("./createStack"), exports);
|
|
30
30
|
__exportStar(require("./getStackByName"), exports);
|
|
31
31
|
__exportStar(require("./listStacks"), exports);
|
|
32
|
+
__exportStar(require("./previewChangeSet"), exports);
|
|
32
33
|
__exportStar(require("./updateStack"), exports);
|
|
33
34
|
__exportStar(require("./deleteStack"), exports);
|
|
34
35
|
__exportStar(require("./validateTemplate"), exports);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/cfn/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAUA,4DAIC;AAED,kCAMC;AAtBD,0EAAoE;AAQpE,IAAI,EAAkC,CAAC;AAEvC,SAAgB,wBAAwB;IAEpC,EAAE,GAAG,IAAI,4CAAoB,EAAE,CAAC;AAEpC,CAAC;AAED,SAAgB,WAAW;IAEvB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAElE,OAAO,EAAE,CAAC;AAEd,CAAC;AAED,gDAA8B;AAC9B,mDAAiC;AACjC,+CAA6B;AAC7B,gDAA8B;AAC9B,gDAA8B;AAC9B,qDAAmC;AACnC,sDAAoC;AACpC,oDAAkC;AAClC,2DAAyC;AACzC,sDAAoC;AACpC,sDAAoC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/cfn/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAUA,4DAIC;AAED,kCAMC;AAtBD,0EAAoE;AAQpE,IAAI,EAAkC,CAAC;AAEvC,SAAgB,wBAAwB;IAEpC,EAAE,GAAG,IAAI,4CAAoB,EAAE,CAAC;AAEpC,CAAC;AAED,SAAgB,WAAW;IAEvB,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAElE,OAAO,EAAE,CAAC;AAEd,CAAC;AAED,gDAA8B;AAC9B,mDAAiC;AACjC,+CAA6B;AAC7B,qDAAmC;AACnC,gDAA8B;AAC9B,gDAA8B;AAC9B,qDAAmC;AACnC,sDAAoC;AACpC,oDAAkC;AAClC,2DAAyC;AACzC,sDAAoC;AACpC,sDAAoC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ChangeSetOperation } from './executeChangeSet';
|
|
2
|
+
import { Template, TemplateParams } from './index';
|
|
3
|
+
/**
|
|
4
|
+
* Build a change set, print planned resource changes (without executing), then delete the change set.
|
|
5
|
+
*/
|
|
6
|
+
export declare function previewChangeSet<P extends TemplateParams>(stackName: string, template: Template<P>, operation: ChangeSetOperation): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=previewChangeSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewChangeSet.d.ts","sourceRoot":"","sources":["../../../src/lib/cfn/previewChangeSet.ts"],"names":[],"mappings":"AAOA,OAAO,EAGH,KAAK,kBAAkB,EAC1B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAc,MAAM,SAAS,CAAC;AA2G9D;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,SAAS,cAAc,EAC3D,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,SAAS,EAAE,kBAAkB,GAC9B,OAAO,CAAC,IAAI,CAAC,CA6Cf"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.previewChangeSet = previewChangeSet;
|
|
4
|
+
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
|
|
5
|
+
const formatChangeSet_1 = require("../formatChangeSet");
|
|
6
|
+
const executeChangeSet_1 = require("./executeChangeSet");
|
|
7
|
+
const index_1 = require("./index");
|
|
8
|
+
const output_1 = require("../output");
|
|
9
|
+
function isNoChangesOutcome(desc) {
|
|
10
|
+
const reason = desc.StatusReason ?? '';
|
|
11
|
+
return Boolean(desc.Status === 'FAILED'
|
|
12
|
+
&& (reason.includes('didn\'t contain changes')
|
|
13
|
+
|| reason.includes('No updates are to be performed')));
|
|
14
|
+
}
|
|
15
|
+
/** Merge paginated {@link DescribeChangeSetCommand} results so large change lists are complete. */
|
|
16
|
+
async function describeChangeSetPaginated(changeSetId) {
|
|
17
|
+
const cf = (0, index_1.getCfClient)();
|
|
18
|
+
let nextToken;
|
|
19
|
+
let first;
|
|
20
|
+
const allChanges = [];
|
|
21
|
+
do {
|
|
22
|
+
const page = await cf.send(new client_cloudformation_1.DescribeChangeSetCommand({
|
|
23
|
+
ChangeSetName: changeSetId,
|
|
24
|
+
NextToken: nextToken,
|
|
25
|
+
}));
|
|
26
|
+
if (!first) {
|
|
27
|
+
first = page;
|
|
28
|
+
}
|
|
29
|
+
allChanges.push(...(page.Changes ?? []));
|
|
30
|
+
nextToken = page.NextToken;
|
|
31
|
+
} while (nextToken);
|
|
32
|
+
return { ...(first ?? {}), Changes: allChanges };
|
|
33
|
+
}
|
|
34
|
+
async function deleteChangeSetQuiet(changeSetId) {
|
|
35
|
+
const cf = (0, index_1.getCfClient)();
|
|
36
|
+
try {
|
|
37
|
+
await cf.send(new client_cloudformation_1.DeleteChangeSetCommand({
|
|
38
|
+
ChangeSetName: changeSetId,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// Best-effort cleanup after preview
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function printPlannedTable(stackName, desc) {
|
|
46
|
+
console.log('');
|
|
47
|
+
(0, output_1.info)(`${output_1.symbols.arrow} Planned resource changes for ${(0, output_1.cyan)(stackName)}`);
|
|
48
|
+
const lines = (0, formatChangeSet_1.formatChangeSetPreviewLines)(desc.Changes ?? []);
|
|
49
|
+
for (const line of lines)
|
|
50
|
+
console.log(line);
|
|
51
|
+
console.log('');
|
|
52
|
+
const statusNote = ` ${output_1.symbols.info} Change set status: ${desc.Status ?? 'unknown'}${desc.ExecutionStatus ? ` · execution: ${desc.ExecutionStatus}` : ''}`;
|
|
53
|
+
(0, output_1.dim)(statusNote);
|
|
54
|
+
(0, output_1.success)(`${output_1.symbols.check} Preview complete — change set was not executed`);
|
|
55
|
+
}
|
|
56
|
+
/** Fetch full change list after the SDK waiter finished building the change set (waiter polls status only). */
|
|
57
|
+
async function runPreviewFromBuiltChangeSet(stackName, changeSetId) {
|
|
58
|
+
const desc = await describeChangeSetPaginated(changeSetId);
|
|
59
|
+
if (isNoChangesOutcome(desc)) {
|
|
60
|
+
(0, output_1.success)(`${output_1.symbols.check} Stack ${(0, output_1.cyan)(stackName)} — no changes to apply`);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (desc.Status !== 'CREATE_COMPLETE') {
|
|
64
|
+
throw new Error(desc.StatusReason ?? `Change set status: ${desc.Status ?? 'unknown'}`);
|
|
65
|
+
}
|
|
66
|
+
printPlannedTable(stackName, desc);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a change set, print planned resource changes (without executing), then delete the change set.
|
|
70
|
+
*/
|
|
71
|
+
async function previewChangeSet(stackName, template, operation) {
|
|
72
|
+
(0, output_1.dim)(` ${output_1.symbols.bullet} Building change set ${(0, output_1.gray)(`(${operation.toLowerCase()} preview)`)}`);
|
|
73
|
+
const changeSetId = await (0, executeChangeSet_1.submitChangeSetRequest)(stackName, template, operation);
|
|
74
|
+
try {
|
|
75
|
+
try {
|
|
76
|
+
await (0, executeChangeSet_1.waitForChangeSetBuild)(changeSetId);
|
|
77
|
+
}
|
|
78
|
+
catch (waitErr) {
|
|
79
|
+
const descEarly = await describeChangeSetPaginated(changeSetId);
|
|
80
|
+
if (isNoChangesOutcome(descEarly)) {
|
|
81
|
+
(0, output_1.success)(`${output_1.symbols.check} Stack ${(0, output_1.cyan)(stackName)} — no changes to apply`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const detail = descEarly.StatusReason ?? 'Change set did not complete successfully';
|
|
85
|
+
if (waitErr instanceof Error) {
|
|
86
|
+
waitErr.message = `${detail} — ${waitErr.message}`;
|
|
87
|
+
throw waitErr;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(detail, { cause: waitErr });
|
|
90
|
+
}
|
|
91
|
+
await runPreviewFromBuiltChangeSet(stackName, changeSetId);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
await deleteChangeSetQuiet(changeSetId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=previewChangeSet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewChangeSet.js","sourceRoot":"","sources":["../../../src/lib/cfn/previewChangeSet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Change } from '@aws-sdk/client-cloudformation';
|
|
2
|
+
/**
|
|
3
|
+
* Printable rows for a CloudFormation change set's {@link Change} list (resource-level rows).
|
|
4
|
+
* Sorts by logical resource id for stable output.
|
|
5
|
+
* Non-resource entries (e.g. hooks) are counted but not tabulated.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatChangeSetPreviewLines(changes: Change[], opts?: {
|
|
8
|
+
color?: boolean;
|
|
9
|
+
}): string[];
|
|
10
|
+
//# sourceMappingURL=formatChangeSet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatChangeSet.d.ts","sourceRoot":"","sources":["../../src/lib/formatChangeSet.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,MAAM,EAAiB,MAAM,gCAAgC,CAAC;AAyE3E;;;;GAIG;AACH,wBAAgB,2BAA2B,CACvC,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,CAAC,EAAE;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAC,GACzB,MAAM,EAAE,CA2CV"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatChangeSetPreviewLines = formatChangeSetPreviewLines;
|
|
4
|
+
const output_1 = require("./output");
|
|
5
|
+
const colors = {
|
|
6
|
+
dim: '\x1b[2m',
|
|
7
|
+
gray: '\x1b[90m',
|
|
8
|
+
};
|
|
9
|
+
function pickActionStyle(action) {
|
|
10
|
+
if (action === 'Add')
|
|
11
|
+
return output_1.green;
|
|
12
|
+
if (action === 'Remove')
|
|
13
|
+
return output_1.red;
|
|
14
|
+
if (action === 'Modify')
|
|
15
|
+
return output_1.yellow;
|
|
16
|
+
if (action === 'Import')
|
|
17
|
+
return output_1.cyan;
|
|
18
|
+
return (t) => t;
|
|
19
|
+
}
|
|
20
|
+
function padRight(s, width) {
|
|
21
|
+
return s.length >= width ? s : s + ' '.repeat(width - s.length);
|
|
22
|
+
}
|
|
23
|
+
/** Entries such as hooks or future types that do not carry {@link ResourceChange}. */
|
|
24
|
+
function countNonResourceEntries(changes) {
|
|
25
|
+
return changes.filter((c) => !c.ResourceChange).length;
|
|
26
|
+
}
|
|
27
|
+
function resourceRows(resourceChanges, maxLogical, maxType, configColor) {
|
|
28
|
+
const out = [];
|
|
29
|
+
for (const r of resourceChanges) {
|
|
30
|
+
const logical = padRight(r.LogicalResourceId ?? '—', maxLogical);
|
|
31
|
+
const resType = padRight(r.ResourceType ?? '—', maxType);
|
|
32
|
+
const replacement = r.Replacement ?? '—';
|
|
33
|
+
const style = pickActionStyle(r.Action);
|
|
34
|
+
const rawAction = r.Action ?? '—';
|
|
35
|
+
const actionCell = configColor
|
|
36
|
+
? style(rawAction) + ' '.repeat(Math.max(0, 10 - rawAction.length))
|
|
37
|
+
: rawAction.padEnd(10);
|
|
38
|
+
out.push(` ${actionCell} ${logical} ${resType} ${replacement}`);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function sortedResourceChanges(changes) {
|
|
43
|
+
const resourceChanges = changes
|
|
44
|
+
.map((c) => c.ResourceChange)
|
|
45
|
+
.filter((rc) => Boolean(rc));
|
|
46
|
+
resourceChanges.sort((a, b) => (a.LogicalResourceId ?? '').localeCompare(b.LogicalResourceId ?? ''));
|
|
47
|
+
return resourceChanges;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Printable rows for a CloudFormation change set's {@link Change} list (resource-level rows).
|
|
51
|
+
* Sorts by logical resource id for stable output.
|
|
52
|
+
* Non-resource entries (e.g. hooks) are counted but not tabulated.
|
|
53
|
+
*/
|
|
54
|
+
function formatChangeSetPreviewLines(changes, opts) {
|
|
55
|
+
const configColor = opts?.color ?? (0, output_1.getOutputConfig)().color;
|
|
56
|
+
const resourceChanges = sortedResourceChanges(changes);
|
|
57
|
+
const nonResourceCount = countNonResourceEntries(changes);
|
|
58
|
+
if (resourceChanges.length === 0) {
|
|
59
|
+
if (nonResourceCount > 0) {
|
|
60
|
+
const msg = ` (no resource-level rows — ${nonResourceCount} other change entr${nonResourceCount === 1 ? 'y' : 'ies'}, e.g. hooks)`;
|
|
61
|
+
return [configColor ? (0, output_1.gray)(msg) : msg];
|
|
62
|
+
}
|
|
63
|
+
return [' (no resource-level changes in this change set)'];
|
|
64
|
+
}
|
|
65
|
+
const maxLogical = Math.max(14, ...resourceChanges.map((r) => (r.LogicalResourceId ?? '').length));
|
|
66
|
+
const maxType = Math.max(12, ...resourceChanges.map((r) => (r.ResourceType ?? '').length));
|
|
67
|
+
const headerLine = `${padRight('ACTION', 10)} ${padRight('LOGICAL ID', maxLogical)} `
|
|
68
|
+
+ `${padRight('RESOURCE TYPE', maxType)} REPLACE`;
|
|
69
|
+
const divider = '-'.repeat(headerLine.length);
|
|
70
|
+
const lines = [
|
|
71
|
+
configColor ? (0, output_1.colorize)(headerLine, colors.dim) : headerLine,
|
|
72
|
+
configColor ? (0, output_1.colorize)(divider, colors.gray) : divider,
|
|
73
|
+
...resourceRows(resourceChanges, maxLogical, maxType, configColor),
|
|
74
|
+
];
|
|
75
|
+
if (nonResourceCount > 0) {
|
|
76
|
+
const note = ` (${nonResourceCount} non-resource change${nonResourceCount === 1 ? '' : 's'} omitted from table — e.g. hooks)`;
|
|
77
|
+
lines.push(configColor ? (0, output_1.gray)(note) : note);
|
|
78
|
+
}
|
|
79
|
+
return lines;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=formatChangeSet.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatChangeSet.js","sourceRoot":"","sources":["../../src/lib/formatChangeSet.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatChangeSet.spec.d.ts","sourceRoot":"","sources":["../../src/lib/formatChangeSet.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const kizu_1 = require("kizu");
|
|
4
|
+
const formatChangeSet_1 = require("./formatChangeSet");
|
|
5
|
+
(0, kizu_1.test)('formatChangeSetPreviewLines sorts by logical id and prints columns', (assert) => {
|
|
6
|
+
const changes = [
|
|
7
|
+
{
|
|
8
|
+
Type: 'Resource',
|
|
9
|
+
ResourceChange: {
|
|
10
|
+
Action: 'Modify',
|
|
11
|
+
LogicalResourceId: 'B',
|
|
12
|
+
ResourceType: 'AWS::S3::Bucket',
|
|
13
|
+
Replacement: 'False',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
Type: 'Resource',
|
|
18
|
+
ResourceChange: {
|
|
19
|
+
Action: 'Add',
|
|
20
|
+
LogicalResourceId: 'A',
|
|
21
|
+
ResourceType: 'AWS::IAM::Role',
|
|
22
|
+
Replacement: 'False',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
const lines = (0, formatChangeSet_1.formatChangeSetPreviewLines)(changes, { color: false });
|
|
27
|
+
const text = lines.join('\n');
|
|
28
|
+
assert.equal(text.includes('LOGICAL ID'), true);
|
|
29
|
+
assert.equal(text.includes('RESOURCE TYPE'), true);
|
|
30
|
+
assert.equal(text.includes('AWS::IAM::Role'), true);
|
|
31
|
+
assert.equal(text.includes('AWS::S3::Bucket'), true);
|
|
32
|
+
const dataLines = lines.filter((l) => l.includes('Add') && l.includes('A'));
|
|
33
|
+
assert.equal(dataLines.length >= 1, true);
|
|
34
|
+
});
|
|
35
|
+
(0, kizu_1.test)('formatChangeSetPreviewLines empty changes', (assert) => {
|
|
36
|
+
const lines = (0, formatChangeSet_1.formatChangeSetPreviewLines)([], { color: false });
|
|
37
|
+
assert.equal(lines.length, 1);
|
|
38
|
+
assert.equal(lines[0].includes('no resource-level'), true);
|
|
39
|
+
});
|
|
40
|
+
(0, kizu_1.test)('formatChangeSetPreviewLines counts non-resource-only changes', (assert) => {
|
|
41
|
+
const changes = [
|
|
42
|
+
{
|
|
43
|
+
Type: 'Resource',
|
|
44
|
+
HookInvocationCount: 1,
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
const lines = (0, formatChangeSet_1.formatChangeSetPreviewLines)(changes, { color: false });
|
|
48
|
+
assert.equal(lines.length, 1);
|
|
49
|
+
assert.equal(lines[0].includes('other change'), true);
|
|
50
|
+
});
|
|
51
|
+
(0, kizu_1.test)('formatChangeSetPreviewLines footer when mixed resource and non-resource', (assert) => {
|
|
52
|
+
const changes = [
|
|
53
|
+
{
|
|
54
|
+
Type: 'Resource',
|
|
55
|
+
ResourceChange: {
|
|
56
|
+
Action: 'Add',
|
|
57
|
+
LogicalResourceId: 'R',
|
|
58
|
+
ResourceType: 'AWS::SNS::Topic',
|
|
59
|
+
Replacement: 'False',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
Type: 'Resource',
|
|
64
|
+
HookInvocationCount: 2,
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
const lines = (0, formatChangeSet_1.formatChangeSetPreviewLines)(changes, { color: false });
|
|
68
|
+
const text = lines.join('\n');
|
|
69
|
+
assert.equal(text.includes('AWS::SNS::Topic'), true);
|
|
70
|
+
assert.equal(text.includes('non-resource'), true);
|
|
71
|
+
});
|
|
72
|
+
//# sourceMappingURL=formatChangeSet.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatChangeSet.spec.js","sourceRoot":"","sources":["../../src/lib/formatChangeSet.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI: preview stack changes without executing (build change set, print table, delete change set).
|
|
3
|
+
* CREATE vs UPDATE matches whether the stack already exists.
|
|
4
|
+
*/
|
|
5
|
+
export declare function previewStack(stackName: string, templatePath: string, paramsPath?: string): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=previewStack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewStack.d.ts","sourceRoot":"","sources":["../src/previewStack.ts"],"names":[],"mappings":"AAMA;;;GAGG;AACH,wBAAsB,YAAY,CAC9B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.previewStack = previewStack;
|
|
37
|
+
const client_cloudformation_1 = require("@aws-sdk/client-cloudformation");
|
|
38
|
+
const cfn = __importStar(require("./lib/cfn"));
|
|
39
|
+
const loadTemplateAndParams_1 = require("./cli/loadTemplateAndParams");
|
|
40
|
+
const validateTemplate_1 = require("./cli/validateTemplate");
|
|
41
|
+
const output_1 = require("./lib/output");
|
|
42
|
+
/**
|
|
43
|
+
* CLI: preview stack changes without executing (build change set, print table, delete change set).
|
|
44
|
+
* CREATE vs UPDATE matches whether the stack already exists.
|
|
45
|
+
*/
|
|
46
|
+
async function previewStack(stackName, templatePath, paramsPath) {
|
|
47
|
+
cfn.initCloudFormationClient();
|
|
48
|
+
const { template, params } = await (0, loadTemplateAndParams_1.loadTemplateAndParams)(templatePath, paramsPath);
|
|
49
|
+
const existing = await cfn.getStackByName(stackName);
|
|
50
|
+
if (existing?.StackStatus === client_cloudformation_1.StackStatus.ROLLBACK_COMPLETE) {
|
|
51
|
+
(0, output_1.warn)(`Stack ${stackName} is in ROLLBACK_COMPLETE; update-stack would delete and recreate it. `
|
|
52
|
+
+ 'Preview cannot model that flow.');
|
|
53
|
+
throw new Error('cannot preview: stack is ROLLBACK_COMPLETE — delete the stack or run update-stack (delete + create) first.');
|
|
54
|
+
}
|
|
55
|
+
console.log('validating template...');
|
|
56
|
+
await (0, validateTemplate_1.validateTemplateOrExit)(template);
|
|
57
|
+
const operation = existing ? 'UPDATE' : 'CREATE';
|
|
58
|
+
(0, output_1.info)(`${output_1.symbols.arrow} Preview ${(0, output_1.cyan)(operation)} for stack ${(0, output_1.cyan)(stackName)}`);
|
|
59
|
+
await cfn.previewChangeSet(stackName, { body: template, params }, operation);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=previewStack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"previewStack.js","sourceRoot":"","sources":["../src/previewStack.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,oCAiCC;AA3CD,0EAA2D;AAC3D,+CAAiC;AACjC,uEAAkE;AAClE,6DAA8D;AAC9D,yCAAuD;AAEvD;;;GAGG;AACI,KAAK,UAAU,YAAY,CAC9B,SAAiB,EACjB,YAAoB,EACpB,UAAmB;IAGnB,GAAG,CAAC,wBAAwB,EAAE,CAAC;IAE/B,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAC,GAAG,MAAM,IAAA,6CAAqB,EAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAErD,IAAI,QAAQ,EAAE,WAAW,KAAK,mCAAW,CAAC,iBAAiB,EAAE,CAAC;QAE1D,IAAA,aAAI,EACA,SAAS,SAAS,uEAAuE;cACvF,iCAAiC,CACtC,CAAC;QAEF,MAAM,IAAI,KAAK,CACX,4GAA4G,CAC/G,CAAC;IAEN,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,MAAM,IAAA,yCAAsB,EAAC,QAAQ,CAAC,CAAC;IAEvC,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEjD,IAAA,aAAI,EAAC,GAAG,gBAAO,CAAC,KAAK,YAAY,IAAA,aAAI,EAAC,SAAS,CAAC,cAAc,IAAA,aAAI,EAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAEjF,MAAM,GAAG,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAC,EAAE,SAAS,CAAC,CAAC;AAE/E,CAAC"}
|
package/dist/updateStack.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* CLI handler: update an existing CloudFormation stack.
|
|
3
3
|
*/
|
|
4
|
-
export declare function updateStack(stackName: string, templatePath: string, paramsPath?: string): Promise<void>;
|
|
4
|
+
export declare function updateStack(stackName: string, templatePath: string, paramsPath?: string, create?: boolean): Promise<void>;
|
|
5
5
|
//# sourceMappingURL=updateStack.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateStack.d.ts","sourceRoot":"","sources":["../src/updateStack.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAsB,WAAW,CAC7B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"updateStack.d.ts","sourceRoot":"","sources":["../src/updateStack.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAsB,WAAW,CAC7B,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EACnB,MAAM,GAAE,OAAe,GACxB,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|
package/dist/updateStack.js
CHANGED
|
@@ -41,12 +41,19 @@ const log_1 = require("./cli/log");
|
|
|
41
41
|
/**
|
|
42
42
|
* CLI handler: update an existing CloudFormation stack.
|
|
43
43
|
*/
|
|
44
|
-
async function updateStack(stackName, templatePath, paramsPath) {
|
|
44
|
+
async function updateStack(stackName, templatePath, paramsPath, create = false) {
|
|
45
45
|
cfn.initCloudFormationClient();
|
|
46
46
|
const { template, params } = await (0, loadTemplateAndParams_1.loadTemplateAndParams)(templatePath, paramsPath);
|
|
47
47
|
const existing = await cfn.getStackByName(stackName);
|
|
48
48
|
if (!existing) {
|
|
49
|
-
|
|
49
|
+
if (!create) {
|
|
50
|
+
throw new Error('stack not found, try create command');
|
|
51
|
+
}
|
|
52
|
+
console.log('validating template...');
|
|
53
|
+
await (0, validateTemplate_1.validateTemplateOrExit)(template);
|
|
54
|
+
(0, log_1.logStackAction)(stackName, 'creating', params);
|
|
55
|
+
await cfn.createStack(stackName, { body: template, params });
|
|
56
|
+
return;
|
|
50
57
|
}
|
|
51
58
|
console.log('validating template...');
|
|
52
59
|
await (0, validateTemplate_1.validateTemplateOrExit)(template);
|
package/dist/updateStack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateStack.js","sourceRoot":"","sources":["../src/updateStack.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,
|
|
1
|
+
{"version":3,"file":"updateStack.js","sourceRoot":"","sources":["../src/updateStack.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,kCAoCC;AA5CD,+CAAiC;AACjC,uEAAkE;AAClE,6DAA8D;AAC9D,mCAAyC;AAEzC;;GAEG;AACI,KAAK,UAAU,WAAW,CAC7B,SAAiB,EACjB,YAAoB,EACpB,UAAmB,EACnB,SAAkB,KAAK;IAGvB,GAAG,CAAC,wBAAwB,EAAE,CAAC;IAE/B,MAAM,EAAC,QAAQ,EAAE,MAAM,EAAC,GAAG,MAAM,IAAA,6CAAqB,EAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;IAErD,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEZ,IAAI,CAAC,MAAM,EAAE,CAAC;YAEV,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAE3D,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;QACtC,MAAM,IAAA,yCAAsB,EAAC,QAAQ,CAAC,CAAC;QAEvC,IAAA,oBAAc,EAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,GAAG,CAAC,WAAW,CAAC,SAAS,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAC,CAAC,CAAC;QAE3D,OAAO;IAEX,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;IACtC,MAAM,IAAA,yCAAsB,EAAC,QAAQ,CAAC,CAAC;IAEvC,IAAA,oBAAc,EAAC,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,MAAM,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAC,CAAC,CAAC;AAE9D,CAAC"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"placeholder.spec.d.ts","sourceRoot":"","sources":["../../src/lib/placeholder.spec.ts"],"names":[],"mappings":""}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const kizu_1 = require("kizu");
|
|
4
|
-
(0, kizu_1.test)('awscfn test suite placeholder', (assert) => {
|
|
5
|
-
// No tests yet; remove this file when adding real specs.
|
|
6
|
-
assert.equal(1, 1);
|
|
7
|
-
});
|
|
8
|
-
//# sourceMappingURL=placeholder.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"placeholder.spec.js","sourceRoot":"","sources":["../../src/lib/placeholder.spec.ts"],"names":[],"mappings":";;AAAA,+BAA0B;AAE1B,IAAA,WAAI,EAAC,+BAA+B,EAAE,CAAC,MAAM,EAAE,EAAE;IAE7C,yDAAyD;IACzD,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEvB,CAAC,CAAC,CAAC"}
|