@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.
Files changed (2) hide show
  1. package/dist/index.js +58 -33
  2. 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 accountLabel = `${accountId} ${region}`;
267
+ const typeLabel = this.getTypeLabel(stackType).padEnd(5);
268
+ const accountLabel = `${accountId} ${region.padEnd(12)}`;
245
269
  const countLabel = `${completed}/${total}`;
246
- const maxStackNameLen = 35;
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" && failureReason) {
250
- const maxLen = 40;
251
- rightInfo = failureReason.length > maxLen ? failureReason.slice(0, maxLen - 3) + "..." : failureReason;
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 > 20 ? latestResourceId.slice(0, 17) + "..." : latestResourceId : "";
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 () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devramps/cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "DevRamps CLI - Bootstrap AWS infrastructure for CI/CD pipelines",
5
5
  "main": "dist/index.js",
6
6
  "bin": {