@adobe/aio-cli-plugin-app 14.5.1 → 14.5.2-pre.2026-03-11.sha-58926dfa
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/README.md +821 -0
- package/package.json +15 -13
- package/src/commands/app/deploy.js +82 -2
- package/src/commands/app/undeploy.js +43 -50
- package/src/lib/defaults.js +12 -1
- package/oclif.manifest.json +0 -2438
package/package.json
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/aio-cli-plugin-app",
|
|
3
3
|
"description": "Create, Build and Deploy Adobe I/O Applications",
|
|
4
|
-
"version": "14.5.
|
|
4
|
+
"version": "14.5.2-pre.2026-03-11.sha-58926dfa",
|
|
5
5
|
"author": "Adobe Inc.",
|
|
6
6
|
"bugs": "https://github.com/adobe/aio-cli-plugin-app/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@adobe/aio-cli-lib-app-config": "
|
|
9
|
-
"@adobe/aio-cli-lib-console": "
|
|
10
|
-
"@adobe/aio-lib-core-config": "
|
|
11
|
-
"@adobe/aio-lib-core-logging": "
|
|
12
|
-
"@adobe/aio-lib-core-networking": "
|
|
13
|
-
"@adobe/aio-lib-
|
|
14
|
-
"@adobe/aio-lib-
|
|
15
|
-
"@adobe/aio-lib-
|
|
8
|
+
"@adobe/aio-cli-lib-app-config": "next",
|
|
9
|
+
"@adobe/aio-cli-lib-console": "next",
|
|
10
|
+
"@adobe/aio-lib-core-config": "next",
|
|
11
|
+
"@adobe/aio-lib-core-logging": "next",
|
|
12
|
+
"@adobe/aio-lib-core-networking": "next",
|
|
13
|
+
"@adobe/aio-lib-db": "^0.2.0-beta.1",
|
|
14
|
+
"@adobe/aio-lib-env": "next",
|
|
15
|
+
"@adobe/aio-lib-ims": "next",
|
|
16
|
+
"@adobe/aio-lib-runtime": "next",
|
|
16
17
|
"@adobe/aio-lib-templates": "^3",
|
|
17
|
-
"@adobe/aio-lib-web": "
|
|
18
|
-
"@adobe/generator-aio-app": "
|
|
18
|
+
"@adobe/aio-lib-web": "next",
|
|
19
|
+
"@adobe/generator-aio-app": "next",
|
|
19
20
|
"@adobe/generator-app-common-lib": "^3",
|
|
20
21
|
"@adobe/inquirer-table-checkbox": "^2",
|
|
21
22
|
"@oclif/core": "^2.11.6",
|
|
@@ -103,5 +104,6 @@
|
|
|
103
104
|
},
|
|
104
105
|
"bin": {
|
|
105
106
|
"aio-next": "./bin/run"
|
|
106
|
-
}
|
|
107
|
-
|
|
107
|
+
},
|
|
108
|
+
"prereleaseSha": "58926dfa0a67e1a957eaa48a777e0eae8a93fad4"
|
|
109
|
+
}
|
|
@@ -24,6 +24,8 @@ const {
|
|
|
24
24
|
getFilesCountWithExtension
|
|
25
25
|
} = require('../../lib/app-helper')
|
|
26
26
|
const rtLib = require('@adobe/aio-lib-runtime')
|
|
27
|
+
const dbLib = require('@adobe/aio-lib-db')
|
|
28
|
+
const { DB_STATUS } = require('../../lib/defaults')
|
|
27
29
|
const LogForwarding = require('../../lib/log-forwarding')
|
|
28
30
|
const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require('../../lib/audit-logger')
|
|
29
31
|
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')
|
|
@@ -133,7 +135,7 @@ class Deploy extends BuildCommand {
|
|
|
133
135
|
const v = {
|
|
134
136
|
...setRuntimeApiHostAndAuthHandler(values[i])
|
|
135
137
|
}
|
|
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 })
|
|
137
139
|
if (cliDetails?.accessToken && v.app.hasFrontend && flags['web-assets']) {
|
|
138
140
|
const opItems = getFilesCountWithExtension(v.web.distProd)
|
|
139
141
|
try {
|
|
@@ -172,7 +174,7 @@ class Deploy extends BuildCommand {
|
|
|
172
174
|
this.log(chalk.green(chalk.bold('Successful deployment 🏄')))
|
|
173
175
|
}
|
|
174
176
|
|
|
175
|
-
async deploySingleConfig ({ name, config, originalConfig, flags, spinner }) {
|
|
177
|
+
async deploySingleConfig ({ name, config, originalConfig, flags, spinner, accessToken }) {
|
|
176
178
|
const onProgress = !flags.verbose
|
|
177
179
|
? info => {
|
|
178
180
|
spinner.text = info
|
|
@@ -204,6 +206,11 @@ class Deploy extends BuildCommand {
|
|
|
204
206
|
this.error(err)
|
|
205
207
|
}
|
|
206
208
|
|
|
209
|
+
// provision database if configured
|
|
210
|
+
if (config.manifest?.full?.database?.['auto-provision'] === true) {
|
|
211
|
+
await this.provisionDatabase(config, spinner, flags, accessToken)
|
|
212
|
+
}
|
|
213
|
+
|
|
207
214
|
if (flags.actions) {
|
|
208
215
|
if (config.app.hasBackend) {
|
|
209
216
|
let filterEntities
|
|
@@ -300,6 +307,79 @@ class Deploy extends BuildCommand {
|
|
|
300
307
|
}
|
|
301
308
|
}
|
|
302
309
|
|
|
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
|
+
|
|
303
383
|
async publishExtensionPoints (deployConfigs, aioConfig, force) {
|
|
304
384
|
const libConsoleCLI = await this.getLibConsoleCLI()
|
|
305
385
|
|
|
@@ -50,65 +50,60 @@ class Undeploy extends BaseCommand {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
const spinner = ora()
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
|
|
54
|
+
const { aio: aioConfig, packagejson: packageJson } = await this.getFullConfig({}, flags)
|
|
55
|
+
const cliDetails = await getAccessToken({ useCachedToken: !flags.unpublish })
|
|
56
|
+
const appInfo = {
|
|
57
|
+
name: packageJson.name,
|
|
58
|
+
version: packageJson.version,
|
|
59
|
+
project: aioConfig?.project,
|
|
60
|
+
runtimeNamespace: aioConfig?.runtime?.namespace
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (cliDetails?.accessToken) {
|
|
64
|
+
try {
|
|
65
|
+
// send audit log at start (don't wait for deployment to finish)
|
|
66
|
+
await sendAppUndeployAuditLog({
|
|
67
|
+
accessToken: cliDetails?.accessToken,
|
|
68
|
+
cliCommandFlags: flags,
|
|
69
|
+
appInfo,
|
|
70
|
+
env: cliDetails.env
|
|
71
|
+
})
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (flags.verbose) {
|
|
74
|
+
this.warn('Error: Audit Log Service Error: Failed to send audit log event for deployment.')
|
|
75
|
+
this.warn(error.message)
|
|
76
|
+
}
|
|
61
77
|
}
|
|
78
|
+
}
|
|
62
79
|
|
|
80
|
+
for (let i = 0; i < keys.length; ++i) {
|
|
81
|
+
const k = keys[i]
|
|
82
|
+
// TODO: remove this check once the deploy service is enabled by default
|
|
83
|
+
const v = setRuntimeApiHostAndAuthHandler(values[i])
|
|
84
|
+
|
|
85
|
+
await this.undeployOneExt(k, v, flags, spinner)
|
|
63
86
|
if (cliDetails?.accessToken) {
|
|
87
|
+
// send logs for case of web-assets undeployment
|
|
64
88
|
try {
|
|
65
|
-
|
|
66
|
-
await sendAppUndeployAuditLog({
|
|
89
|
+
await sendAppAssetsUndeployedAuditLog({
|
|
67
90
|
accessToken: cliDetails?.accessToken,
|
|
68
91
|
cliCommandFlags: flags,
|
|
69
92
|
appInfo,
|
|
70
93
|
env: cliDetails.env
|
|
71
94
|
})
|
|
72
95
|
} catch (error) {
|
|
73
|
-
|
|
74
|
-
this.warn('Error: Audit Log Service Error: Failed to send audit log event for deployment.')
|
|
75
|
-
this.warn(error.message)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
for (let i = 0; i < keys.length; ++i) {
|
|
81
|
-
const k = keys[i]
|
|
82
|
-
// TODO: remove this check once the deploy service is enabled by default
|
|
83
|
-
const v = setRuntimeApiHostAndAuthHandler(values[i])
|
|
84
|
-
|
|
85
|
-
await this.undeployOneExt(k, v, flags, spinner)
|
|
86
|
-
if (cliDetails?.accessToken) {
|
|
87
|
-
// send logs for case of web-assets undeployment
|
|
88
|
-
try {
|
|
89
|
-
await sendAppAssetsUndeployedAuditLog({
|
|
90
|
-
accessToken: cliDetails?.accessToken,
|
|
91
|
-
cliCommandFlags: flags,
|
|
92
|
-
appInfo,
|
|
93
|
-
env: cliDetails.env
|
|
94
|
-
})
|
|
95
|
-
} catch (error) {
|
|
96
|
-
this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.')
|
|
97
|
-
}
|
|
96
|
+
this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.')
|
|
98
97
|
}
|
|
99
98
|
}
|
|
99
|
+
}
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
} catch (error) {
|
|
109
|
-
spinner.stop()
|
|
110
|
-
// delegate to top handler
|
|
111
|
-
throw error
|
|
101
|
+
// 1.2. unpublish extension manifest
|
|
102
|
+
if (flags.unpublish) {
|
|
103
|
+
const payload = await this.unpublishExtensionPoints(libConsoleCLI, undeployConfigs, aioConfig, flags['force-unpublish'])
|
|
104
|
+
this.log(chalk.blue(chalk.bold(`New Extension Point(s) in Workspace '${aioConfig.project.workspace.name}': '${Object.keys(payload.endpoints)}'`)))
|
|
105
|
+
} else {
|
|
106
|
+
this.log('skipping unpublish phase...')
|
|
112
107
|
}
|
|
113
108
|
|
|
114
109
|
const command = await this.config.findCommand('app:clean')
|
|
@@ -151,8 +146,7 @@ class Undeploy extends BaseCommand {
|
|
|
151
146
|
}
|
|
152
147
|
spinner.succeed(chalk.green(`Un-deploying actions for ${extName}`))
|
|
153
148
|
} catch (err) {
|
|
154
|
-
spinner.
|
|
155
|
-
throw err
|
|
149
|
+
spinner.warn(chalk.yellow(`Error when un-deploying actions for ${extName}: ${err.message}`))
|
|
156
150
|
}
|
|
157
151
|
} else {
|
|
158
152
|
this.log('no manifest file, skipping action undeploy')
|
|
@@ -168,8 +162,7 @@ class Undeploy extends BaseCommand {
|
|
|
168
162
|
|
|
169
163
|
spinner.succeed(chalk.green(`Un-Deploying web assets for ${extName}`))
|
|
170
164
|
} catch (err) {
|
|
171
|
-
spinner.
|
|
172
|
-
throw err
|
|
165
|
+
spinner.warn(chalk.yellow(`Error when un-deploying web assets for ${extName}: ${err.message}`))
|
|
173
166
|
}
|
|
174
167
|
} else {
|
|
175
168
|
this.log('no frontend, skipping frontend undeploy')
|
package/src/lib/defaults.js
CHANGED
|
@@ -41,5 +41,16 @@ module.exports = {
|
|
|
41
41
|
EXTENSIONS_CONFIG_KEY: 'extensions',
|
|
42
42
|
// Adding tracking file constants
|
|
43
43
|
LAST_BUILT_ACTIONS_FILENAME: 'last-built-actions.json',
|
|
44
|
-
LAST_DEPLOYED_ACTIONS_FILENAME: 'last-deployed-actions.json'
|
|
44
|
+
LAST_DEPLOYED_ACTIONS_FILENAME: 'last-deployed-actions.json',
|
|
45
|
+
// Database constants
|
|
46
|
+
DB_STATUS: {
|
|
47
|
+
PROVISIONED: 'PROVISIONED',
|
|
48
|
+
REQUESTED: 'REQUESTED',
|
|
49
|
+
PROCESSING: 'PROCESSING',
|
|
50
|
+
FAILED: 'FAILED',
|
|
51
|
+
REJECTED: 'REJECTED',
|
|
52
|
+
NOT_PROVISIONED: 'NOT_PROVISIONED',
|
|
53
|
+
DELETED: 'DELETED',
|
|
54
|
+
UNKNOWN: 'UNKNOWN'
|
|
55
|
+
}
|
|
45
56
|
}
|