@devramps/cli 0.1.7 → 0.1.9
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/index.js +58 -33
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -90,6 +90,8 @@ var MultiStackProgress = class {
|
|
|
90
90
|
hasRenderedOnce = false;
|
|
91
91
|
useAltScreen = true;
|
|
92
92
|
// Use alternate screen buffer for clean display
|
|
93
|
+
maxStackNameLen = 40;
|
|
94
|
+
// Will be calculated dynamically
|
|
93
95
|
constructor() {
|
|
94
96
|
this.isTTY = process.stdout.isTTY ?? false;
|
|
95
97
|
}
|
|
@@ -97,6 +99,11 @@ var MultiStackProgress = class {
|
|
|
97
99
|
* Start the progress display (call after all stacks are registered)
|
|
98
100
|
*/
|
|
99
101
|
start() {
|
|
102
|
+
this.maxStackNameLen = Math.max(
|
|
103
|
+
...Array.from(this.stacks.values()).map((s) => s.stackName.length),
|
|
104
|
+
20
|
|
105
|
+
// minimum width
|
|
106
|
+
);
|
|
100
107
|
if (this.isTTY) {
|
|
101
108
|
if (this.useAltScreen) {
|
|
102
109
|
process.stdout.write("\x1B[?1049h");
|
|
@@ -114,13 +121,14 @@ var MultiStackProgress = class {
|
|
|
114
121
|
/**
|
|
115
122
|
* Register a stack to track
|
|
116
123
|
*/
|
|
117
|
-
addStack(stackName, accountId, region, totalResources) {
|
|
124
|
+
addStack(stackName, stackType, accountId, region, totalResources) {
|
|
118
125
|
const key = getStackKey(stackName, accountId, region);
|
|
119
126
|
if (this.stacks.has(key)) {
|
|
120
127
|
return;
|
|
121
128
|
}
|
|
122
129
|
this.stacks.set(key, {
|
|
123
130
|
stackName,
|
|
131
|
+
stackType,
|
|
124
132
|
accountId,
|
|
125
133
|
region,
|
|
126
134
|
completed: 0,
|
|
@@ -212,11 +220,26 @@ var MultiStackProgress = class {
|
|
|
212
220
|
console.log(this.formatStackLine(stack, false));
|
|
213
221
|
}
|
|
214
222
|
}
|
|
223
|
+
/**
|
|
224
|
+
* Get a short label for stack type
|
|
225
|
+
*/
|
|
226
|
+
getTypeLabel(stackType) {
|
|
227
|
+
switch (stackType) {
|
|
228
|
+
case "org":
|
|
229
|
+
return "ORG";
|
|
230
|
+
case "pipeline":
|
|
231
|
+
return "PIPE";
|
|
232
|
+
case "account":
|
|
233
|
+
return "ACCT";
|
|
234
|
+
case "stage":
|
|
235
|
+
return "STAGE";
|
|
236
|
+
}
|
|
237
|
+
}
|
|
215
238
|
/**
|
|
216
239
|
* Format a single stack line
|
|
217
240
|
*/
|
|
218
241
|
formatStackLine(stack, withSpinner) {
|
|
219
|
-
const { accountId, region, stackName, completed, total, status, cfnStatus, latestResourceId, failureReason } = stack;
|
|
242
|
+
const { accountId, region, stackName, stackType, completed, total, status, cfnStatus, latestResourceId, failureReason } = stack;
|
|
220
243
|
let statusIndicator;
|
|
221
244
|
let colorFn;
|
|
222
245
|
switch (status) {
|
|
@@ -241,22 +264,28 @@ var MultiStackProgress = class {
|
|
|
241
264
|
const filled = Math.round(this.barWidth * percentage);
|
|
242
265
|
const empty = this.barWidth - filled;
|
|
243
266
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
244
|
-
const
|
|
267
|
+
const typeLabel = this.getTypeLabel(stackType).padEnd(5);
|
|
268
|
+
const accountLabel = `${accountId} ${region.padEnd(12)}`;
|
|
245
269
|
const countLabel = `${completed}/${total}`;
|
|
246
|
-
const
|
|
247
|
-
const displayName = stackName.length > maxStackNameLen ? stackName.slice(0, maxStackNameLen - 3) + "..." : stackName.padEnd(maxStackNameLen);
|
|
270
|
+
const displayName = stackName.padEnd(this.maxStackNameLen);
|
|
248
271
|
let rightInfo = "";
|
|
249
|
-
if (status === "failed"
|
|
250
|
-
const
|
|
251
|
-
|
|
272
|
+
if (status === "failed" || status === "rollback") {
|
|
273
|
+
const statusText = cfnStatus || "FAILED";
|
|
274
|
+
if (failureReason && failureReason !== cfnStatus) {
|
|
275
|
+
const maxLen = 50;
|
|
276
|
+
const fullReason = `${statusText}: ${failureReason}`;
|
|
277
|
+
rightInfo = fullReason.length > maxLen ? fullReason.slice(0, maxLen - 3) + "..." : fullReason;
|
|
278
|
+
} else {
|
|
279
|
+
rightInfo = statusText;
|
|
280
|
+
}
|
|
252
281
|
} else if (status === "in_progress") {
|
|
253
282
|
const cfnStatusDisplay = cfnStatus || "DEPLOYING";
|
|
254
|
-
const resourceDisplay = latestResourceId ? latestResourceId.length >
|
|
283
|
+
const resourceDisplay = latestResourceId ? latestResourceId.length > 25 ? latestResourceId.slice(0, 22) + "..." : latestResourceId : "";
|
|
255
284
|
rightInfo = resourceDisplay ? `${cfnStatusDisplay} \u2192 ${resourceDisplay}` : cfnStatusDisplay;
|
|
256
285
|
} else if (status === "complete") {
|
|
257
|
-
rightInfo = "COMPLETE";
|
|
286
|
+
rightInfo = cfnStatus || "COMPLETE";
|
|
258
287
|
}
|
|
259
|
-
const leftPart = `${statusIndicator} ${accountLabel} ${displayName}`;
|
|
288
|
+
const leftPart = `${statusIndicator} [${typeLabel}] ${accountLabel} ${displayName}`;
|
|
260
289
|
const middlePart = `[${bar}] ${countLabel}`;
|
|
261
290
|
const line = `${leftPart} ${middlePart} ${rightInfo}`;
|
|
262
291
|
return colorFn(line);
|
|
@@ -611,6 +640,7 @@ async function waitForStackWithProgress(client, stackName, accountId, region, op
|
|
|
611
640
|
const pollInterval = 2e3;
|
|
612
641
|
const progress = getMultiStackProgress();
|
|
613
642
|
let latestResourceId = "";
|
|
643
|
+
let latestFailureReason = "";
|
|
614
644
|
verbose(`[${stackName}] Starting to wait for stack operation...`);
|
|
615
645
|
try {
|
|
616
646
|
while (true) {
|
|
@@ -646,6 +676,10 @@ async function waitForStackWithProgress(client, stackName, accountId, region, op
|
|
|
646
676
|
if (isResourceComplete(status)) {
|
|
647
677
|
completedResources.add(logicalId);
|
|
648
678
|
}
|
|
679
|
+
if (status.includes("FAILED") && event.ResourceStatusReason) {
|
|
680
|
+
latestFailureReason = `${logicalId}: ${event.ResourceStatusReason}`;
|
|
681
|
+
verbose(`[${stackName}] Failure reason: ${latestFailureReason}`);
|
|
682
|
+
}
|
|
649
683
|
}
|
|
650
684
|
}
|
|
651
685
|
let displayStatus = "in_progress";
|
|
@@ -657,7 +691,7 @@ async function waitForStackWithProgress(client, stackName, accountId, region, op
|
|
|
657
691
|
progress.updateStack(stackName, accountId, region, completedResources.size, displayStatus, currentStatus, latestResourceId);
|
|
658
692
|
if (TERMINAL_STATES.has(currentStatus)) {
|
|
659
693
|
const success2 = SUCCESS_STATES.has(currentStatus);
|
|
660
|
-
const failureReason = success2 ? void 0 : currentStatus;
|
|
694
|
+
const failureReason = success2 ? void 0 : latestFailureReason || currentStatus;
|
|
661
695
|
progress.completeStack(stackName, accountId, region, success2, failureReason);
|
|
662
696
|
verbose(`[${stackName}] Reached terminal state: ${currentStatus} (success: ${success2})`);
|
|
663
697
|
if (success2) {
|
|
@@ -1486,18 +1520,6 @@ function addOidcProviderResource(template, conditional = true) {
|
|
|
1486
1520
|
}
|
|
1487
1521
|
};
|
|
1488
1522
|
}
|
|
1489
|
-
function getOidcProviderArn(accountId, conditional = true) {
|
|
1490
|
-
if (conditional) {
|
|
1491
|
-
return {
|
|
1492
|
-
"Fn::If": [
|
|
1493
|
-
"CreateOIDCProvider",
|
|
1494
|
-
{ "Fn::GetAtt": ["DevRampsOIDCProvider", "Arn"] },
|
|
1495
|
-
`arn:aws:iam::${accountId}:oidc-provider/${OIDC_PROVIDER_URL}`
|
|
1496
|
-
]
|
|
1497
|
-
};
|
|
1498
|
-
}
|
|
1499
|
-
return { "Fn::GetAtt": ["DevRampsOIDCProvider", "Arn"] };
|
|
1500
|
-
}
|
|
1501
1523
|
function buildOidcTrustPolicy(accountId, subject) {
|
|
1502
1524
|
return {
|
|
1503
1525
|
Version: "2012-10-17",
|
|
@@ -1875,7 +1897,6 @@ function createTerraformStateBucketPolicy(bucketName, cicdAccountId, allowedAcco
|
|
|
1875
1897
|
function generateOrgStackTemplate(options) {
|
|
1876
1898
|
const { orgSlug, cicdAccountId, targetAccountIds } = options;
|
|
1877
1899
|
const template = createBaseTemplate(`DevRamps Org Stack for ${orgSlug}`);
|
|
1878
|
-
addOidcProviderResource(template, true);
|
|
1879
1900
|
const kmsKeyPolicy = buildKmsKeyPolicy(cicdAccountId, targetAccountIds);
|
|
1880
1901
|
template.Resources.DevRampsKMSKey = createKmsKeyResource(
|
|
1881
1902
|
`DevRamps encryption key for org: ${orgSlug}`,
|
|
@@ -1939,10 +1960,6 @@ function generateOrgStackTemplate(options) {
|
|
|
1939
1960
|
TerraformStateBucketArn: {
|
|
1940
1961
|
Description: "ARN of the Terraform state bucket",
|
|
1941
1962
|
Value: { "Fn::GetAtt": ["TerraformStateBucket", "Arn"] }
|
|
1942
|
-
},
|
|
1943
|
-
OIDCProviderArn: {
|
|
1944
|
-
Description: "ARN of the OIDC provider",
|
|
1945
|
-
Value: getOidcProviderArn(cicdAccountId, true)
|
|
1946
1963
|
}
|
|
1947
1964
|
};
|
|
1948
1965
|
return template;
|
|
@@ -2622,6 +2639,14 @@ async function buildDeploymentPlan(pipelines, pipelineArtifacts, authData, curre
|
|
|
2622
2639
|
const accountStacks = [];
|
|
2623
2640
|
const accountStackName = getAccountStackName();
|
|
2624
2641
|
const accountsWithStacks = /* @__PURE__ */ new Set();
|
|
2642
|
+
accountsWithStacks.add(cicdAccountId);
|
|
2643
|
+
accountStacks.push({
|
|
2644
|
+
stackType: "Account" /* ACCOUNT */,
|
|
2645
|
+
stackName: accountStackName,
|
|
2646
|
+
accountId: cicdAccountId,
|
|
2647
|
+
region: cicdRegion,
|
|
2648
|
+
action: await determineStackAction(accountStackName, cicdCredentials, cicdRegion)
|
|
2649
|
+
});
|
|
2625
2650
|
for (const pipeline of pipelines) {
|
|
2626
2651
|
for (const stage of pipeline.stages) {
|
|
2627
2652
|
if (accountsWithStacks.has(stage.account_id)) {
|
|
@@ -2770,17 +2795,17 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
|
|
|
2770
2795
|
info(`Deploying ${totalStacks} stack(s) in parallel...`);
|
|
2771
2796
|
newline();
|
|
2772
2797
|
const progress = getMultiStackProgress();
|
|
2773
|
-
progress.addStack(plan.orgStack.stackName, plan.orgStack.accountId, plan.orgStack.region, 5);
|
|
2798
|
+
progress.addStack(plan.orgStack.stackName, "org", plan.orgStack.accountId, plan.orgStack.region, 5);
|
|
2774
2799
|
for (const stack of plan.pipelineStacks) {
|
|
2775
2800
|
const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length;
|
|
2776
|
-
progress.addStack(stack.stackName, stack.accountId, stack.region, Math.max(resourceCount, 1));
|
|
2801
|
+
progress.addStack(stack.stackName, "pipeline", stack.accountId, stack.region, Math.max(resourceCount, 1));
|
|
2777
2802
|
}
|
|
2778
2803
|
for (const stack of plan.accountStacks) {
|
|
2779
|
-
progress.addStack(stack.stackName, stack.accountId, stack.region, 1);
|
|
2804
|
+
progress.addStack(stack.stackName, "account", stack.accountId, stack.region, 1);
|
|
2780
2805
|
}
|
|
2781
2806
|
for (const stack of plan.stageStacks) {
|
|
2782
2807
|
const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length + 2;
|
|
2783
|
-
progress.addStack(stack.stackName, stack.accountId, stack.region, resourceCount);
|
|
2808
|
+
progress.addStack(stack.stackName, "stage", stack.accountId, stack.region, resourceCount);
|
|
2784
2809
|
}
|
|
2785
2810
|
progress.start();
|
|
2786
2811
|
const orgPromise = (async () => {
|