@devramps/cli 0.1.10 → 0.1.12

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 +67 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -116,6 +116,7 @@ var MultiStackProgress = class {
116
116
  this.spinnerFrame = (this.spinnerFrame + 1) % SPINNER_FRAMES.length;
117
117
  this.scheduleRender();
118
118
  }, 100);
119
+ if (this.spinnerInterval.unref) this.spinnerInterval.unref();
119
120
  }
120
121
  }
121
122
  /**
@@ -932,6 +933,11 @@ async function authenticateViaBrowser(options = {}) {
932
933
  const state = generateState();
933
934
  verbose("Generated PKCE code_challenge and state");
934
935
  const { server, port, callbackPromise } = await startCallbackServer(state);
936
+ const sigintHandler = () => {
937
+ server.close();
938
+ process.exit(130);
939
+ };
940
+ process.on("SIGINT", sigintHandler);
935
941
  try {
936
942
  const redirectUri = `http://localhost:${port}`;
937
943
  const authParams = new URLSearchParams({
@@ -1004,6 +1010,7 @@ async function authenticateViaBrowser(options = {}) {
1004
1010
  cicdRegion: awsConfig.defaultRegion
1005
1011
  };
1006
1012
  } finally {
1013
+ process.removeListener("SIGINT", sigintHandler);
1007
1014
  await closeServer(server);
1008
1015
  }
1009
1016
  }
@@ -1295,8 +1302,11 @@ async function parseAdditionalPolicies(pipelineDir) {
1295
1302
  if (!policy || typeof policy !== "object") {
1296
1303
  throw new Error(`Policy at index ${i} is not an object`);
1297
1304
  }
1298
- if (!("Statement" in policy) || !Array.isArray(policy.Statement)) {
1299
- throw new Error(`Policy at index ${i} is missing Statement array`);
1305
+ if (!("Statement" in policy) || !policy.Statement || typeof policy.Statement !== "object") {
1306
+ throw new Error(`Policy at index ${i} is missing Statement`);
1307
+ }
1308
+ if (!Array.isArray(policy.Statement)) {
1309
+ policy.Statement = [policy.Statement];
1300
1310
  }
1301
1311
  validatedPolicies.push(policy);
1302
1312
  }
@@ -2770,7 +2780,9 @@ async function showDryRunPlan(plan) {
2770
2780
  }
2771
2781
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
2772
2782
  newline();
2773
- info(`Total stacks to deploy (in parallel): ${totalStacks}`);
2783
+ info(`Total stacks to deploy: ${totalStacks}`);
2784
+ info(` Phase 1: ${plan.accountStacks.length} Account stack(s) (deployed first)`);
2785
+ info(` Phase 2: ${1 + plan.pipelineStacks.length + plan.stageStacks.length} Org/Pipeline/Stage stack(s) (deployed in parallel after Phase 1)`);
2774
2786
  }
2775
2787
  async function confirmDeploymentPlan(plan) {
2776
2788
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
@@ -2793,24 +2805,62 @@ async function confirmDeploymentPlan(plan) {
2793
2805
  async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, currentAccountId, options) {
2794
2806
  const results = { success: 0, failed: 0 };
2795
2807
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
2808
+ const remainingStacks = 1 + plan.pipelineStacks.length + plan.stageStacks.length;
2796
2809
  newline();
2797
- header("Deploying All Stacks");
2798
- info(`Deploying ${totalStacks} stack(s) in parallel...`);
2810
+ header("Phase 1: Deploying Account Bootstrap Stacks");
2811
+ info(`Deploying ${plan.accountStacks.length} account stack(s) in parallel...`);
2799
2812
  newline();
2800
- const progress = getMultiStackProgress();
2801
- progress.addStack(plan.orgStack.stackName, "org", plan.orgStack.accountId, plan.orgStack.region, 5);
2813
+ const accountProgress = getMultiStackProgress();
2814
+ for (const stack of plan.accountStacks) {
2815
+ accountProgress.addStack(stack.stackName, "account", stack.accountId, stack.region, 1);
2816
+ }
2817
+ accountProgress.start();
2818
+ const accountResults = await Promise.all(
2819
+ plan.accountStacks.map(async (stack) => {
2820
+ try {
2821
+ await deployAccountStack(stack, currentAccountId, options);
2822
+ return { stack: `${stack.stackName} (${stack.accountId})`, success: true };
2823
+ } catch (error2) {
2824
+ return {
2825
+ stack: `${stack.stackName} (${stack.accountId})`,
2826
+ success: false,
2827
+ error: error2 instanceof Error ? error2.message : String(error2)
2828
+ };
2829
+ }
2830
+ })
2831
+ );
2832
+ clearMultiStackProgress();
2833
+ newline();
2834
+ for (const result of accountResults) {
2835
+ if (result.success) {
2836
+ success(`${result.stack} deployed`);
2837
+ results.success++;
2838
+ } else {
2839
+ error(`${result.stack} failed: ${result.error}`);
2840
+ results.failed++;
2841
+ }
2842
+ }
2843
+ if (results.failed > 0) {
2844
+ newline();
2845
+ header("Deployment Summary");
2846
+ error(`${results.failed} account stack(s) failed. Skipping remaining ${remainingStacks} stack(s).`);
2847
+ process.exit(1);
2848
+ }
2849
+ newline();
2850
+ header("Phase 2: Deploying Org, Pipeline, and Stage Stacks");
2851
+ info(`Deploying ${remainingStacks} stack(s) in parallel...`);
2852
+ newline();
2853
+ const mainProgress = getMultiStackProgress();
2854
+ mainProgress.addStack(plan.orgStack.stackName, "org", plan.orgStack.accountId, plan.orgStack.region, 5);
2802
2855
  for (const stack of plan.pipelineStacks) {
2803
2856
  const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length;
2804
- progress.addStack(stack.stackName, "pipeline", stack.accountId, stack.region, Math.max(resourceCount, 1));
2805
- }
2806
- for (const stack of plan.accountStacks) {
2807
- progress.addStack(stack.stackName, "account", stack.accountId, stack.region, 1);
2857
+ mainProgress.addStack(stack.stackName, "pipeline", stack.accountId, stack.region, Math.max(resourceCount, 1));
2808
2858
  }
2809
2859
  for (const stack of plan.stageStacks) {
2810
2860
  const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length + 2;
2811
- progress.addStack(stack.stackName, "stage", stack.accountId, stack.region, resourceCount);
2861
+ mainProgress.addStack(stack.stackName, "stage", stack.accountId, stack.region, resourceCount);
2812
2862
  }
2813
- progress.start();
2863
+ mainProgress.start();
2814
2864
  const orgPromise = (async () => {
2815
2865
  try {
2816
2866
  await deployOrgStack(plan, pipelines, authData, currentAccountId, options);
@@ -2835,18 +2885,6 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
2835
2885
  };
2836
2886
  }
2837
2887
  });
2838
- const accountPromises = plan.accountStacks.map(async (stack) => {
2839
- try {
2840
- await deployAccountStack(stack, currentAccountId, options);
2841
- return { stack: stack.stackName, success: true };
2842
- } catch (error2) {
2843
- return {
2844
- stack: stack.stackName,
2845
- success: false,
2846
- error: error2 instanceof Error ? error2.message : String(error2)
2847
- };
2848
- }
2849
- });
2850
2888
  const stagePromises = plan.stageStacks.map(async (stack) => {
2851
2889
  try {
2852
2890
  await deployStageStack(stack, authData, currentAccountId, options);
@@ -2859,15 +2897,14 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
2859
2897
  };
2860
2898
  }
2861
2899
  });
2862
- const allResults = await Promise.all([
2900
+ const mainResults = await Promise.all([
2863
2901
  orgPromise,
2864
2902
  ...pipelinePromises,
2865
- ...accountPromises,
2866
2903
  ...stagePromises
2867
2904
  ]);
2868
2905
  clearMultiStackProgress();
2869
2906
  newline();
2870
- for (const result of allResults) {
2907
+ for (const result of mainResults) {
2871
2908
  if (result.success) {
2872
2909
  success(`${result.stack} deployed`);
2873
2910
  results.success++;
@@ -2880,8 +2917,10 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
2880
2917
  header("Deployment Summary");
2881
2918
  if (results.failed === 0) {
2882
2919
  success(`All ${results.success} stack(s) deployed successfully!`);
2920
+ process.exit(0);
2883
2921
  } else {
2884
2922
  warn(`${results.success} stack(s) succeeded, ${results.failed} stack(s) failed.`);
2923
+ process.exit(1);
2885
2924
  }
2886
2925
  }
2887
2926
  async function deployOrgStack(plan, pipelines, authData, currentAccountId, options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devramps/cli",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "DevRamps CLI - Bootstrap AWS infrastructure for CI/CD pipelines",
5
5
  "main": "dist/index.js",
6
6
  "bin": {