@@ -24,6 +24,8 @@ const {
2424 getFilesCountWithExtension
2525} = require ( '../../lib/app-helper' )
2626const rtLib = require ( '@adobe/aio-lib-runtime' )
27+ const dbLib = require ( '@adobe/aio-lib-db' )
28+ const { DB_STATUS } = require ( '../../lib/defaults' )
2729const LogForwarding = require ( '../../lib/log-forwarding' )
2830const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require ( '../../lib/audit-logger' )
2931const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require ( '../../lib/auth-helper' )
@@ -133,7 +135,7 @@ class Deploy extends BuildCommand {
133135 const v = {
134136 ...setRuntimeApiHostAndAuthHandler ( values [ i ] )
135137 }
136- await this . deploySingleConfig ( { name : k , config : v , originalConfig : values [ i ] , flags, spinner } )
138+ await this . deploySingleConfig ( { name : k , config : v , originalConfig : values [ i ] , flags, spinner, accessToken : cliDetails ?. accessToken } )
137139 if ( cliDetails ?. accessToken && v . app . hasFrontend && flags [ 'web-assets' ] ) {
138140 const opItems = getFilesCountWithExtension ( v . web . distProd )
139141 try {
@@ -172,7 +174,7 @@ class Deploy extends BuildCommand {
172174 this . log ( chalk . green ( chalk . bold ( 'Successful deployment 🏄' ) ) )
173175 }
174176
175- async deploySingleConfig ( { name, config, originalConfig, flags, spinner } ) {
177+ async deploySingleConfig ( { name, config, originalConfig, flags, spinner, accessToken } ) {
176178 const onProgress = ! flags . verbose
177179 ? info => {
178180 spinner . text = info
@@ -204,6 +206,11 @@ class Deploy extends BuildCommand {
204206 this . error ( err )
205207 }
206208
209+ // provision database if configured
210+ if ( config . manifest ?. full ?. database ?. [ 'auto-provision' ] === true ) {
211+ await this . provisionDatabase ( config , spinner , flags , accessToken )
212+ }
213+
207214 if ( flags . actions ) {
208215 if ( config . app . hasBackend ) {
209216 let filterEntities
@@ -300,6 +307,79 @@ class Deploy extends BuildCommand {
300307 }
301308 }
302309
310+ async provisionDatabase ( config , spinner , flags , accessToken ) {
311+ const { namespace } = config . ow || { }
312+ if ( ! ( namespace ) ) {
313+ throw new Error ( 'Database deployment requires OW namespace configuration.' )
314+ }
315+ if ( ! accessToken ) {
316+ throw new Error ( 'Database deployment requires an IMS access token.' )
317+ }
318+
319+ const region = config . manifest ?. full ?. database ?. region
320+ const regionMess = region ? `'${ region } '` : 'default'
321+
322+ const progress = ( { next = undefined , status = undefined , verboseOnly = false } , statusMethod = spinner . info ) => {
323+ if ( flags . verbose ) {
324+ const method = statusMethod . bind ( spinner )
325+ method ( status )
326+ spinner . start ( next )
327+ } else if ( next && ! verboseOnly ) {
328+ spinner . text = next
329+ }
330+ }
331+
332+ let provRes
333+ try {
334+ spinner . start ( `Deploying database in the ${ regionMess } region...` )
335+
336+ const db = await dbLib . init ( { ow : { namespace } , region, token : accessToken } )
337+
338+ progress ( { next : 'Checking existing database deployment status...' , verboseOnly : true } )
339+
340+ let prevStatus
341+ let statusRegion
342+ const next = `Submitting database provisioning request in the ${ regionMess } region...`
343+ try {
344+ const statusRes = await db . provisionStatus ( )
345+ prevStatus = statusRes . status . toUpperCase ( )
346+ statusRegion = statusRes . region
347+ const regionMessage = statusRegion ? ` in region '${ statusRegion } '` : ''
348+ progress ( { status : chalk . dim ( `Existing database provisioning status: ${ prevStatus } ${ regionMessage } ` ) , next } )
349+ } catch ( err ) {
350+ progress ( { status : chalk . red ( `Database status check failed: ${ err . message } ` ) , next } , spinner . warn )
351+ prevStatus = null
352+ }
353+
354+ if ( prevStatus === DB_STATUS . PROVISIONED ) {
355+ spinner . succeed ( chalk . green ( `Database is deployed and ready for use in the '${ statusRegion } ' region` ) )
356+ return
357+ } else if ( prevStatus === DB_STATUS . REQUESTED || prevStatus === DB_STATUS . PROCESSING ) {
358+ spinner . succeed ( chalk . green ( `Database provisioning request has already been submitted in the '${ statusRegion } ' region and is pending` ) )
359+ return
360+ }
361+
362+ provRes = await db . provisionRequest ( )
363+ progress ( { status : chalk . dim ( `Database provisioning result:\n${ JSON . stringify ( provRes , null , 2 ) } ` ) } )
364+ } catch ( error ) {
365+ spinner . fail ( chalk . red ( 'Database deployment failed' ) )
366+ throw error
367+ }
368+
369+ const resultStatus = provRes ?. status ?. toUpperCase ( ) || DB_STATUS . UNKNOWN
370+ if ( resultStatus === DB_STATUS . PROVISIONED ) {
371+ spinner . succeed ( chalk . green ( `Database is deployed and ready for use in the '${ provRes . region } ' region` ) )
372+ } else if ( resultStatus === DB_STATUS . REQUESTED || resultStatus === DB_STATUS . PROCESSING ) {
373+ spinner . succeed ( chalk . green ( `Database provisioning request submitted in the '${ provRes . region } ' region, database deployment is now pending` ) )
374+ } else if ( resultStatus === DB_STATUS . FAILED || resultStatus === DB_STATUS . REJECTED ) {
375+ const message = `Database provisioning request failed with status '${ resultStatus } '`
376+ spinner . fail ( chalk . red ( message ) )
377+ throw new Error ( `${ message } : ${ provRes . message || 'Unknown error' } ` )
378+ } else {
379+ spinner . warn ( chalk . yellow ( `Database provisioning request returned unexpected status '${ resultStatus } ', an update to the aio cli tool may be necessary.` ) )
380+ }
381+ }
382+
303383 async publishExtensionPoints ( deployConfigs , aioConfig , force ) {
304384 const libConsoleCLI = await this . getLibConsoleCLI ( )
305385
0 commit comments