@devramps/cli 0.1.6 → 0.1.7
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 +89 -57
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -81,18 +81,34 @@ function getStackKey(stackName, accountId, region) {
|
|
|
81
81
|
var MultiStackProgress = class {
|
|
82
82
|
stacks = /* @__PURE__ */ new Map();
|
|
83
83
|
stackOrder = [];
|
|
84
|
-
lastLineCount = 0;
|
|
85
84
|
isTTY;
|
|
86
85
|
spinnerFrame = 0;
|
|
87
86
|
spinnerInterval = null;
|
|
88
87
|
barWidth = 20;
|
|
88
|
+
renderScheduled = false;
|
|
89
|
+
lastRenderTime = 0;
|
|
90
|
+
hasRenderedOnce = false;
|
|
91
|
+
useAltScreen = true;
|
|
92
|
+
// Use alternate screen buffer for clean display
|
|
89
93
|
constructor() {
|
|
90
94
|
this.isTTY = process.stdout.isTTY ?? false;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Start the progress display (call after all stacks are registered)
|
|
98
|
+
*/
|
|
99
|
+
start() {
|
|
91
100
|
if (this.isTTY) {
|
|
101
|
+
if (this.useAltScreen) {
|
|
102
|
+
process.stdout.write("\x1B[?1049h");
|
|
103
|
+
}
|
|
104
|
+
process.stdout.write("\x1B[?25l");
|
|
105
|
+
process.stdout.write("\x1B[H");
|
|
106
|
+
process.stdout.write("\x1B[2J");
|
|
107
|
+
this.doRender();
|
|
92
108
|
this.spinnerInterval = setInterval(() => {
|
|
93
109
|
this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
94
|
-
this.
|
|
95
|
-
},
|
|
110
|
+
this.scheduleRender();
|
|
111
|
+
}, 100);
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
/**
|
|
@@ -112,20 +128,19 @@ var MultiStackProgress = class {
|
|
|
112
128
|
status: "pending"
|
|
113
129
|
});
|
|
114
130
|
this.stackOrder.push(key);
|
|
115
|
-
this.render();
|
|
116
131
|
}
|
|
117
132
|
/**
|
|
118
133
|
* Update a stack's progress
|
|
119
134
|
*/
|
|
120
|
-
updateStack(stackName, accountId, region, completed, status,
|
|
135
|
+
updateStack(stackName, accountId, region, completed, status, cfnStatus, latestResourceId) {
|
|
121
136
|
const key = getStackKey(stackName, accountId, region);
|
|
122
137
|
const stack = this.stacks.get(key);
|
|
123
138
|
if (stack) {
|
|
124
139
|
stack.completed = completed;
|
|
125
140
|
stack.status = status;
|
|
126
|
-
if (
|
|
141
|
+
if (cfnStatus) stack.cfnStatus = cfnStatus;
|
|
127
142
|
if (latestResourceId) stack.latestResourceId = latestResourceId;
|
|
128
|
-
this.
|
|
143
|
+
this.scheduleRender();
|
|
129
144
|
}
|
|
130
145
|
}
|
|
131
146
|
/**
|
|
@@ -136,30 +151,40 @@ var MultiStackProgress = class {
|
|
|
136
151
|
const stack = this.stacks.get(key);
|
|
137
152
|
if (stack) {
|
|
138
153
|
stack.status = "in_progress";
|
|
139
|
-
|
|
154
|
+
stack.cfnStatus = "STARTING";
|
|
155
|
+
this.scheduleRender();
|
|
140
156
|
}
|
|
141
157
|
}
|
|
142
158
|
/**
|
|
143
159
|
* Mark a stack as complete
|
|
144
160
|
*/
|
|
145
|
-
completeStack(stackName, accountId, region, success2) {
|
|
161
|
+
completeStack(stackName, accountId, region, success2, failureReason) {
|
|
146
162
|
const key = getStackKey(stackName, accountId, region);
|
|
147
163
|
const stack = this.stacks.get(key);
|
|
148
164
|
if (stack) {
|
|
149
165
|
stack.status = success2 ? "complete" : "failed";
|
|
150
166
|
stack.completed = success2 ? stack.total : stack.completed;
|
|
151
|
-
|
|
167
|
+
if (failureReason) stack.failureReason = failureReason;
|
|
168
|
+
this.scheduleRender();
|
|
152
169
|
}
|
|
153
170
|
}
|
|
154
171
|
/**
|
|
155
|
-
*
|
|
172
|
+
* Schedule a render (debounced to prevent too many updates)
|
|
156
173
|
*/
|
|
157
|
-
|
|
158
|
-
if (
|
|
159
|
-
|
|
160
|
-
|
|
174
|
+
scheduleRender() {
|
|
175
|
+
if (this.renderScheduled) return;
|
|
176
|
+
const now = Date.now();
|
|
177
|
+
const timeSinceLastRender = now - this.lastRenderTime;
|
|
178
|
+
const minInterval = 50;
|
|
179
|
+
if (timeSinceLastRender >= minInterval) {
|
|
180
|
+
this.doRender();
|
|
181
|
+
} else {
|
|
182
|
+
this.renderScheduled = true;
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
this.renderScheduled = false;
|
|
185
|
+
this.doRender();
|
|
186
|
+
}, minInterval - timeSinceLastRender);
|
|
161
187
|
}
|
|
162
|
-
this.lastLineCount = 0;
|
|
163
188
|
}
|
|
164
189
|
/**
|
|
165
190
|
* Finish and stop updates
|
|
@@ -169,7 +194,12 @@ var MultiStackProgress = class {
|
|
|
169
194
|
clearInterval(this.spinnerInterval);
|
|
170
195
|
this.spinnerInterval = null;
|
|
171
196
|
}
|
|
172
|
-
this.
|
|
197
|
+
if (this.isTTY) {
|
|
198
|
+
process.stdout.write("\x1B[?25h");
|
|
199
|
+
if (this.useAltScreen) {
|
|
200
|
+
process.stdout.write("\x1B[?1049l");
|
|
201
|
+
}
|
|
202
|
+
}
|
|
173
203
|
this.renderFinal();
|
|
174
204
|
}
|
|
175
205
|
/**
|
|
@@ -186,7 +216,7 @@ var MultiStackProgress = class {
|
|
|
186
216
|
* Format a single stack line
|
|
187
217
|
*/
|
|
188
218
|
formatStackLine(stack, withSpinner) {
|
|
189
|
-
const { accountId, region, stackName, completed, total, status,
|
|
219
|
+
const { accountId, region, stackName, completed, total, status, cfnStatus, latestResourceId, failureReason } = stack;
|
|
190
220
|
let statusIndicator;
|
|
191
221
|
let colorFn;
|
|
192
222
|
switch (status) {
|
|
@@ -201,7 +231,7 @@ var MultiStackProgress = class {
|
|
|
201
231
|
break;
|
|
202
232
|
case "in_progress":
|
|
203
233
|
statusIndicator = withSpinner ? SPINNER_FRAMES[this.spinnerFrame] : "\u22EF";
|
|
204
|
-
colorFn = chalk.
|
|
234
|
+
colorFn = chalk.cyanBright;
|
|
205
235
|
break;
|
|
206
236
|
default:
|
|
207
237
|
statusIndicator = "\u25CB";
|
|
@@ -211,45 +241,47 @@ var MultiStackProgress = class {
|
|
|
211
241
|
const filled = Math.round(this.barWidth * percentage);
|
|
212
242
|
const empty = this.barWidth - filled;
|
|
213
243
|
const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
const
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
244
|
+
const accountLabel = `${accountId} ${region}`;
|
|
245
|
+
const countLabel = `${completed}/${total}`;
|
|
246
|
+
const maxStackNameLen = 35;
|
|
247
|
+
const displayName = stackName.length > maxStackNameLen ? stackName.slice(0, maxStackNameLen - 3) + "..." : stackName.padEnd(maxStackNameLen);
|
|
248
|
+
let rightInfo = "";
|
|
249
|
+
if (status === "failed" && failureReason) {
|
|
250
|
+
const maxLen = 40;
|
|
251
|
+
rightInfo = failureReason.length > maxLen ? failureReason.slice(0, maxLen - 3) + "..." : failureReason;
|
|
252
|
+
} else if (status === "in_progress") {
|
|
253
|
+
const cfnStatusDisplay = cfnStatus || "DEPLOYING";
|
|
254
|
+
const resourceDisplay = latestResourceId ? latestResourceId.length > 20 ? latestResourceId.slice(0, 17) + "..." : latestResourceId : "";
|
|
255
|
+
rightInfo = resourceDisplay ? `${cfnStatusDisplay} \u2192 ${resourceDisplay}` : cfnStatusDisplay;
|
|
256
|
+
} else if (status === "complete") {
|
|
257
|
+
rightInfo = "COMPLETE";
|
|
258
|
+
}
|
|
259
|
+
const leftPart = `${statusIndicator} ${accountLabel} ${displayName}`;
|
|
260
|
+
const middlePart = `[${bar}] ${countLabel}`;
|
|
261
|
+
const line = `${leftPart} ${middlePart} ${rightInfo}`;
|
|
226
262
|
return colorFn(line);
|
|
227
263
|
}
|
|
228
264
|
/**
|
|
229
|
-
*
|
|
265
|
+
* Perform the actual render
|
|
230
266
|
*/
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
this.
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (!stack) continue;
|
|
241
|
-
lines.push(this.formatStackLine(stack, true));
|
|
242
|
-
}
|
|
243
|
-
for (const line of lines) {
|
|
244
|
-
process.stdout.write(line + "\n");
|
|
245
|
-
}
|
|
246
|
-
this.lastLineCount = lines.length;
|
|
247
|
-
}
|
|
248
|
-
} finally {
|
|
249
|
-
this.isRendering = false;
|
|
267
|
+
doRender() {
|
|
268
|
+
this.lastRenderTime = Date.now();
|
|
269
|
+
if (!this.isTTY) return;
|
|
270
|
+
process.stdout.write("\x1B[H");
|
|
271
|
+
process.stdout.write(chalk.bold.underline("Deploying Stacks") + "\x1B[K\n\n");
|
|
272
|
+
for (const key of this.stackOrder) {
|
|
273
|
+
const stack = this.stacks.get(key);
|
|
274
|
+
if (!stack) continue;
|
|
275
|
+
process.stdout.write(this.formatStackLine(stack, true) + "\x1B[K\n");
|
|
250
276
|
}
|
|
277
|
+
const completed = Array.from(this.stacks.values()).filter((s) => s.status === "complete").length;
|
|
278
|
+
const failed = Array.from(this.stacks.values()).filter((s) => s.status === "failed" || s.status === "rollback").length;
|
|
279
|
+
const inProgress = Array.from(this.stacks.values()).filter((s) => s.status === "in_progress").length;
|
|
280
|
+
const pending = Array.from(this.stacks.values()).filter((s) => s.status === "pending").length;
|
|
281
|
+
process.stdout.write("\n");
|
|
282
|
+
process.stdout.write(chalk.gray(`Progress: ${completed} complete, ${inProgress} in progress, ${pending} pending, ${failed} failed`) + "\x1B[K\n");
|
|
283
|
+
this.hasRenderedOnce = true;
|
|
251
284
|
}
|
|
252
|
-
isRendering = false;
|
|
253
285
|
};
|
|
254
286
|
var globalProgress = null;
|
|
255
287
|
function getMultiStackProgress() {
|
|
@@ -572,13 +604,12 @@ function isResourceComplete(status) {
|
|
|
572
604
|
if (!status) return false;
|
|
573
605
|
return status.includes("_COMPLETE") && !status.includes("ROLLBACK");
|
|
574
606
|
}
|
|
575
|
-
async function waitForStackWithProgress(client, stackName, accountId, region, operationStartTime,
|
|
607
|
+
async function waitForStackWithProgress(client, stackName, accountId, region, operationStartTime, _totalResources, maxWaitTime = 600) {
|
|
576
608
|
const seenEventIds = /* @__PURE__ */ new Set();
|
|
577
609
|
const completedResources = /* @__PURE__ */ new Set();
|
|
578
610
|
const startTime = Date.now();
|
|
579
611
|
const pollInterval = 2e3;
|
|
580
612
|
const progress = getMultiStackProgress();
|
|
581
|
-
let latestEvent = "";
|
|
582
613
|
let latestResourceId = "";
|
|
583
614
|
verbose(`[${stackName}] Starting to wait for stack operation...`);
|
|
584
615
|
try {
|
|
@@ -610,7 +641,6 @@ async function waitForStackWithProgress(client, stackName, accountId, region, op
|
|
|
610
641
|
const logicalId = event.LogicalResourceId;
|
|
611
642
|
const status = event.ResourceStatus || "";
|
|
612
643
|
if (logicalId && logicalId !== stackName) {
|
|
613
|
-
latestEvent = status;
|
|
614
644
|
latestResourceId = logicalId;
|
|
615
645
|
verbose(`[${stackName}] Resource ${logicalId}: ${status}`);
|
|
616
646
|
if (isResourceComplete(status)) {
|
|
@@ -624,10 +654,11 @@ async function waitForStackWithProgress(client, stackName, accountId, region, op
|
|
|
624
654
|
} else if (currentStatus.includes("FAILED")) {
|
|
625
655
|
displayStatus = "failed";
|
|
626
656
|
}
|
|
627
|
-
progress.updateStack(stackName, accountId, region, completedResources.size, displayStatus,
|
|
657
|
+
progress.updateStack(stackName, accountId, region, completedResources.size, displayStatus, currentStatus, latestResourceId);
|
|
628
658
|
if (TERMINAL_STATES.has(currentStatus)) {
|
|
629
659
|
const success2 = SUCCESS_STATES.has(currentStatus);
|
|
630
|
-
|
|
660
|
+
const failureReason = success2 ? void 0 : currentStatus;
|
|
661
|
+
progress.completeStack(stackName, accountId, region, success2, failureReason);
|
|
631
662
|
verbose(`[${stackName}] Reached terminal state: ${currentStatus} (success: ${success2})`);
|
|
632
663
|
if (success2) {
|
|
633
664
|
return;
|
|
@@ -2751,6 +2782,7 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
|
|
|
2751
2782
|
const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length + 2;
|
|
2752
2783
|
progress.addStack(stack.stackName, stack.accountId, stack.region, resourceCount);
|
|
2753
2784
|
}
|
|
2785
|
+
progress.start();
|
|
2754
2786
|
const orgPromise = (async () => {
|
|
2755
2787
|
try {
|
|
2756
2788
|
await deployOrgStack(plan, pipelines, authData, currentAccountId, options);
|