@go-to-k/cdkd 0.85.0 → 0.87.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/dist/cli.js +235 -50
- package/dist/cli.js.map +3 -3
- package/dist/go-to-k-cdkd-0.87.0.tgz +0 -0
- package/package.json +1 -1
- package/dist/go-to-k-cdkd-0.85.0.tgz +0 -0
package/dist/cli.js
CHANGED
|
@@ -79270,7 +79270,8 @@ import {
|
|
|
79270
79270
|
DescribeTypeCommand,
|
|
79271
79271
|
DeleteChangeSetCommand,
|
|
79272
79272
|
waitUntilChangeSetCreateComplete,
|
|
79273
|
-
waitUntilStackImportComplete
|
|
79273
|
+
waitUntilStackImportComplete,
|
|
79274
|
+
waitUntilStackUpdateComplete as waitUntilStackUpdateComplete2
|
|
79274
79275
|
} from "@aws-sdk/client-cloudformation";
|
|
79275
79276
|
init_aws_clients();
|
|
79276
79277
|
var NEVER_IMPORTABLE_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -79317,6 +79318,38 @@ var PRIMARY_IDENTIFIER_FALLBACK = {
|
|
|
79317
79318
|
"AWS::Cognito::UserPool": "UserPoolId",
|
|
79318
79319
|
"AWS::ECR::Repository": "RepositoryName"
|
|
79319
79320
|
};
|
|
79321
|
+
var COMPOSITE_ID_SPLITTERS = {
|
|
79322
|
+
// cdkd stores `restApiId|resourceId|httpMethod` (apigateway-provider.ts);
|
|
79323
|
+
// CFn primary identifier is [RestApiId, ResourceId, HttpMethod] — same order.
|
|
79324
|
+
"AWS::ApiGateway::Method": (id) => {
|
|
79325
|
+
const parts = id.split("|");
|
|
79326
|
+
if (parts.length !== 3) {
|
|
79327
|
+
throw new Error(
|
|
79328
|
+
`expected 3 parts (restApiId|resourceId|httpMethod), got ${parts.length}: '${id}'`
|
|
79329
|
+
);
|
|
79330
|
+
}
|
|
79331
|
+
return { RestApiId: parts[0], ResourceId: parts[1], HttpMethod: parts[2] };
|
|
79332
|
+
},
|
|
79333
|
+
// cdkd stores `restApiId|resourceId` (apigateway-provider.ts);
|
|
79334
|
+
// CFn primary identifier is [RestApiId, ResourceId].
|
|
79335
|
+
"AWS::ApiGateway::Resource": (id) => {
|
|
79336
|
+
const parts = id.split("|");
|
|
79337
|
+
if (parts.length !== 2) {
|
|
79338
|
+
throw new Error(`expected 2 parts (restApiId|resourceId), got ${parts.length}: '${id}'`);
|
|
79339
|
+
}
|
|
79340
|
+
return { RestApiId: parts[0], ResourceId: parts[1] };
|
|
79341
|
+
},
|
|
79342
|
+
// cdkd stores `IGW|VpcId` (ec2-provider.ts);
|
|
79343
|
+
// CFn primary identifier is [VpcId, InternetGatewayId] — DIFFERENT order
|
|
79344
|
+
// from cdkd. Splitter reorders explicitly.
|
|
79345
|
+
"AWS::EC2::VPCGatewayAttachment": (id) => {
|
|
79346
|
+
const parts = id.split("|");
|
|
79347
|
+
if (parts.length !== 2) {
|
|
79348
|
+
throw new Error(`expected 2 parts (IGW|VpcId), got ${parts.length}: '${id}'`);
|
|
79349
|
+
}
|
|
79350
|
+
return { VpcId: parts[1], InternetGatewayId: parts[0] };
|
|
79351
|
+
}
|
|
79352
|
+
};
|
|
79320
79353
|
async function exportCommand(stackArg, options) {
|
|
79321
79354
|
const logger = getLogger();
|
|
79322
79355
|
if (options.verbose) {
|
|
@@ -79425,39 +79458,90 @@ async function exportCommand(stackArg, options) {
|
|
|
79425
79458
|
}
|
|
79426
79459
|
}
|
|
79427
79460
|
try {
|
|
79428
|
-
const {
|
|
79429
|
-
|
|
79461
|
+
const { phase1Imports, phase2Creates, blocked } = await buildImportPlan(
|
|
79462
|
+
state,
|
|
79463
|
+
template,
|
|
79464
|
+
awsClients.cloudFormation
|
|
79465
|
+
);
|
|
79466
|
+
if (blocked.length > 0) {
|
|
79467
|
+
logger.error("The following resources block migration:");
|
|
79468
|
+
for (const b of blocked) {
|
|
79469
|
+
logger.error(` - ${b.logicalId} (${b.resourceType}): ${b.reason}`);
|
|
79470
|
+
}
|
|
79471
|
+
throw new Error(
|
|
79472
|
+
`${blocked.length} resource(s) block migration. Either destroy them first (cdkd destroy / cdkd state destroy cherry-picked), or remove them from the CDK app and re-synthesize.`
|
|
79473
|
+
);
|
|
79474
|
+
}
|
|
79475
|
+
if (phase2Creates.length > 0 && !options.includeNonImportable) {
|
|
79430
79476
|
logger.error("The following resources cannot be imported into CloudFormation:");
|
|
79431
|
-
for (const
|
|
79432
|
-
logger.error(` - ${
|
|
79477
|
+
for (const p of phase2Creates) {
|
|
79478
|
+
logger.error(` - ${p.logicalId} (${p.resourceType}): CFn cannot import this type`);
|
|
79433
79479
|
}
|
|
79434
79480
|
throw new Error(
|
|
79435
|
-
`${
|
|
79481
|
+
`${phase2Creates.length} non-importable resource(s) detected (Custom::*). Pass --include-non-importable to run a 2-phase migration: phase 1 imports the importable resources; phase 2 CFn-CREATEs the non-importable ones (re-invoking each Custom Resource's backing Lambda onCreate handler \u2014 make sure those are idempotent). Or destroy these resources first.`
|
|
79436
79482
|
);
|
|
79437
79483
|
}
|
|
79438
|
-
if (
|
|
79439
|
-
logger.warn("No resources to
|
|
79484
|
+
if (phase1Imports.length === 0 && phase2Creates.length === 0) {
|
|
79485
|
+
logger.warn("No resources to migrate \u2014 cdkd state is empty.");
|
|
79440
79486
|
return;
|
|
79441
79487
|
}
|
|
79442
|
-
|
|
79488
|
+
if (phase1Imports.length === 0) {
|
|
79489
|
+
throw new Error(
|
|
79490
|
+
"No importable resources in the template. CloudFormation IMPORT changeset requires at least one importable resource for phase 1."
|
|
79491
|
+
);
|
|
79492
|
+
}
|
|
79493
|
+
printPlan(phase1Imports, cfnStackName);
|
|
79494
|
+
if (phase2Creates.length > 0) {
|
|
79495
|
+
logger.info(`Phase 2 will CREATE ${phase2Creates.length} non-importable resource(s):`);
|
|
79496
|
+
for (const p of phase2Creates) {
|
|
79497
|
+
logger.info(` ${p.logicalId} (${p.resourceType})`);
|
|
79498
|
+
}
|
|
79499
|
+
logger.info("");
|
|
79500
|
+
}
|
|
79443
79501
|
if (options.dryRun) {
|
|
79444
79502
|
logger.info("--dry-run: no CloudFormation changeset will be created.");
|
|
79445
79503
|
return;
|
|
79446
79504
|
}
|
|
79447
79505
|
if (!options.yes) {
|
|
79506
|
+
const phase2Note = phase2Creates.length > 0 ? ` Phase 2 will then CREATE ${phase2Creates.length} non-importable resource(s) (invoking each Custom Resource's onCreate handler).` : "";
|
|
79448
79507
|
const ok = await confirmPrompt6(
|
|
79449
|
-
`Create CloudFormation stack '${cfnStackName}' by importing ${
|
|
79508
|
+
`Create CloudFormation stack '${cfnStackName}' by importing ${phase1Imports.length} resource(s) from cdkd state '${resolvedStackName}' (${targetRegion})?` + phase2Note + ` AWS resources are unchanged on import. cdkd state for '${resolvedStackName}' will be deleted on success.`
|
|
79450
79509
|
);
|
|
79451
79510
|
if (!ok) {
|
|
79452
79511
|
logger.info("Migration cancelled. cdkd state and CloudFormation are unchanged.");
|
|
79453
79512
|
return;
|
|
79454
79513
|
}
|
|
79455
79514
|
}
|
|
79456
|
-
const
|
|
79457
|
-
await executeImportChangeSet(
|
|
79515
|
+
const phase1Template = filterTemplateForImport(template, phase1Imports);
|
|
79516
|
+
await executeImportChangeSet(
|
|
79517
|
+
awsClients.cloudFormation,
|
|
79518
|
+
cfnStackName,
|
|
79519
|
+
phase1Template,
|
|
79520
|
+
phase1Imports
|
|
79521
|
+
);
|
|
79458
79522
|
logger.info(
|
|
79459
|
-
`\u2713 CloudFormation stack '${cfnStackName}' created via IMPORT. ${
|
|
79523
|
+
`\u2713 Phase 1: CloudFormation stack '${cfnStackName}' created via IMPORT. ${phase1Imports.length} resource(s) imported.`
|
|
79460
79524
|
);
|
|
79525
|
+
if (phase2Creates.length > 0) {
|
|
79526
|
+
try {
|
|
79527
|
+
await executeUpdateChangeSet(awsClients.cloudFormation, cfnStackName, template);
|
|
79528
|
+
logger.info(`\u2713 Phase 2: ${phase2Creates.length} non-importable resource(s) CREATEd.`);
|
|
79529
|
+
} catch (err) {
|
|
79530
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79531
|
+
throw new Error(
|
|
79532
|
+
`Phase 1 (IMPORT) succeeded; phase 2 (UPDATE) failed: ${msg}
|
|
79533
|
+
|
|
79534
|
+
The CloudFormation stack '${cfnStackName}' now contains the imported resources but is missing the ${phase2Creates.length} non-importable resource(s). cdkd state is UNCHANGED so you can inspect what's in it, but DO NOT run \`cdkd deploy\` against this stack (the imported resources are now CFn-managed). To recover:
|
|
79535
|
+
1. Fix the failure cause (typically an onCreate Lambda error).
|
|
79536
|
+
2. Re-run the phase 2 UPDATE manually with the full synth template:
|
|
79537
|
+
aws cloudformation create-change-set --stack-name ${cfnStackName} \\
|
|
79538
|
+
--change-set-name cdkd-phase2-retry --change-set-type UPDATE \\
|
|
79539
|
+
--template-body file://<full-template.json>
|
|
79540
|
+
3. Once phase 2 succeeds, run: cdkd state orphan ${resolvedStackName}
|
|
79541
|
+
to clean up cdkd's stale state record.`
|
|
79542
|
+
);
|
|
79543
|
+
}
|
|
79544
|
+
}
|
|
79461
79545
|
await stateBackend.deleteState(resolvedStackName, targetRegion);
|
|
79462
79546
|
logger.info(
|
|
79463
79547
|
`cdkd state for '${resolvedStackName}' (${targetRegion}) removed. Manage the stack with 'cdk deploy' or 'aws cloudformation' from here on.`
|
|
@@ -79553,13 +79637,17 @@ async function assertCfnStackAbsent(cfnClient, stackName) {
|
|
|
79553
79637
|
throw err;
|
|
79554
79638
|
}
|
|
79555
79639
|
}
|
|
79640
|
+
function isPhase2CreatableType(resourceType) {
|
|
79641
|
+
return resourceType.startsWith("Custom::");
|
|
79642
|
+
}
|
|
79556
79643
|
async function buildImportPlan(state, template, cfnClient) {
|
|
79557
79644
|
const templateResources = template["Resources"];
|
|
79558
79645
|
if (!templateResources || typeof templateResources !== "object" || Array.isArray(templateResources)) {
|
|
79559
79646
|
throw new Error("Template has no Resources section.");
|
|
79560
79647
|
}
|
|
79561
|
-
const
|
|
79562
|
-
const
|
|
79648
|
+
const phase1Imports = [];
|
|
79649
|
+
const phase2Creates = [];
|
|
79650
|
+
const blocked = [];
|
|
79563
79651
|
const identifierCache = /* @__PURE__ */ new Map();
|
|
79564
79652
|
for (const [logicalId, raw] of Object.entries(templateResources)) {
|
|
79565
79653
|
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
@@ -79568,49 +79656,88 @@ async function buildImportPlan(state, template, cfnClient) {
|
|
|
79568
79656
|
const resourceType = resource.Type ?? "";
|
|
79569
79657
|
if (!resourceType)
|
|
79570
79658
|
continue;
|
|
79659
|
+
if (resourceType === "AWS::CDK::Metadata") {
|
|
79660
|
+
continue;
|
|
79661
|
+
}
|
|
79571
79662
|
if (isNeverImportableType(resourceType)) {
|
|
79572
|
-
if (resourceType
|
|
79573
|
-
|
|
79574
|
-
|
|
79575
|
-
|
|
79576
|
-
|
|
79577
|
-
|
|
79578
|
-
|
|
79663
|
+
if (isPhase2CreatableType(resourceType)) {
|
|
79664
|
+
phase2Creates.push({ logicalId, resourceType });
|
|
79665
|
+
} else {
|
|
79666
|
+
blocked.push({
|
|
79667
|
+
logicalId,
|
|
79668
|
+
resourceType,
|
|
79669
|
+
reason: "CloudFormation cannot import or recreate this resource type"
|
|
79670
|
+
});
|
|
79671
|
+
}
|
|
79579
79672
|
continue;
|
|
79580
79673
|
}
|
|
79581
79674
|
const stateEntry = state.resources[logicalId];
|
|
79582
79675
|
if (!stateEntry || !stateEntry.physicalId) {
|
|
79583
|
-
|
|
79676
|
+
blocked.push({
|
|
79584
79677
|
logicalId,
|
|
79585
79678
|
resourceType,
|
|
79586
79679
|
reason: "no entry in cdkd state (resource is in template but was not deployed by cdkd)"
|
|
79587
79680
|
});
|
|
79588
79681
|
continue;
|
|
79589
79682
|
}
|
|
79590
|
-
let
|
|
79683
|
+
let resourceIdentifier;
|
|
79591
79684
|
try {
|
|
79592
|
-
|
|
79685
|
+
resourceIdentifier = await resolveResourceIdentifier(
|
|
79686
|
+
resourceType,
|
|
79687
|
+
stateEntry.physicalId,
|
|
79688
|
+
cfnClient,
|
|
79689
|
+
identifierCache
|
|
79690
|
+
);
|
|
79593
79691
|
} catch (err) {
|
|
79594
|
-
|
|
79692
|
+
blocked.push({
|
|
79595
79693
|
logicalId,
|
|
79596
79694
|
resourceType,
|
|
79597
|
-
reason: "could not resolve
|
|
79695
|
+
reason: "could not resolve resource identifier: " + (err instanceof Error ? err.message : String(err))
|
|
79598
79696
|
});
|
|
79599
79697
|
continue;
|
|
79600
79698
|
}
|
|
79601
|
-
|
|
79699
|
+
phase1Imports.push({
|
|
79602
79700
|
logicalId,
|
|
79603
79701
|
resourceType,
|
|
79604
79702
|
physicalId: stateEntry.physicalId,
|
|
79605
|
-
|
|
79703
|
+
resourceIdentifier
|
|
79606
79704
|
});
|
|
79607
79705
|
}
|
|
79608
|
-
return {
|
|
79706
|
+
return { phase1Imports, phase2Creates, blocked };
|
|
79609
79707
|
}
|
|
79610
|
-
async function
|
|
79611
|
-
|
|
79612
|
-
if (
|
|
79613
|
-
|
|
79708
|
+
async function resolveResourceIdentifier(resourceType, physicalId, cfnClient, cache2) {
|
|
79709
|
+
let entry = cache2.get(resourceType);
|
|
79710
|
+
if (entry === void 0) {
|
|
79711
|
+
entry = await fetchPrimaryIdentifier(resourceType, cfnClient);
|
|
79712
|
+
cache2.set(resourceType, entry);
|
|
79713
|
+
}
|
|
79714
|
+
if (entry.fields.length === 1) {
|
|
79715
|
+
return { [entry.fields[0]]: physicalId };
|
|
79716
|
+
}
|
|
79717
|
+
const splitter = COMPOSITE_ID_SPLITTERS[resourceType];
|
|
79718
|
+
if (!splitter) {
|
|
79719
|
+
throw new Error(
|
|
79720
|
+
`resource type uses a composite primary identifier (${entry.fields.length} fields: ${entry.fields.join(", ")}); add an entry to COMPOSITE_ID_SPLITTERS in src/cli/commands/export.ts that parses cdkd's physicalId for this type, or destroy the resource first and let CFn create it fresh`
|
|
79721
|
+
);
|
|
79722
|
+
}
|
|
79723
|
+
let split;
|
|
79724
|
+
try {
|
|
79725
|
+
split = splitter(physicalId);
|
|
79726
|
+
} catch (err) {
|
|
79727
|
+
throw new Error(
|
|
79728
|
+
`composite-id splitter for ${resourceType} failed: ` + (err instanceof Error ? err.message : String(err))
|
|
79729
|
+
);
|
|
79730
|
+
}
|
|
79731
|
+
for (const f of entry.fields) {
|
|
79732
|
+
if (!(f in split)) {
|
|
79733
|
+
throw new Error(
|
|
79734
|
+
`composite-id splitter for ${resourceType} did not produce field '${f}' (produced: ${Object.keys(split).join(", ")})`
|
|
79735
|
+
);
|
|
79736
|
+
}
|
|
79737
|
+
}
|
|
79738
|
+
return split;
|
|
79739
|
+
}
|
|
79740
|
+
async function fetchPrimaryIdentifier(resourceType, cfnClient) {
|
|
79614
79741
|
try {
|
|
79615
79742
|
const resp = await cfnClient.send(
|
|
79616
79743
|
new DescribeTypeCommand({ Type: "RESOURCE", TypeName: resourceType })
|
|
@@ -79618,15 +79745,9 @@ async function resolvePrimaryIdentifier(resourceType, cfnClient, cache2) {
|
|
|
79618
79745
|
if (resp.Schema) {
|
|
79619
79746
|
const parsed = JSON.parse(resp.Schema);
|
|
79620
79747
|
const primary = parsed.primaryIdentifier;
|
|
79621
|
-
if (Array.isArray(primary) && primary.length
|
|
79622
|
-
const
|
|
79623
|
-
|
|
79624
|
-
return propName;
|
|
79625
|
-
}
|
|
79626
|
-
if (Array.isArray(primary) && primary.length > 1) {
|
|
79627
|
-
throw new Error(
|
|
79628
|
-
`resource type uses a composite primary identifier (${primary.length} fields); cdkd does not yet support composite identifiers for cdkd export`
|
|
79629
|
-
);
|
|
79748
|
+
if (Array.isArray(primary) && primary.length > 0 && primary.every((p) => typeof p === "string")) {
|
|
79749
|
+
const fields = primary.map((p) => p.replace(/^\/properties\//, ""));
|
|
79750
|
+
return { fields };
|
|
79630
79751
|
}
|
|
79631
79752
|
}
|
|
79632
79753
|
} catch (err) {
|
|
@@ -79635,8 +79756,7 @@ async function resolvePrimaryIdentifier(resourceType, cfnClient, cache2) {
|
|
|
79635
79756
|
}
|
|
79636
79757
|
const fallback = PRIMARY_IDENTIFIER_FALLBACK[resourceType];
|
|
79637
79758
|
if (fallback) {
|
|
79638
|
-
|
|
79639
|
-
return fallback;
|
|
79759
|
+
return { fields: [fallback] };
|
|
79640
79760
|
}
|
|
79641
79761
|
throw new Error(
|
|
79642
79762
|
`primary identifier unknown (DescribeType returned no usable schema and no fallback is registered). Add ${resourceType} to PRIMARY_IDENTIFIER_FALLBACK in export.ts, or open an issue.`
|
|
@@ -79696,9 +79816,8 @@ function printPlan(plan, cfnStackName) {
|
|
|
79696
79816
|
logger.info("");
|
|
79697
79817
|
logger.info(`Import plan for CloudFormation stack '${cfnStackName}':`);
|
|
79698
79818
|
for (const entry of plan) {
|
|
79699
|
-
|
|
79700
|
-
|
|
79701
|
-
);
|
|
79819
|
+
const idStr = Object.entries(entry.resourceIdentifier).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
79820
|
+
logger.info(` ${entry.logicalId} (${entry.resourceType}) \u2190 ${idStr}`);
|
|
79702
79821
|
}
|
|
79703
79822
|
logger.info("");
|
|
79704
79823
|
}
|
|
@@ -79709,7 +79828,7 @@ async function executeImportChangeSet(cfnClient, stackName, template, plan) {
|
|
|
79709
79828
|
const resourcesToImport = plan.map((entry) => ({
|
|
79710
79829
|
ResourceType: entry.resourceType,
|
|
79711
79830
|
LogicalResourceId: entry.logicalId,
|
|
79712
|
-
ResourceIdentifier:
|
|
79831
|
+
ResourceIdentifier: entry.resourceIdentifier
|
|
79713
79832
|
}));
|
|
79714
79833
|
logger.info(
|
|
79715
79834
|
`Creating IMPORT changeset '${changeSetName}' for stack '${stackName}' (${plan.length} resource(s), ${templateBody.length} bytes)...`
|
|
@@ -79773,6 +79892,68 @@ async function executeImportChangeSet(cfnClient, stackName, template, plan) {
|
|
|
79773
79892
|
throw err;
|
|
79774
79893
|
}
|
|
79775
79894
|
}
|
|
79895
|
+
async function executeUpdateChangeSet(cfnClient, stackName, template) {
|
|
79896
|
+
const logger = getLogger();
|
|
79897
|
+
const changeSetName = `cdkd-phase2-${Date.now()}`;
|
|
79898
|
+
const templateBody = JSON.stringify(template, null, 2);
|
|
79899
|
+
if (templateBody.length > 51200) {
|
|
79900
|
+
throw new Error(
|
|
79901
|
+
`Full template is ${templateBody.length} bytes, over the 51,200-byte inline TemplateBody limit for phase-2 UPDATE. TemplateURL upload is not yet implemented.`
|
|
79902
|
+
);
|
|
79903
|
+
}
|
|
79904
|
+
logger.info(
|
|
79905
|
+
`Creating UPDATE changeset '${changeSetName}' for phase 2 (${templateBody.length} bytes)...`
|
|
79906
|
+
);
|
|
79907
|
+
try {
|
|
79908
|
+
await cfnClient.send(
|
|
79909
|
+
new CreateChangeSetCommand({
|
|
79910
|
+
StackName: stackName,
|
|
79911
|
+
ChangeSetName: changeSetName,
|
|
79912
|
+
ChangeSetType: "UPDATE",
|
|
79913
|
+
TemplateBody: templateBody,
|
|
79914
|
+
Capabilities: ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM", "CAPABILITY_AUTO_EXPAND"]
|
|
79915
|
+
})
|
|
79916
|
+
);
|
|
79917
|
+
} catch (err) {
|
|
79918
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
79919
|
+
throw new Error(`Failed to create UPDATE changeset: ${msg}`);
|
|
79920
|
+
}
|
|
79921
|
+
try {
|
|
79922
|
+
await waitUntilChangeSetCreateComplete(
|
|
79923
|
+
{ client: cfnClient, maxWaitTime: 600 },
|
|
79924
|
+
{ StackName: stackName, ChangeSetName: changeSetName }
|
|
79925
|
+
);
|
|
79926
|
+
} catch (err) {
|
|
79927
|
+
try {
|
|
79928
|
+
const desc = await cfnClient.send(
|
|
79929
|
+
new DescribeChangeSetCommand({ StackName: stackName, ChangeSetName: changeSetName })
|
|
79930
|
+
);
|
|
79931
|
+
const reason = desc.StatusReason ?? "unknown";
|
|
79932
|
+
await cfnClient.send(new DeleteChangeSetCommand({ StackName: stackName, ChangeSetName: changeSetName })).catch(() => {
|
|
79933
|
+
});
|
|
79934
|
+
throw new Error(`UPDATE changeset FAILED: ${reason}`);
|
|
79935
|
+
} catch (innerErr) {
|
|
79936
|
+
if (innerErr instanceof Error && innerErr.message.startsWith("UPDATE changeset FAILED")) {
|
|
79937
|
+
throw innerErr;
|
|
79938
|
+
}
|
|
79939
|
+
throw err;
|
|
79940
|
+
}
|
|
79941
|
+
}
|
|
79942
|
+
logger.info(`Executing UPDATE changeset...`);
|
|
79943
|
+
try {
|
|
79944
|
+
await cfnClient.send(
|
|
79945
|
+
new ExecuteChangeSetCommand({ StackName: stackName, ChangeSetName: changeSetName })
|
|
79946
|
+
);
|
|
79947
|
+
await waitUntilStackUpdateComplete2(
|
|
79948
|
+
{ client: cfnClient, maxWaitTime: 3600 },
|
|
79949
|
+
{ StackName: stackName }
|
|
79950
|
+
);
|
|
79951
|
+
} catch (err) {
|
|
79952
|
+
await cfnClient.send(new DeleteChangeSetCommand({ StackName: stackName, ChangeSetName: changeSetName })).catch(() => {
|
|
79953
|
+
});
|
|
79954
|
+
throw err;
|
|
79955
|
+
}
|
|
79956
|
+
}
|
|
79776
79957
|
function refuseTransientContextIfUnsafe(options) {
|
|
79777
79958
|
const overrides = options.context ?? [];
|
|
79778
79959
|
if (overrides.length === 0)
|
|
@@ -79842,6 +80023,10 @@ function createExportCommand() {
|
|
|
79842
80023
|
"--accept-transient-context",
|
|
79843
80024
|
"Allow CLI -c key=value overrides at export time even though they are not persisted to cdk.json / cdk.context.json (default: refuse). When set, the user is responsible for passing the same -c flags to every future cdk deploy.",
|
|
79844
80025
|
false
|
|
80026
|
+
).option(
|
|
80027
|
+
"--include-non-importable",
|
|
80028
|
+
"Run a 2-phase migration when the stack contains non-importable resources (Custom::*). Phase 1 imports the importable resources; phase 2 CFn-CREATEs the non-importable ones, which re-invokes each Custom Resource's onCreate handler. Make sure onCreate is idempotent before enabling.",
|
|
80029
|
+
false
|
|
79845
80030
|
).action(withErrorHandling(exportCommand));
|
|
79846
80031
|
[...commonOptions, ...appOptions, ...stateOptions, ...contextOptions].forEach(
|
|
79847
80032
|
(opt) => cmd.addOption(opt)
|
|
@@ -79880,7 +80065,7 @@ function reorderArgs(argv) {
|
|
|
79880
80065
|
}
|
|
79881
80066
|
async function main() {
|
|
79882
80067
|
const program = new Command18();
|
|
79883
|
-
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.
|
|
80068
|
+
program.name("cdkd").description("CDK Direct - Deploy AWS CDK apps directly via SDK/Cloud Control API").version("0.87.0");
|
|
79884
80069
|
program.addCommand(createBootstrapCommand());
|
|
79885
80070
|
program.addCommand(createSynthCommand());
|
|
79886
80071
|
program.addCommand(createListCommand());
|