@devramps/cli 0.1.11 → 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 +64 -28
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -933,6 +933,11 @@ async function authenticateViaBrowser(options = {}) {
933
933
  const state = generateState();
934
934
  verbose("Generated PKCE code_challenge and state");
935
935
  const { server, port, callbackPromise } = await startCallbackServer(state);
936
+ const sigintHandler = () => {
937
+ server.close();
938
+ process.exit(130);
939
+ };
940
+ process.on("SIGINT", sigintHandler);
936
941
  try {
937
942
  const redirectUri = `http://localhost:${port}`;
938
943
  const authParams = new URLSearchParams({
@@ -1005,6 +1010,7 @@ async function authenticateViaBrowser(options = {}) {
1005
1010
  cicdRegion: awsConfig.defaultRegion
1006
1011
  };
1007
1012
  } finally {
1013
+ process.removeListener("SIGINT", sigintHandler);
1008
1014
  await closeServer(server);
1009
1015
  }
1010
1016
  }
@@ -1296,8 +1302,11 @@ async function parseAdditionalPolicies(pipelineDir) {
1296
1302
  if (!policy || typeof policy !== "object") {
1297
1303
  throw new Error(`Policy at index ${i} is not an object`);
1298
1304
  }
1299
- if (!("Statement" in policy) || !Array.isArray(policy.Statement)) {
1300
- 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];
1301
1310
  }
1302
1311
  validatedPolicies.push(policy);
1303
1312
  }
@@ -2771,7 +2780,9 @@ async function showDryRunPlan(plan) {
2771
2780
  }
2772
2781
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
2773
2782
  newline();
2774
- 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)`);
2775
2786
  }
2776
2787
  async function confirmDeploymentPlan(plan) {
2777
2788
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
@@ -2794,24 +2805,62 @@ async function confirmDeploymentPlan(plan) {
2794
2805
  async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, currentAccountId, options) {
2795
2806
  const results = { success: 0, failed: 0 };
2796
2807
  const totalStacks = 1 + plan.pipelineStacks.length + plan.accountStacks.length + plan.stageStacks.length;
2808
+ const remainingStacks = 1 + plan.pipelineStacks.length + plan.stageStacks.length;
2797
2809
  newline();
2798
- header("Deploying All Stacks");
2799
- 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...`);
2800
2812
  newline();
2801
- const progress = getMultiStackProgress();
2802
- 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);
2803
2855
  for (const stack of plan.pipelineStacks) {
2804
2856
  const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length;
2805
- progress.addStack(stack.stackName, "pipeline", stack.accountId, stack.region, Math.max(resourceCount, 1));
2806
- }
2807
- for (const stack of plan.accountStacks) {
2808
- progress.addStack(stack.stackName, "account", stack.accountId, stack.region, 1);
2857
+ mainProgress.addStack(stack.stackName, "pipeline", stack.accountId, stack.region, Math.max(resourceCount, 1));
2809
2858
  }
2810
2859
  for (const stack of plan.stageStacks) {
2811
2860
  const resourceCount = stack.dockerArtifacts.length + stack.bundleArtifacts.length + 2;
2812
- progress.addStack(stack.stackName, "stage", stack.accountId, stack.region, resourceCount);
2861
+ mainProgress.addStack(stack.stackName, "stage", stack.accountId, stack.region, resourceCount);
2813
2862
  }
2814
- progress.start();
2863
+ mainProgress.start();
2815
2864
  const orgPromise = (async () => {
2816
2865
  try {
2817
2866
  await deployOrgStack(plan, pipelines, authData, currentAccountId, options);
@@ -2836,18 +2885,6 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
2836
2885
  };
2837
2886
  }
2838
2887
  });
2839
- const accountPromises = plan.accountStacks.map(async (stack) => {
2840
- try {
2841
- await deployAccountStack(stack, currentAccountId, options);
2842
- return { stack: stack.stackName, success: true };
2843
- } catch (error2) {
2844
- return {
2845
- stack: stack.stackName,
2846
- success: false,
2847
- error: error2 instanceof Error ? error2.message : String(error2)
2848
- };
2849
- }
2850
- });
2851
2888
  const stagePromises = plan.stageStacks.map(async (stack) => {
2852
2889
  try {
2853
2890
  await deployStageStack(stack, authData, currentAccountId, options);
@@ -2860,15 +2897,14 @@ async function executeDeployment(plan, pipelines, pipelineArtifacts, authData, c
2860
2897
  };
2861
2898
  }
2862
2899
  });
2863
- const allResults = await Promise.all([
2900
+ const mainResults = await Promise.all([
2864
2901
  orgPromise,
2865
2902
  ...pipelinePromises,
2866
- ...accountPromises,
2867
2903
  ...stagePromises
2868
2904
  ]);
2869
2905
  clearMultiStackProgress();
2870
2906
  newline();
2871
- for (const result of allResults) {
2907
+ for (const result of mainResults) {
2872
2908
  if (result.success) {
2873
2909
  success(`${result.stack} deployed`);
2874
2910
  results.success++;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devramps/cli",
3
- "version": "0.1.11",
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": {