@fjall/deploy-core 0.94.1 → 0.95.0
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/.minified +1 -1
- package/dist/src/aws/organisations/accounts.js +1 -99
- package/dist/src/aws/organisations/backup.js +1 -30
- package/dist/src/aws/organisations/costAllocation.js +1 -28
- package/dist/src/aws/organisations/delegatedAdmin.js +3 -43
- package/dist/src/aws/organisations/identityCentre.js +1 -23
- package/dist/src/aws/organisations/ipam.js +1 -20
- package/dist/src/aws/organisations/organisation.js +1 -103
- package/dist/src/aws/organisations/organisationalUnits.js +1 -239
- package/dist/src/aws/organisations/policies.js +1 -37
- package/dist/src/aws/organisations/ram.js +1 -19
- package/dist/src/aws/organisations/serviceAccess.js +1 -44
- package/dist/src/aws/organisations/trustedAccess.js +1 -19
- package/dist/src/aws/utils/regions.js +1 -1
- package/dist/src/index.js +1 -65
- package/dist/src/orchestration/__tests__/cascadeTestHelpers.js +1 -78
- package/dist/src/orchestration/activeDeploymentGuard.js +5 -39
- package/dist/src/orchestration/applicationDeploy.js +1 -149
- package/dist/src/orchestration/applicationDeployHelpers.js +4 -223
- package/dist/src/orchestration/applicationDestroy.js +1 -131
- package/dist/src/orchestration/builders/dockerBuilder.js +1 -98
- package/dist/src/orchestration/builders/openNextBuilder.js +1 -144
- package/dist/src/orchestration/cascadeHelpers.js +1 -160
- package/dist/src/orchestration/contextHelpers.js +1 -107
- package/dist/src/orchestration/deploy.js +1 -42
- package/dist/src/orchestration/destroy.js +1 -67
- package/dist/src/orchestration/detectionPipeline.js +1 -84
- package/dist/src/orchestration/dockerBuildHelper.js +1 -49
- package/dist/src/orchestration/dockerInterface.js +0 -1
- package/dist/src/orchestration/domainInterface.js +0 -1
- package/dist/src/orchestration/openNextBuild.js +3 -243
- package/dist/src/orchestration/organisationDeploy.js +3 -284
- package/dist/src/orchestration/organisationDestroy.js +3 -189
- package/dist/src/orchestration/organisationSetup.js +1 -247
- package/dist/src/orchestration/resolveOperation.js +1 -123
- package/dist/src/orchestration/welcomeImageHelper.js +1 -64
- package/dist/src/services/application/ApplicationStackService.js +1 -218
- package/dist/src/services/application/applicationStackHelpers.js +4 -248
- package/dist/src/services/infrastructure/CdkCommandRunner.js +2 -244
- package/dist/src/services/infrastructure/CdkOutputAnalyser.js +1 -125
- package/dist/src/services/infrastructure/CdkProcessManager.js +3 -278
- package/dist/src/services/infrastructure/CdkService.js +3 -213
- package/dist/src/services/infrastructure/CloudFormationService.js +1 -248
- package/dist/src/services/infrastructure/ICdkProcessManager.js +0 -1
- package/dist/src/services/supporting/CdkContextBuilder.js +1 -44
- package/dist/src/services/supporting/TemplateHashService.js +1 -152
- package/dist/src/steps/stepRegistry.js +1 -505
- package/dist/src/types/apiClient.js +0 -1
- package/dist/src/types/detection.js +0 -1
- package/dist/src/types/frameworkBuilder.js +0 -8
- package/dist/src/types/params.js +0 -1
- package/dist/src/types/patternDetection.js +1 -88
- package/dist/src/types/stepDefinitions.js +1 -98
- package/package.json +4 -4
|
@@ -1,19 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { success, failure } from "@fjall/generator";
|
|
3
|
-
import { getErrorMessage } from "@fjall/util";
|
|
4
|
-
import { SDK_TIMEOUT_MS } from "./types.js";
|
|
5
|
-
/**
|
|
6
|
-
* Enable RAM sharing with the AWS Organisation.
|
|
7
|
-
* Idempotent — calling when already enabled is a no-op.
|
|
8
|
-
*/
|
|
9
|
-
export async function enableRamSharing(client) {
|
|
10
|
-
try {
|
|
11
|
-
await client.send(new EnableSharingWithAwsOrganizationCommand({}), {
|
|
12
|
-
abortSignal: AbortSignal.timeout(SDK_TIMEOUT_MS)
|
|
13
|
-
});
|
|
14
|
-
return success(undefined);
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
return failure(new Error(`Failed to enable RAM sharing: ${getErrorMessage(error)}`));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
import{EnableSharingWithAwsOrganizationCommand as n}from"@aws-sdk/client-ram";import{success as a,failure as o}from"@fjall/generator";import{getErrorMessage as t}from"@fjall/util";import{SDK_TIMEOUT_MS as i}from"./types.js";async function l(r){try{return await r.send(new n({}),{abortSignal:AbortSignal.timeout(i)}),a(void 0)}catch(e){return o(new Error(`Failed to enable RAM sharing: ${t(e)}`))}}export{l as enableRamSharing};
|
|
@@ -1,44 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { success, failure } from "@fjall/generator";
|
|
3
|
-
import { extractErrorName, SDK_TIMEOUT_MS, AWS_ERROR_NAMES } from "./types.js";
|
|
4
|
-
import { getErrorMessage } from "@fjall/util";
|
|
5
|
-
const SERVICE_PRINCIPALS = [
|
|
6
|
-
"account.amazonaws.com",
|
|
7
|
-
"sso.amazonaws.com",
|
|
8
|
-
"ipam.amazonaws.com",
|
|
9
|
-
"ram.amazonaws.com",
|
|
10
|
-
"backup.amazonaws.com",
|
|
11
|
-
"member.org.stacksets.cloudformation.amazonaws.com",
|
|
12
|
-
"guardduty.amazonaws.com",
|
|
13
|
-
"securityhub.amazonaws.com",
|
|
14
|
-
"config.amazonaws.com",
|
|
15
|
-
"inspector2.amazonaws.com",
|
|
16
|
-
"access-analyzer.amazonaws.com"
|
|
17
|
-
];
|
|
18
|
-
/**
|
|
19
|
-
* Enable AWS service access for all required service principals.
|
|
20
|
-
* Idempotent — enabling an already-enabled principal is a no-op.
|
|
21
|
-
*/
|
|
22
|
-
export async function enableServiceAccess(client) {
|
|
23
|
-
try {
|
|
24
|
-
for (const principal of SERVICE_PRINCIPALS) {
|
|
25
|
-
try {
|
|
26
|
-
await client.send(new EnableAWSServiceAccessCommand({
|
|
27
|
-
ServicePrincipal: principal
|
|
28
|
-
}), { abortSignal: AbortSignal.timeout(SDK_TIMEOUT_MS) });
|
|
29
|
-
}
|
|
30
|
-
catch (error) {
|
|
31
|
-
const errorName = extractErrorName(error);
|
|
32
|
-
if (errorName === AWS_ERROR_NAMES.ACCESS_DENIED) {
|
|
33
|
-
return failure(new Error(`Access denied when enabling service access for ${principal}. ` +
|
|
34
|
-
"Ensure your credentials have organizations:EnableAWSServiceAccess permission."));
|
|
35
|
-
}
|
|
36
|
-
throw new Error(`Service principal ${principal}: ${getErrorMessage(error)}`);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return success(undefined);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
return failure(new Error(`Failed to enable service access: ${getErrorMessage(error)}`));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
import{EnableAWSServiceAccessCommand as n}from"@aws-sdk/client-organizations";import{success as s,failure as e}from"@fjall/generator";import{extractErrorName as m,SDK_TIMEOUT_MS as i,AWS_ERROR_NAMES as t}from"./types.js";import{getErrorMessage as o}from"@fjall/util";const w=["account.amazonaws.com","sso.amazonaws.com","ipam.amazonaws.com","ram.amazonaws.com","backup.amazonaws.com","member.org.stacksets.cloudformation.amazonaws.com","guardduty.amazonaws.com","securityhub.amazonaws.com","config.amazonaws.com","inspector2.amazonaws.com","access-analyzer.amazonaws.com"];async function f(c){try{for(const r of w)try{await c.send(new n({ServicePrincipal:r}),{abortSignal:AbortSignal.timeout(i)})}catch(a){if(m(a)===t.ACCESS_DENIED)return e(new Error(`Access denied when enabling service access for ${r}. Ensure your credentials have organizations:EnableAWSServiceAccess permission.`));throw new Error(`Service principal ${r}: ${o(a)}`)}return s(void 0)}catch(r){return e(new Error(`Failed to enable service access: ${o(r)}`))}}export{f as enableServiceAccess};
|
|
@@ -1,19 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { success, failure } from "@fjall/generator";
|
|
3
|
-
import { getErrorMessage } from "@fjall/util";
|
|
4
|
-
import { SDK_TIMEOUT_MS } from "./types.js";
|
|
5
|
-
/**
|
|
6
|
-
* Activate trusted access for CloudFormation StackSets.
|
|
7
|
-
* Idempotent — calling when already activated is a no-op.
|
|
8
|
-
*/
|
|
9
|
-
export async function activateTrustedAccess(client) {
|
|
10
|
-
try {
|
|
11
|
-
await client.send(new ActivateOrganizationsAccessCommand({}), {
|
|
12
|
-
abortSignal: AbortSignal.timeout(SDK_TIMEOUT_MS)
|
|
13
|
-
});
|
|
14
|
-
return success(undefined);
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
return failure(new Error(`Failed to activate trusted access: ${getErrorMessage(error)}`));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
1
|
+
import{ActivateOrganizationsAccessCommand as e}from"@aws-sdk/client-cloudformation";import{success as a,failure as o}from"@fjall/generator";import{getErrorMessage as i}from"@fjall/util";import{SDK_TIMEOUT_MS as s}from"./types.js";async function d(r){try{return await r.send(new e({}),{abortSignal:AbortSignal.timeout(s)}),a(void 0)}catch(t){return o(new Error(`Failed to activate trusted access: ${i(t)}`))}}export{d as activateTrustedAccess};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{DEFAULT_REGION as o,regions as g,AWS_REGIONS_METADATA as t,topRegions as n,commonRegions as R,parseRegionList as s,isValidRegion as a,isValidRegionFormat as r,getSuggestions as l,validateRegion as m,validateRegionList as p,filterDuplicateRegions as d,getRegionOptions as A,getRegionOptionsExcluding as E,getRegionName as c,createRegionFormatter as O}from"@fjall/generator";export{t as AWS_REGIONS_METADATA,o as DEFAULT_REGION,R as commonRegions,O as createRegionFormatter,d as filterDuplicateRegions,c as getRegionName,A as getRegionOptions,E as getRegionOptionsExcluding,l as getSuggestions,a as isValidRegion,r as isValidRegionFormat,s as parseRegionList,g as regions,n as topRegions,m as validateRegion,p as validateRegionList};
|
package/dist/src/index.js
CHANGED
|
@@ -1,65 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* @fjall/deploy-core — Shared Deployment Engine
|
|
3
|
-
*
|
|
4
|
-
* This package contains the deployment logic shared between the CLI and
|
|
5
|
-
* the webapp worker. Both callers construct a DeployParams object and
|
|
6
|
-
* call deploy(). The engine handles CDK synthesis, CloudFormation
|
|
7
|
-
* deployment, Docker builds, and multi-account cascade — reporting
|
|
8
|
-
* progress via typed callbacks.
|
|
9
|
-
*
|
|
10
|
-
* Auth, config discovery, and output formatting are the caller's
|
|
11
|
-
* responsibility. deploy-core receives credentials and a working
|
|
12
|
-
* directory; it never reads credential files or writes to the terminal.
|
|
13
|
-
*/
|
|
14
|
-
// Deployment event schema (canonical source for CLI + webapp)
|
|
15
|
-
export { DeploymentEventSchema, DEPLOYMENT_EVENT_TYPES, DEPLOYMENT_EVENT_RESOURCE_CATEGORIES, CASCADE_PHASES, CASCADE_ACCOUNT_STATUSES } from "./types/index.js";
|
|
16
|
-
export { SimpleAwsProvider } from "./aws/index.js";
|
|
17
|
-
// Organisation setup primitives
|
|
18
|
-
export { ensureOrganisationExists, describeOrganisation, enablePolicyTypes, enableServiceAccess, enableRamSharing, activateTrustedAccess, enableIpamDelegatedAdmin, updateBackupGlobalSettings, listAccounts, findAccount, createAccount, ensureOrganisationalUnitsExist, placeAccountsInOUs, buildAccountToOUMap, activateCostAllocationTags, checkIdentityCentreStatus, extractErrorName, isOULeaf, registerSecurityDelegates, SECURITY_SERVICE_PRINCIPALS } from "./aws/index.js";
|
|
19
|
-
// Step definitions (canonical source for CLI + webapp)
|
|
20
|
-
export { STEP_IDS, STEP_NAMES, INFRASTRUCTURE_STEP_NAMES, INFRA_STEP_NAME } from "./types/index.js";
|
|
21
|
-
export { ProgressReporter, APPLICATION_STACKS, ORGANISATION_TYPES, APPLICATION_DEPLOY_ORDER, APPLICATION_DESTROY_ORDER, OPENNEXT_DEPLOY_ORDER, OPENNEXT_DESTROY_ORDER, PARALLEL_DEPLOY_GROUPS, PARALLEL_DESTROY_GROUPS, OPENNEXT_PARALLEL_GROUPS, PARALLEL_OPERATION_TYPES, isApplicationOperation, isOrganisationOperation, getParallelDeployGroups, getParallelDestroyGroups, getApplicationDeployOrder, getApplicationDestroyOrder, getApplicationStackName, getOrganisationStackName, isApplicationStack, getApplicationStepName, getApplicationStepId, toPascalCase,
|
|
22
|
-
// Pattern detection (browser-safe pure predicates)
|
|
23
|
-
isOpenNextPattern, OPENNEXT_PATTERNS,
|
|
24
|
-
// Pattern detection (Node fs-based)
|
|
25
|
-
deriveResourcesFromManifestStacks,
|
|
26
|
-
// Constants
|
|
27
|
-
STACK_NOT_FOUND_PATTERN, STACK_FAILED_STATE_PATTERN, CDK_NO_STACKS_MATCH, INFRASTRUCTURE_FILENAME,
|
|
28
|
-
// Application errors
|
|
29
|
-
ApplicationError, wrapApplicationError,
|
|
30
|
-
// State management
|
|
31
|
-
FjallStateFileSchema, readStateFile, writeStateFile, createEmptyState, deleteStateFile, updateTemplateHash, getStateFilePath,
|
|
32
|
-
// Caller identity helper
|
|
33
|
-
stubCallerIdentity } from "./types/index.js";
|
|
34
|
-
/** @deprecated Use FrameworkRegistry.resolve() instead */
|
|
35
|
-
export { detectPattern } from "./types/index.js";
|
|
36
|
-
/** @deprecated Use FrameworkRegistry.resolve() instead */
|
|
37
|
-
export { detectPayloadPattern } from "./types/index.js";
|
|
38
|
-
/** @deprecated Use FrameworkRegistry.resolve() instead */
|
|
39
|
-
export { detectDatabase } from "./types/index.js";
|
|
40
|
-
// CloudFormation event monitoring
|
|
41
|
-
export { CloudFormationEventMonitor } from "./aws/index.js";
|
|
42
|
-
// Services (infrastructure, supporting, application)
|
|
43
|
-
export { CdkService, CdkArgumentBuilder, CdkProcessManager, CdkEventMonitor, startStackMonitoring, DEFAULT_DEPLOY_TIMEOUT_MS, isCdkError, formatInfrastructureError, hasCdkDifferences, parseDiffOutput, CloudFormationService, CloudFormationError, TemplateHashService, TemplateHashError, CdkContextBuilder, emitProgress, PROGRESS_MESSAGES, parseBuildPhase, buildStepContextBuildConfig, convertCloudFormationOutputsToRecord, ApplicationStackService } from "./services/index.js";
|
|
44
|
-
// Error types
|
|
45
|
-
export { CdkError } from "./types/errors/index.js";
|
|
46
|
-
export { BaseServiceError, ValidationError, AuthError, AwsError, DeploymentError, NetworkError, FileSystemError, ConfigError, toServiceError } from "./types/errors/index.js";
|
|
47
|
-
// Utilities (re-exported from @fjall/util)
|
|
48
|
-
export { filterDangerousEnvVars, maskSensitiveOutput, parseShellArgs, sleep } from "@fjall/util";
|
|
49
|
-
// Dockerfile detection
|
|
50
|
-
export { hasDockerfile } from "./util/dockerfileDetection.js";
|
|
51
|
-
// Sequenced callbacks wrapper
|
|
52
|
-
export { createSequencedCallbacks } from "./util/sequencedCallbacks.js";
|
|
53
|
-
export { fileExists } from "@fjall/util/fsHelpers";
|
|
54
|
-
// Re-export Result from generator for convenience
|
|
55
|
-
export { success, failure, isSuccess, isFailure } from "@fjall/generator";
|
|
56
|
-
// Orchestration — primary entry points
|
|
57
|
-
export { deploy } from "./orchestration/index.js";
|
|
58
|
-
export { destroy } from "./orchestration/index.js";
|
|
59
|
-
export { partitionAccounts } from "./orchestration/index.js";
|
|
60
|
-
export { runOpenNextBuild } from "./orchestration/index.js";
|
|
61
|
-
export { runOrganisationSetup } from "./orchestration/index.js";
|
|
62
|
-
export { FrameworkRegistry } from "./orchestration/index.js";
|
|
63
|
-
export { openNextBuilder, dockerBuilder } from "./orchestration/index.js";
|
|
64
|
-
// Step registry (filtering & step management)
|
|
65
|
-
export { StepRegistry, getDestroyStepId } from "./steps/index.js";
|
|
1
|
+
import{DeploymentEventSchema as t,DEPLOYMENT_EVENT_TYPES as o,DEPLOYMENT_EVENT_RESOURCE_CATEGORIES as a,CASCADE_PHASES as i,CASCADE_ACCOUNT_STATUSES as E}from"./types/index.js";import{SimpleAwsProvider as p}from"./aws/index.js";import{ensureOrganisationExists as S,describeOrganisation as l,enablePolicyTypes as c,enableServiceAccess as A,enableRamSharing as T,activateTrustedAccess as O,enableIpamDelegatedAdmin as m,updateBackupGlobalSettings as P,listAccounts as u,findAccount as _,createAccount as d,ensureOrganisationalUnitsExist as R,placeAccountsInOUs as C,buildAccountToOUMap as N,activateCostAllocationTags as f,checkIdentityCentreStatus as x,extractErrorName as D,isOULeaf as g,registerSecurityDelegates as I,SECURITY_SERVICE_PRINCIPALS as L}from"./aws/index.js";import{STEP_IDS as F,STEP_NAMES as y,INFRASTRUCTURE_STEP_NAMES as U,INFRA_STEP_NAME as v}from"./types/index.js";import{ProgressReporter as h,APPLICATION_STACKS as Y,ORGANISATION_TYPES as b,APPLICATION_DEPLOY_ORDER as G,APPLICATION_DESTROY_ORDER as B,OPENNEXT_DEPLOY_ORDER as w,OPENNEXT_DESTROY_ORDER as H,PARALLEL_DEPLOY_GROUPS as K,PARALLEL_DESTROY_GROUPS as V,OPENNEXT_PARALLEL_GROUPS as X,PARALLEL_OPERATION_TYPES as j,isApplicationOperation as q,isOrganisationOperation as z,getParallelDeployGroups as J,getParallelDestroyGroups as Q,getApplicationDeployOrder as W,getApplicationDestroyOrder as Z,getApplicationStackName as $,getOrganisationStackName as ee,isApplicationStack as re,getApplicationStepName as te,getApplicationStepId as oe,toPascalCase as ae,isOpenNextPattern as ie,OPENNEXT_PATTERNS as Ee,deriveResourcesFromManifestStacks as se,STACK_NOT_FOUND_PATTERN as pe,STACK_FAILED_STATE_PATTERN as ne,CDK_NO_STACKS_MATCH as Se,INFRASTRUCTURE_FILENAME as le,ApplicationError as ce,wrapApplicationError as Ae,FjallStateFileSchema as Te,readStateFile as Oe,writeStateFile as me,createEmptyState as Pe,deleteStateFile as ue,updateTemplateHash as _e,getStateFilePath as de,stubCallerIdentity as Re}from"./types/index.js";import{detectPattern as Ne}from"./types/index.js";import{detectPayloadPattern as xe}from"./types/index.js";import{detectDatabase as ge}from"./types/index.js";import{CloudFormationEventMonitor as Le}from"./aws/index.js";import{CdkService as Fe,CdkArgumentBuilder as ye,CdkProcessManager as Ue,CdkEventMonitor as ve,startStackMonitoring as Me,DEFAULT_DEPLOY_TIMEOUT_MS as he,isCdkError as Ye,formatInfrastructureError as be,hasCdkDifferences as Ge,parseDiffOutput as Be,CloudFormationService as we,CloudFormationError as He,TemplateHashService as Ke,TemplateHashError as Ve,CdkContextBuilder as Xe,emitProgress as je,PROGRESS_MESSAGES as qe,parseBuildPhase as ze,buildStepContextBuildConfig as Je,convertCloudFormationOutputsToRecord as Qe,ApplicationStackService as We}from"./services/index.js";import{CdkError as $e}from"./types/errors/index.js";import{BaseServiceError as rr,ValidationError as tr,AuthError as or,AwsError as ar,DeploymentError as ir,NetworkError as Er,FileSystemError as sr,ConfigError as pr,toServiceError as nr}from"./types/errors/index.js";import{filterDangerousEnvVars as lr,maskSensitiveOutput as cr,parseShellArgs as Ar,sleep as Tr}from"@fjall/util";import{hasDockerfile as mr}from"./util/dockerfileDetection.js";import{createSequencedCallbacks as ur}from"./util/sequencedCallbacks.js";import{fileExists as dr}from"@fjall/util/fsHelpers";import{success as Cr,failure as Nr,isSuccess as fr,isFailure as xr}from"@fjall/generator";import{deploy as gr}from"./orchestration/index.js";import{destroy as Lr}from"./orchestration/index.js";import{partitionAccounts as Fr}from"./orchestration/index.js";import{runOpenNextBuild as Ur}from"./orchestration/index.js";import{runOrganisationSetup as Mr}from"./orchestration/index.js";import{FrameworkRegistry as Yr}from"./orchestration/index.js";import{openNextBuilder as Gr,dockerBuilder as Br}from"./orchestration/index.js";import{StepRegistry as Hr,getDestroyStepId as Kr}from"./steps/index.js";export{G as APPLICATION_DEPLOY_ORDER,B as APPLICATION_DESTROY_ORDER,Y as APPLICATION_STACKS,ce as ApplicationError,We as ApplicationStackService,or as AuthError,ar as AwsError,rr as BaseServiceError,E as CASCADE_ACCOUNT_STATUSES,i as CASCADE_PHASES,Se as CDK_NO_STACKS_MATCH,ye as CdkArgumentBuilder,Xe as CdkContextBuilder,$e as CdkError,ve as CdkEventMonitor,Ue as CdkProcessManager,Fe as CdkService,He as CloudFormationError,Le as CloudFormationEventMonitor,we as CloudFormationService,pr as ConfigError,he as DEFAULT_DEPLOY_TIMEOUT_MS,a as DEPLOYMENT_EVENT_RESOURCE_CATEGORIES,o as DEPLOYMENT_EVENT_TYPES,ir as DeploymentError,t as DeploymentEventSchema,sr as FileSystemError,Te as FjallStateFileSchema,Yr as FrameworkRegistry,le as INFRASTRUCTURE_FILENAME,U as INFRASTRUCTURE_STEP_NAMES,v as INFRA_STEP_NAME,Er as NetworkError,w as OPENNEXT_DEPLOY_ORDER,H as OPENNEXT_DESTROY_ORDER,X as OPENNEXT_PARALLEL_GROUPS,Ee as OPENNEXT_PATTERNS,b as ORGANISATION_TYPES,K as PARALLEL_DEPLOY_GROUPS,V as PARALLEL_DESTROY_GROUPS,j as PARALLEL_OPERATION_TYPES,qe as PROGRESS_MESSAGES,h as ProgressReporter,L as SECURITY_SERVICE_PRINCIPALS,ne as STACK_FAILED_STATE_PATTERN,pe as STACK_NOT_FOUND_PATTERN,F as STEP_IDS,y as STEP_NAMES,p as SimpleAwsProvider,Hr as StepRegistry,Ve as TemplateHashError,Ke as TemplateHashService,tr as ValidationError,f as activateCostAllocationTags,O as activateTrustedAccess,N as buildAccountToOUMap,Je as buildStepContextBuildConfig,x as checkIdentityCentreStatus,Qe as convertCloudFormationOutputsToRecord,d as createAccount,Pe as createEmptyState,ur as createSequencedCallbacks,ue as deleteStateFile,gr as deploy,se as deriveResourcesFromManifestStacks,l as describeOrganisation,Lr as destroy,ge as detectDatabase,Ne as detectPattern,xe as detectPayloadPattern,Br as dockerBuilder,je as emitProgress,m as enableIpamDelegatedAdmin,c as enablePolicyTypes,T as enableRamSharing,A as enableServiceAccess,S as ensureOrganisationExists,R as ensureOrganisationalUnitsExist,D as extractErrorName,Nr as failure,dr as fileExists,lr as filterDangerousEnvVars,_ as findAccount,be as formatInfrastructureError,W as getApplicationDeployOrder,Z as getApplicationDestroyOrder,$ as getApplicationStackName,oe as getApplicationStepId,te as getApplicationStepName,Kr as getDestroyStepId,ee as getOrganisationStackName,J as getParallelDeployGroups,Q as getParallelDestroyGroups,de as getStateFilePath,Ge as hasCdkDifferences,mr as hasDockerfile,q as isApplicationOperation,re as isApplicationStack,Ye as isCdkError,xr as isFailure,g as isOULeaf,ie as isOpenNextPattern,z as isOrganisationOperation,fr as isSuccess,u as listAccounts,cr as maskSensitiveOutput,Gr as openNextBuilder,ze as parseBuildPhase,Be as parseDiffOutput,Ar as parseShellArgs,Fr as partitionAccounts,C as placeAccountsInOUs,Oe as readStateFile,I as registerSecurityDelegates,Ur as runOpenNextBuild,Mr as runOrganisationSetup,Tr as sleep,Me as startStackMonitoring,Re as stubCallerIdentity,Cr as success,ae as toPascalCase,nr as toServiceError,P as updateBackupGlobalSettings,_e as updateTemplateHash,Ae as wrapApplicationError,me as writeStateFile};
|
|
@@ -1,78 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { success } from "@fjall/generator";
|
|
3
|
-
export const TEST_REGION = "eu-west-1";
|
|
4
|
-
export const TEST_ACCOUNT = {
|
|
5
|
-
id: "222222222222",
|
|
6
|
-
name: "platform",
|
|
7
|
-
environment: "platform"
|
|
8
|
-
};
|
|
9
|
-
export function createOrgOperation() {
|
|
10
|
-
return {
|
|
11
|
-
kind: "organisation",
|
|
12
|
-
type: "organisation",
|
|
13
|
-
target: "organisation",
|
|
14
|
-
path: "/tmp/test/fjall/organisation"
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export function createBaseMockCallbacks() {
|
|
18
|
-
return {
|
|
19
|
-
onLog: vi.fn(),
|
|
20
|
-
onError: vi.fn(),
|
|
21
|
-
onOutput: vi.fn(),
|
|
22
|
-
onStepStart: vi.fn(),
|
|
23
|
-
onStepComplete: vi.fn(),
|
|
24
|
-
onCascadeStart: vi.fn(),
|
|
25
|
-
onCascadePhaseStart: vi.fn(),
|
|
26
|
-
onCascadeAccountStart: vi.fn(),
|
|
27
|
-
onCascadeAccountPhaseChange: vi.fn(),
|
|
28
|
-
onCascadeAccountResourceProgress: vi.fn(),
|
|
29
|
-
onCascadeAccountComplete: vi.fn(),
|
|
30
|
-
onCascadeComplete: vi.fn(),
|
|
31
|
-
onResourceProgress: vi.fn(),
|
|
32
|
-
onCdkOutput: vi.fn()
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
export function createMockServices(overrides) {
|
|
36
|
-
return {
|
|
37
|
-
awsProvider: {
|
|
38
|
-
getRegion: vi.fn().mockReturnValue(TEST_REGION),
|
|
39
|
-
getAccountId: vi.fn().mockReturnValue("111111111111"),
|
|
40
|
-
exportToEnv: vi.fn(),
|
|
41
|
-
getClient: vi.fn(),
|
|
42
|
-
getCredentials: vi.fn().mockReturnValue({
|
|
43
|
-
accessKeyId: "AKIA_TEST",
|
|
44
|
-
secretAccessKey: "secret_test",
|
|
45
|
-
sessionToken: "token_test"
|
|
46
|
-
}),
|
|
47
|
-
assumeRole: vi.fn().mockResolvedValue({
|
|
48
|
-
accessKeyId: "AKIA_ASSUMED",
|
|
49
|
-
secretAccessKey: "secret_assumed",
|
|
50
|
-
sessionToken: "token_assumed"
|
|
51
|
-
}),
|
|
52
|
-
...overrides?.awsProvider
|
|
53
|
-
},
|
|
54
|
-
cdkService: {
|
|
55
|
-
runCdkSynth: vi.fn().mockResolvedValue(success(undefined)),
|
|
56
|
-
runCdkBootstrap: vi.fn().mockResolvedValue(success(undefined)),
|
|
57
|
-
runCdkDeploy: vi.fn().mockResolvedValue(success(undefined)),
|
|
58
|
-
runCdkDestroy: vi.fn().mockResolvedValue(success(undefined)),
|
|
59
|
-
...overrides?.cdkService
|
|
60
|
-
},
|
|
61
|
-
cfnService: {
|
|
62
|
-
getStackOutputs: vi.fn().mockResolvedValue(success([])),
|
|
63
|
-
stackExists: vi.fn().mockResolvedValue(true),
|
|
64
|
-
...overrides?.cfnService
|
|
65
|
-
},
|
|
66
|
-
stackService: {
|
|
67
|
-
...overrides?.stackService
|
|
68
|
-
},
|
|
69
|
-
hashService: {
|
|
70
|
-
...overrides?.hashService
|
|
71
|
-
},
|
|
72
|
-
frameworkRegistry: {
|
|
73
|
-
resolve: vi.fn().mockReturnValue(null),
|
|
74
|
-
...overrides?.frameworkRegistry
|
|
75
|
-
},
|
|
76
|
-
dispose: vi.fn()
|
|
77
|
-
};
|
|
78
|
-
}
|
|
1
|
+
import{vi as e}from"vitest";import{success as t}from"@fjall/generator";const o="eu-west-1",a={id:"222222222222",name:"platform",environment:"platform"};function r(){return{kind:"organisation",type:"organisation",target:"organisation",path:"/tmp/test/fjall/organisation"}}function u(){return{onLog:e.fn(),onError:e.fn(),onOutput:e.fn(),onStepStart:e.fn(),onStepComplete:e.fn(),onCascadeStart:e.fn(),onCascadePhaseStart:e.fn(),onCascadeAccountStart:e.fn(),onCascadeAccountPhaseChange:e.fn(),onCascadeAccountResourceProgress:e.fn(),onCascadeAccountComplete:e.fn(),onCascadeComplete:e.fn(),onResourceProgress:e.fn(),onCdkOutput:e.fn()}}function f(n){return{awsProvider:{getRegion:e.fn().mockReturnValue(o),getAccountId:e.fn().mockReturnValue("111111111111"),exportToEnv:e.fn(),getClient:e.fn(),getCredentials:e.fn().mockReturnValue({accessKeyId:"AKIA_TEST",secretAccessKey:"secret_test",sessionToken:"token_test"}),assumeRole:e.fn().mockResolvedValue({accessKeyId:"AKIA_ASSUMED",secretAccessKey:"secret_assumed",sessionToken:"token_assumed"}),...n?.awsProvider},cdkService:{runCdkSynth:e.fn().mockResolvedValue(t(void 0)),runCdkBootstrap:e.fn().mockResolvedValue(t(void 0)),runCdkDeploy:e.fn().mockResolvedValue(t(void 0)),runCdkDestroy:e.fn().mockResolvedValue(t(void 0)),...n?.cdkService},cfnService:{getStackOutputs:e.fn().mockResolvedValue(t([])),stackExists:e.fn().mockResolvedValue(!0),...n?.cfnService},stackService:{...n?.stackService},hashService:{...n?.hashService},frameworkRegistry:{resolve:e.fn().mockReturnValue(null),...n?.frameworkRegistry},dispose:e.fn()}}export{a as TEST_ACCOUNT,o as TEST_REGION,u as createBaseMockCallbacks,f as createMockServices,r as createOrgOperation};
|
|
@@ -1,39 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* Uses the canonical stackStatusMap to determine whether a status
|
|
8
|
-
* is blocking — specifically `safeToRedeploy === "No"`.
|
|
9
|
-
*/
|
|
10
|
-
export async function checkActiveDeployments(stackNames, cfnService) {
|
|
11
|
-
if (stackNames.length === 0) {
|
|
12
|
-
return success(undefined);
|
|
13
|
-
}
|
|
14
|
-
const statusResults = await Promise.all(stackNames.map(async (name) => {
|
|
15
|
-
const result = await cfnService.getStackStatus(name);
|
|
16
|
-
return { name, result };
|
|
17
|
-
}));
|
|
18
|
-
const busyStacks = [];
|
|
19
|
-
for (const { name, result } of statusResults) {
|
|
20
|
-
if (!result.success) {
|
|
21
|
-
return failure(result.error);
|
|
22
|
-
}
|
|
23
|
-
const stackStatus = result.data;
|
|
24
|
-
if (stackStatus === null || stackStatus.status === "DOES_NOT_EXIST") {
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
const mapped = stackStatusMap[stackStatus.status];
|
|
28
|
-
if (mapped?.safeToRedeploy === "No") {
|
|
29
|
-
busyStacks.push({ name, status: stackStatus.status });
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
if (busyStacks.length > 0) {
|
|
33
|
-
const details = busyStacks
|
|
34
|
-
.map((s) => ` ${s.name}: ${s.status}`)
|
|
35
|
-
.join("\n");
|
|
36
|
-
return failure(new Error(`Cannot proceed while stacks are busy:\n${details}\n\nWait for the in-progress operation to complete, or use --force to override.`));
|
|
37
|
-
}
|
|
38
|
-
return success(undefined);
|
|
39
|
-
}
|
|
1
|
+
import{success as r,failure as a}from"@fjall/generator";import{stackStatusMap as i}from"../aws/utils/stackStatus.js";async function d(o,u){if(o.length===0)return r(void 0);const c=await Promise.all(o.map(async e=>{const t=await u.getStackStatus(e);return{name:e,result:t}})),n=[];for(const{name:e,result:t}of c){if(!t.success)return a(t.error);const s=t.data;if(s===null||s.status==="DOES_NOT_EXIST")continue;i[s.status]?.safeToRedeploy==="No"&&n.push({name:e,status:s.status})}if(n.length>0){const e=n.map(t=>` ${t.name}: ${t.status}`).join(`
|
|
2
|
+
`);return a(new Error(`Cannot proceed while stacks are busy:
|
|
3
|
+
${e}
|
|
4
|
+
|
|
5
|
+
Wait for the in-progress operation to complete, or use --force to override.`))}return r(void 0)}export{d as checkActiveDeployments};
|
|
@@ -1,149 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { logger } from "@fjall/util/logger";
|
|
3
|
-
import { stubCallerIdentity } from "../types/deployment/index.js";
|
|
4
|
-
import { getApplicationDeployOrder, getApplicationStackName, getApplicationStepName, getApplicationStepId } from "../types/operations.js";
|
|
5
|
-
import { CdkContextBuilder } from "../services/supporting/CdkContextBuilder.js";
|
|
6
|
-
import { buildParamsContext, bootstrapOrFail } from "./contextHelpers.js";
|
|
7
|
-
import { runDetectionPipeline } from "./detectionPipeline.js";
|
|
8
|
-
import { getParallelPhase2Stacks, deployParallelPhase, deployStackSequential, runDockerPreCompute, deployAllStacks, createBuildCallbacks } from "./applicationDeployHelpers.js";
|
|
9
|
-
/**
|
|
10
|
-
* Core application deployment orchestration.
|
|
11
|
-
*
|
|
12
|
-
* Runs detection, bootstraps AWS, then deploys stacks in order —
|
|
13
|
-
* parallelising Phase 2 stacks (Storage, Messaging, Database) when possible.
|
|
14
|
-
*/
|
|
15
|
-
export async function deployApplication(params, services, operation) {
|
|
16
|
-
const { callbacks, options } = params;
|
|
17
|
-
const startTime = Date.now();
|
|
18
|
-
// 1. Build deployment context
|
|
19
|
-
const context = CdkContextBuilder.buildDeploymentContext({
|
|
20
|
-
deployType: "application",
|
|
21
|
-
target: operation.appName,
|
|
22
|
-
path: operation.path,
|
|
23
|
-
region: services.awsProvider.getRegion(),
|
|
24
|
-
callerIdentity: stubCallerIdentity(services.awsProvider.getAccountId()),
|
|
25
|
-
...buildParamsContext({
|
|
26
|
-
orgConfig: params.orgConfig,
|
|
27
|
-
identity: params.identity,
|
|
28
|
-
skipOidc: params.options?.skipOidc
|
|
29
|
-
})
|
|
30
|
-
}, {
|
|
31
|
-
verbose: options?.verbose,
|
|
32
|
-
infraOnly: options?.infraOnly
|
|
33
|
-
}, params.orgConfig);
|
|
34
|
-
// 1b. Resolve framework builder and run build (if applicable — runs before detection)
|
|
35
|
-
const resolved = services.frameworkRegistry.resolve({
|
|
36
|
-
appPath: operation.path
|
|
37
|
-
});
|
|
38
|
-
let plan;
|
|
39
|
-
if (resolved) {
|
|
40
|
-
plan = resolved.builder.plan({ appPath: operation.path }, resolved.detection);
|
|
41
|
-
const buildCallbacks = createBuildCallbacks(callbacks);
|
|
42
|
-
const buildResult = await resolved.builder.build(operation.path, plan, buildCallbacks, { skipBuild: options?.skipBuild, infraOnly: options?.infraOnly });
|
|
43
|
-
if (!buildResult.success) {
|
|
44
|
-
callbacks.onError?.(buildResult.error);
|
|
45
|
-
return failure(buildResult.error);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
// deployOnly: skip detection pipeline, deploy all stacks unconditionally
|
|
49
|
-
if (options?.deployOnly) {
|
|
50
|
-
callbacks.onLog?.("Deploy-only mode — skipping change detection", "info");
|
|
51
|
-
return deployAllStacks(params, services, operation, context, startTime, plan);
|
|
52
|
-
}
|
|
53
|
-
// 2. Run detection pipeline
|
|
54
|
-
callbacks.onLog?.("Analysing infrastructure…", "info");
|
|
55
|
-
const detectionResult = await runDetectionPipeline(operation, services, context, callbacks);
|
|
56
|
-
if (!detectionResult.success) {
|
|
57
|
-
callbacks.onError?.(detectionResult.error);
|
|
58
|
-
return failure(detectionResult.error);
|
|
59
|
-
}
|
|
60
|
-
const detection = detectionResult.data;
|
|
61
|
-
// 2b. Notify callers of detection results (resource flags, pattern, etc.)
|
|
62
|
-
// Awaited so callers can run post-detection hooks (e.g. secrets validation).
|
|
63
|
-
await callbacks.onDetectionComplete?.({
|
|
64
|
-
...detection,
|
|
65
|
-
builderName: resolved?.builder.name ?? "unknown"
|
|
66
|
-
});
|
|
67
|
-
// 3. Early exit if no differences
|
|
68
|
-
if (!detection.hasDifferences && !options?.force) {
|
|
69
|
-
callbacks.onLog?.("No infrastructure changes detected", "info");
|
|
70
|
-
return success({
|
|
71
|
-
target: operation.appName,
|
|
72
|
-
deploymentType: "application",
|
|
73
|
-
durationMs: Date.now() - startTime
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
// 4. Bootstrap AWS environment
|
|
77
|
-
const bsResult = await bootstrapOrFail(services, context, callbacks);
|
|
78
|
-
if (!bsResult.success)
|
|
79
|
-
return bsResult;
|
|
80
|
-
// 5. Determine deploy order (prefer plan from registry, fall back to legacy)
|
|
81
|
-
const deployOrder = plan
|
|
82
|
-
? plan.deployOrder
|
|
83
|
-
: getApplicationDeployOrder({
|
|
84
|
-
pattern: detection.pattern,
|
|
85
|
-
resources: detection.resources
|
|
86
|
-
});
|
|
87
|
-
const totalSteps = deployOrder.length;
|
|
88
|
-
// 6. Deploy stacks
|
|
89
|
-
const allOutputs = {};
|
|
90
|
-
const deployedHashes = new Map();
|
|
91
|
-
for (let i = 0; i < deployOrder.length; i++) {
|
|
92
|
-
const stack = deployOrder[i];
|
|
93
|
-
const stackName = getApplicationStackName(operation.appName, stack);
|
|
94
|
-
const stepId = getApplicationStepId(stack, "deploy");
|
|
95
|
-
const stepName = getApplicationStepName(stack, "deploy");
|
|
96
|
-
// Check if stack is unchanged and exists
|
|
97
|
-
const hasChanges = detection.stackChanges.get(stackName) ?? true;
|
|
98
|
-
if (!hasChanges && !options?.force) {
|
|
99
|
-
callbacks.onStepStart?.(stepId, stepName, i, totalSteps);
|
|
100
|
-
callbacks.onLog?.(`Skipping ${stack} — no changes detected`, "info");
|
|
101
|
-
callbacks.onStepComplete?.(stepId, stepName, "skipped", i, totalSteps);
|
|
102
|
-
continue;
|
|
103
|
-
}
|
|
104
|
-
// Check for Phase 2 parallel deployment opportunity
|
|
105
|
-
const parallelStacks = getParallelPhase2Stacks(deployOrder, i, detection.stackChanges, options?.force);
|
|
106
|
-
if (parallelStacks.length >= 2) {
|
|
107
|
-
const parallelResult = await deployParallelPhase(parallelStacks, operation, services, context, callbacks, i, totalSteps, detection, allOutputs, deployedHashes);
|
|
108
|
-
if (!parallelResult.success)
|
|
109
|
-
return failure(parallelResult.error);
|
|
110
|
-
// Skip past the parallel stacks in the main loop
|
|
111
|
-
i += parallelStacks.length - 1;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
// Docker operations before Compute stack
|
|
115
|
-
const dockerFailed = await runDockerPreCompute(stack, params, services, operation, callbacks, detection.hasDockerfile);
|
|
116
|
-
if (dockerFailed)
|
|
117
|
-
return dockerFailed;
|
|
118
|
-
// Sequential deployment
|
|
119
|
-
const deployResult = await deployStackSequential(stack, services, context, callbacks, i, totalSteps, allOutputs);
|
|
120
|
-
if (!deployResult.success)
|
|
121
|
-
return failure(deployResult.error);
|
|
122
|
-
// Track deployed hashes
|
|
123
|
-
const hash = detection.currentHashes.get(stackName);
|
|
124
|
-
if (hash) {
|
|
125
|
-
deployedHashes.set(stackName, hash);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// 7. Update state file with deployed hashes
|
|
129
|
-
if (deployedHashes.size > 0) {
|
|
130
|
-
const stateResult = await services.hashService.updateStateAfterDeploy(operation.path, deployedHashes);
|
|
131
|
-
if (!stateResult.success) {
|
|
132
|
-
logger.debug("applicationDeploy", "Failed to update state file", {
|
|
133
|
-
error: stateResult.error.message
|
|
134
|
-
});
|
|
135
|
-
callbacks.onLog?.(`Warning: failed to update state file — next deploy may re-deploy unchanged stacks: ${stateResult.error.message}`, "warn");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
// 8. Resolve website URL
|
|
139
|
-
const websiteUrl = await services.stackService.resolveWebsiteUrl(operation.appName);
|
|
140
|
-
if (websiteUrl) {
|
|
141
|
-
allOutputs.websiteUrl = websiteUrl;
|
|
142
|
-
}
|
|
143
|
-
return success({
|
|
144
|
-
target: operation.appName,
|
|
145
|
-
deploymentType: "application",
|
|
146
|
-
outputs: Object.keys(allOutputs).length > 0 ? allOutputs : undefined,
|
|
147
|
-
durationMs: Date.now() - startTime
|
|
148
|
-
});
|
|
149
|
-
}
|
|
1
|
+
import{success as R,failure as m}from"@fjall/generator";import{logger as x}from"@fjall/util/logger";import{stubCallerIdentity as I}from"../types/deployment/index.js";import{getApplicationDeployOrder as L,getApplicationStackName as B,getApplicationStepName as T,getApplicationStepId as F}from"../types/operations.js";import{CdkContextBuilder as M}from"../services/supporting/CdkContextBuilder.js";import{buildParamsContext as U,bootstrapOrFail as E}from"./contextHelpers.js";import{runDetectionPipeline as H}from"./detectionPipeline.js";import{getParallelPhase2Stacks as W,deployParallelPhase as $,deployStackSequential as j,runDockerPreCompute as q,deployAllStacks as z,createBuildCallbacks as G}from"./applicationDeployHelpers.js";async function ee(l,n,o){const{callbacks:e,options:i}=l,h=Date.now(),s=M.buildDeploymentContext({deployType:"application",target:o.appName,path:o.path,region:n.awsProvider.getRegion(),callerIdentity:I(n.awsProvider.getAccountId()),...U({orgConfig:l.orgConfig,identity:l.identity,skipOidc:l.options?.skipOidc})},{verbose:i?.verbose,infraOnly:i?.infraOnly},l.orgConfig),c=n.frameworkRegistry.resolve({appPath:o.path});let p;if(c){p=c.builder.plan({appPath:o.path},c.detection);const t=G(e),a=await c.builder.build(o.path,p,t,{skipBuild:i?.skipBuild,infraOnly:i?.infraOnly});if(!a.success)return e.onError?.(a.error),m(a.error)}if(i?.deployOnly)return e.onLog?.("Deploy-only mode \u2014 skipping change detection","info"),z(l,n,o,s,h,p);e.onLog?.("Analysing infrastructure\u2026","info");const u=await H(o,n,s,e);if(!u.success)return e.onError?.(u.error),m(u.error);const r=u.data;if(await e.onDetectionComplete?.({...r,builderName:c?.builder.name??"unknown"}),!r.hasDifferences&&!i?.force)return e.onLog?.("No infrastructure changes detected","info"),R({target:o.appName,deploymentType:"application",durationMs:Date.now()-h});const w=await E(n,s,e);if(!w.success)return w;const f=p?p.deployOrder:L({pattern:r.pattern,resources:r.resources}),g=f.length,d={},y=new Map;for(let t=0;t<f.length;t++){const a=f[t],k=B(o.appName,a),S=F(a,"deploy"),D=T(a,"deploy");if(!(r.stackChanges.get(k)??!0)&&!i?.force){e.onStepStart?.(S,D,t,g),e.onLog?.(`Skipping ${a} \u2014 no changes detected`,"info"),e.onStepComplete?.(S,D,"skipped",t,g);continue}const b=W(f,t,r.stackChanges,i?.force);if(b.length>=2){const A=await $(b,o,n,s,e,t,g,r,d,y);if(!A.success)return m(A.error);t+=b.length-1;continue}const O=await q(a,l,n,o,e,r.hasDockerfile);if(O)return O;const N=await j(a,n,s,e,t,g,d);if(!N.success)return m(N.error);const P=r.currentHashes.get(k);P&&y.set(k,P)}if(y.size>0){const t=await n.hashService.updateStateAfterDeploy(o.path,y);t.success||(x.debug("applicationDeploy","Failed to update state file",{error:t.error.message}),e.onLog?.(`Warning: failed to update state file \u2014 next deploy may re-deploy unchanged stacks: ${t.error.message}`,"warn"))}const C=await n.stackService.resolveWebsiteUrl(o.appName);return C&&(d.websiteUrl=C),R({target:o.appName,deploymentType:"application",outputs:Object.keys(d).length>0?d:void 0,durationMs:Date.now()-h})}export{ee as deployApplication};
|