@go-to-k/cdkd 0.28.0 → 0.28.1
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 +27 -2
- package/dist/cli.js +49 -14
- package/dist/cli.js.map +2 -2
- package/dist/go-to-k-cdkd-0.28.1.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.28.0.tgz +0 -0
package/README.md
CHANGED
|
@@ -678,6 +678,20 @@ out of a larger stack — for example, you have one S3 bucket that was
|
|
|
678
678
|
created manually that you want cdkd to manage, while the rest of the
|
|
679
679
|
stack will be deployed fresh.
|
|
680
680
|
|
|
681
|
+
**Selective mode is non-destructive.** When state already exists for
|
|
682
|
+
the stack, listed resources are **merged** into it: unlisted entries
|
|
683
|
+
already in state are preserved (no `--force` needed). `--force` is
|
|
684
|
+
only required when a listed override would overwrite a resource
|
|
685
|
+
already in state — that's the one case where the merge is destructive.
|
|
686
|
+
This is the right command for "I have a deployed stack and want to
|
|
687
|
+
adopt one more resource into it":
|
|
688
|
+
|
|
689
|
+
```bash
|
|
690
|
+
# Existing state has Queue + Topic; add Bucket without affecting them.
|
|
691
|
+
cdkd import MyStack --resource MyBucket=my-bucket-name
|
|
692
|
+
# Resulting state: Queue + Topic (preserved) + Bucket (newly imported).
|
|
693
|
+
```
|
|
694
|
+
|
|
681
695
|
### Mode 3: hybrid (`--auto` with overrides)
|
|
682
696
|
|
|
683
697
|
```bash
|
|
@@ -698,7 +712,18 @@ the rest by tag automatically.
|
|
|
698
712
|
| ----------- | ----------------------------------------------------------------------------- |
|
|
699
713
|
| `--dry-run` | Preview what would be imported. State is NOT written. |
|
|
700
714
|
| `--yes` | Skip the confirmation prompt before writing state. |
|
|
701
|
-
| `--force` |
|
|
715
|
+
| `--force` | Confirm a destructive write to existing state — see below. |
|
|
716
|
+
|
|
717
|
+
`--force` is only needed when the import would lose data:
|
|
718
|
+
|
|
719
|
+
- **Auto / whole-stack mode + existing state**: required. The resource
|
|
720
|
+
map is rebuilt from the template, so any state entry not re-imported
|
|
721
|
+
is dropped.
|
|
722
|
+
- **Selective mode + listed override already in state**: required.
|
|
723
|
+
The listed entry is overwritten with the new physical id.
|
|
724
|
+
- **Selective mode without a conflict (pure merge)**: not required.
|
|
725
|
+
Unlisted state entries are preserved automatically.
|
|
726
|
+
- **No existing state (first-time import)**: not required.
|
|
702
727
|
|
|
703
728
|
### After import
|
|
704
729
|
|
|
@@ -746,7 +771,7 @@ table to predict behavior when migrating from `cdk import`.
|
|
|
746
771
|
| Bootstrap requirement | Bootstrap v12+ (deploy role needs to read the encrypted staging bucket). | cdkd's own state bucket; no CDK bootstrap version requirement. |
|
|
747
772
|
| Resource-type coverage | Whatever [CloudFormation supports for import](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/resource-import-supported-resources.html). | The set of cdkd providers that implement `import()` (see [CLAUDE.md](CLAUDE.md) for the current list). For any other CC-API-supported type, use `--resource <id>=<physical>` to drive the Cloud Control API fallback. The two lists overlap heavily but are not identical. |
|
|
748
773
|
| Confirmation prompt before writing state | n/a (CloudFormation operates atomically). | Yes — cdkd asks before writing the state file. Skip with `--yes`. |
|
|
749
|
-
| `--force` | "Continue even if the diff includes updates or deletions" — about diff strictness. | "
|
|
774
|
+
| `--force` | "Continue even if the diff includes updates or deletions" — about diff strictness. | "Confirm a destructive write to existing state" — required for auto/whole-stack rebuild and for overwriting a listed entry already in state; not required for a pure selective merge. **Same flag name, different meaning.** |
|
|
750
775
|
| `--dry-run` | Implied by `--no-execute` (creates the changeset without executing). | Native: shows the import plan and exits without writing state. |
|
|
751
776
|
|
|
752
777
|
#### Practical implications when migrating from `cdk import`
|
package/dist/cli.js
CHANGED
|
@@ -35259,12 +35259,6 @@ async function importCommand(stackArg, options) {
|
|
|
35259
35259
|
}
|
|
35260
35260
|
const targetRegion = stackInfo.region || region;
|
|
35261
35261
|
logger.info(`Target stack: ${stackInfo.stackName} (${targetRegion})`);
|
|
35262
|
-
const existing = await stateBackend.stateExists(stackInfo.stackName, targetRegion);
|
|
35263
|
-
if (existing && !options.force) {
|
|
35264
|
-
throw new Error(
|
|
35265
|
-
`State already exists for stack '${stackInfo.stackName}' (${targetRegion}). Pass --force to overwrite. (cdkd state import rebuilds the resource map from AWS, so the existing state \u2014 including any drift you've manually edited \u2014 will be lost.)`
|
|
35266
|
-
);
|
|
35267
|
-
}
|
|
35268
35262
|
const overrides = parseResourceOverrides(
|
|
35269
35263
|
options.resource,
|
|
35270
35264
|
options.resourceMapping,
|
|
@@ -35279,6 +35273,34 @@ async function importCommand(stackArg, options) {
|
|
|
35279
35273
|
`Selective mode: only importing the ${overrides.size} resource(s) you listed (${[...overrides.keys()].join(", ")}). Pass --auto to also tag-import the rest.`
|
|
35280
35274
|
);
|
|
35281
35275
|
}
|
|
35276
|
+
const existingResult = await stateBackend.getState(stackInfo.stackName, targetRegion);
|
|
35277
|
+
const existingState = existingResult?.state ?? null;
|
|
35278
|
+
const existingEtag = existingResult?.etag;
|
|
35279
|
+
const migrationPending = existingResult?.migrationPending ?? false;
|
|
35280
|
+
if (existingState) {
|
|
35281
|
+
if (!selectiveMode) {
|
|
35282
|
+
if (!options.force) {
|
|
35283
|
+
throw new Error(
|
|
35284
|
+
`State already exists for stack '${stackInfo.stackName}' (${targetRegion}). Auto / whole-stack import rebuilds the entire resource map from the template, which would drop any state entry not re-imported. Pass --force to confirm. To add specific resources without affecting unlisted ones, use --resource <id>=<physicalId> (selective merge \u2014 no --force needed).`
|
|
35285
|
+
);
|
|
35286
|
+
}
|
|
35287
|
+
} else {
|
|
35288
|
+
const conflicts = [...overrides.keys()].filter(
|
|
35289
|
+
(id) => Object.prototype.hasOwnProperty.call(existingState.resources, id)
|
|
35290
|
+
);
|
|
35291
|
+
if (conflicts.length > 0 && !options.force) {
|
|
35292
|
+
throw new Error(
|
|
35293
|
+
`Selective import would overwrite resource(s) already in state: ${conflicts.join(", ")}. Pass --force to confirm the overwrite, or remove these IDs from --resource / --resource-mapping.`
|
|
35294
|
+
);
|
|
35295
|
+
}
|
|
35296
|
+
const preservedCount = Object.keys(existingState.resources).filter(
|
|
35297
|
+
(id) => !overrides.has(id)
|
|
35298
|
+
).length;
|
|
35299
|
+
logger.info(
|
|
35300
|
+
`Merging into existing state for ${stackInfo.stackName} (${targetRegion}): preserving ${preservedCount} unlisted resource(s)` + (conflicts.length > 0 ? `, overwriting ${conflicts.length} listed entry(ies)` : "")
|
|
35301
|
+
);
|
|
35302
|
+
}
|
|
35303
|
+
}
|
|
35282
35304
|
const template = stackInfo.template;
|
|
35283
35305
|
const templateParser = new TemplateParser();
|
|
35284
35306
|
const resources = collectImportableResources(template);
|
|
@@ -35329,8 +35351,12 @@ async function importCommand(stackArg, options) {
|
|
|
35329
35351
|
return;
|
|
35330
35352
|
}
|
|
35331
35353
|
if (!options.yes) {
|
|
35354
|
+
const importedCount = importedRows.length;
|
|
35355
|
+
const preservedCount = selectiveMode && existingState ? Object.keys(existingState.resources).filter((id) => !overrides.has(id)).length : 0;
|
|
35356
|
+
const totalAfter = importedCount + preservedCount;
|
|
35357
|
+
const breakdown = preservedCount > 0 ? ` (${importedCount} new/overwritten + ${preservedCount} preserved)` : "";
|
|
35332
35358
|
const ok = await confirmPrompt3(
|
|
35333
|
-
`Write state for ${stackInfo.stackName} (${targetRegion}) with ${
|
|
35359
|
+
`Write state for ${stackInfo.stackName} (${targetRegion}) with ${totalAfter} resource(s)${breakdown}?`
|
|
35334
35360
|
);
|
|
35335
35361
|
if (!ok) {
|
|
35336
35362
|
logger.info("Import cancelled.");
|
|
@@ -35342,9 +35368,18 @@ async function importCommand(stackArg, options) {
|
|
|
35342
35368
|
targetRegion,
|
|
35343
35369
|
rows,
|
|
35344
35370
|
templateParser,
|
|
35345
|
-
template
|
|
35371
|
+
template,
|
|
35372
|
+
existingState,
|
|
35373
|
+
selectiveMode
|
|
35346
35374
|
);
|
|
35347
|
-
|
|
35375
|
+
const saveOptions = {};
|
|
35376
|
+
if (existingEtag) {
|
|
35377
|
+
saveOptions.expectedEtag = existingEtag;
|
|
35378
|
+
}
|
|
35379
|
+
if (migrationPending) {
|
|
35380
|
+
saveOptions.migrateLegacy = true;
|
|
35381
|
+
}
|
|
35382
|
+
await stateBackend.saveState(stackInfo.stackName, targetRegion, stackState, saveOptions);
|
|
35348
35383
|
logger.info(`\u2713 State written: ${stackInfo.stackName} (${targetRegion})`);
|
|
35349
35384
|
logger.info(
|
|
35350
35385
|
` ${importedRows.length} resource(s) imported. Run 'cdkd diff' to see how the imported state lines up with the template.`
|
|
@@ -35500,8 +35535,8 @@ function collectImportableResources(template) {
|
|
|
35500
35535
|
}
|
|
35501
35536
|
return out;
|
|
35502
35537
|
}
|
|
35503
|
-
function buildStackState(stackName, region, rows, templateParser, template) {
|
|
35504
|
-
const resources = {};
|
|
35538
|
+
function buildStackState(stackName, region, rows, templateParser, template, existingState, selectiveMode) {
|
|
35539
|
+
const resources = selectiveMode && existingState ? { ...existingState.resources } : {};
|
|
35505
35540
|
for (const row of rows) {
|
|
35506
35541
|
if (row.outcome !== "imported" || !row.physicalId)
|
|
35507
35542
|
continue;
|
|
@@ -35522,7 +35557,7 @@ function buildStackState(stackName, region, rows, templateParser, template) {
|
|
|
35522
35557
|
stackName,
|
|
35523
35558
|
region,
|
|
35524
35559
|
resources,
|
|
35525
|
-
outputs: {},
|
|
35560
|
+
outputs: existingState?.outputs ?? {},
|
|
35526
35561
|
lastModified: Date.now()
|
|
35527
35562
|
};
|
|
35528
35563
|
}
|
|
@@ -35597,7 +35632,7 @@ function createImportCommand() {
|
|
|
35597
35632
|
false
|
|
35598
35633
|
).option("--dry-run", "Show planned imports without writing state", false).option(
|
|
35599
35634
|
"--force",
|
|
35600
|
-
"
|
|
35635
|
+
"Confirm a destructive write to existing state. Required for auto / whole-stack import when state already exists (rebuilds the entire resource map). Also required in selective mode if a listed override would overwrite a resource already in state. Not needed for a pure selective merge (adding new resources without touching unlisted entries).",
|
|
35601
35636
|
false
|
|
35602
35637
|
).action(withErrorHandling(importCommand));
|
|
35603
35638
|
[...commonOptions, ...appOptions, ...stateOptions, ...contextOptions].forEach(
|
|
@@ -35636,7 +35671,7 @@ function reorderArgs(argv) {
|
|
|
35636
35671
|
}
|
|
35637
35672
|
async function main() {
|
|
35638
35673
|
const program = new Command13();
|
|
35639
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.28.
|
|
35674
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.28.1");
|
|
35640
35675
|
program.addCommand(createBootstrapCommand());
|
|
35641
35676
|
program.addCommand(createSynthCommand());
|
|
35642
35677
|
program.addCommand(createListCommand());
|