@adobe/aio-cli-plugin-app 14.7.0 → 14.8.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/README.md +42 -42
- package/oclif.manifest.json +183 -146
- package/package.json +6 -11
- package/src/BaseCommand.js +25 -0
- package/src/commands/app/deploy.js +2 -0
- package/src/commands/app/init.js +98 -8
- package/src/commands/app/install.js +0 -1
- package/src/commands/app/pack.js +0 -1
- package/src/lib/cleanup.js +2 -2
- package/src/lib/install-helper.js +0 -1
- package/src/lib/run-dev.js +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adobe/aio-cli-plugin-app",
|
|
3
3
|
"description": "Create, Build and Deploy Adobe I/O Applications",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.8.0",
|
|
5
5
|
"author": "Adobe Inc.",
|
|
6
6
|
"bugs": "https://github.com/adobe/aio-cli-plugin-app/issues",
|
|
7
7
|
"dependencies": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"@adobe/generator-aio-app": "^9",
|
|
20
20
|
"@adobe/generator-app-common-lib": "^3",
|
|
21
21
|
"@adobe/inquirer-table-checkbox": "^2",
|
|
22
|
-
"@oclif/core": "^
|
|
22
|
+
"@oclif/core": "^4.9.0",
|
|
23
23
|
"@octokit/rest": "^19.0.11",
|
|
24
24
|
"@parcel/core": "^2.7.0",
|
|
25
25
|
"@parcel/reporter-cli": "^2.7.0",
|
|
@@ -51,26 +51,21 @@
|
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@adobe/aio-lib-test-proxy": "^2",
|
|
54
|
-
"@adobe/eslint-config-aio-lib-config": "^
|
|
54
|
+
"@adobe/eslint-config-aio-lib-config": "^5.0.0",
|
|
55
55
|
"@types/jest": "^29",
|
|
56
56
|
"babel-runtime": "^6.26.0",
|
|
57
57
|
"core-js": "^3",
|
|
58
58
|
"eol": "^0.9.1",
|
|
59
|
-
"eslint": "^
|
|
60
|
-
"eslint-config-standard": "^17.1.0",
|
|
61
|
-
"eslint-plugin-import": "^2.31.0",
|
|
62
|
-
"eslint-plugin-jest": "^27.9.0",
|
|
59
|
+
"eslint": "^9",
|
|
63
60
|
"eslint-plugin-jsdoc": "^48.11.0",
|
|
64
|
-
"
|
|
65
|
-
"eslint-plugin-node": "^11.1.0",
|
|
66
|
-
"eslint-plugin-promise": "^6.6.0",
|
|
61
|
+
"neostandard": "^0",
|
|
67
62
|
"jest": "^29.5.0",
|
|
68
63
|
"nock": "^13.2.9",
|
|
69
64
|
"oclif": "^4.17.13",
|
|
70
65
|
"stdout-stderr": "^0.1.9"
|
|
71
66
|
},
|
|
72
67
|
"engines": {
|
|
73
|
-
"node": ">=
|
|
68
|
+
"node": ">=20"
|
|
74
69
|
},
|
|
75
70
|
"files": [
|
|
76
71
|
"bin/run",
|
package/src/BaseCommand.js
CHANGED
|
@@ -40,6 +40,31 @@ class BaseCommand extends Command {
|
|
|
40
40
|
|
|
41
41
|
async init () {
|
|
42
42
|
await super.init()
|
|
43
|
+
// Normalize hooks from plugins loaded by oclif v2 into this v4 Config.
|
|
44
|
+
// oclif v2 stores hooks as string arrays; v4 expects {identifier, target} objects.
|
|
45
|
+
// Only mutate when string hooks are present; guard against frozen plugin references.
|
|
46
|
+
const pluginList = typeof this.config.getPluginsList === 'function'
|
|
47
|
+
? this.config.getPluginsList()
|
|
48
|
+
: [...(this.config.plugins?.values() ?? [])]
|
|
49
|
+
for (const plugin of pluginList) {
|
|
50
|
+
if (!plugin.hooks) {
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
for (const [event, hooks] of Object.entries(plugin.hooks)) {
|
|
54
|
+
const hooksArr = Array.isArray(hooks) ? hooks : [hooks]
|
|
55
|
+
if (!hooksArr.some(h => typeof h === 'string')) {
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
plugin.hooks[event] = hooksArr.map(h =>
|
|
60
|
+
typeof h === 'string' ? { identifier: 'default', target: h } : h
|
|
61
|
+
)
|
|
62
|
+
} catch {
|
|
63
|
+
// plugin.hooks is frozen or sealed; skip normalization for this event
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
43
68
|
// setup a prompt that outputs to stderr
|
|
44
69
|
this.prompt = inquirer.createPromptModule({ output: process.stderr })
|
|
45
70
|
|
|
@@ -30,6 +30,7 @@ const LogForwarding = require('../../lib/log-forwarding')
|
|
|
30
30
|
const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require('../../lib/audit-logger')
|
|
31
31
|
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')
|
|
32
32
|
const logActions = require('../../lib/log-actions')
|
|
33
|
+
const aioConfigLoader = require('@adobe/aio-lib-core-config')
|
|
33
34
|
|
|
34
35
|
const PRE_DEPLOY_EVENT_REG = 'pre-deploy-event-reg'
|
|
35
36
|
const POST_DEPLOY_EVENT_REG = 'post-deploy-event-reg'
|
|
@@ -230,6 +231,7 @@ class Deploy extends BuildCommand {
|
|
|
230
231
|
// output should be "Error : <plugin-name> : <error-message>\n" for each failure
|
|
231
232
|
this.error(hookResults.failures.map(f => `${f.plugin.name} : ${f.error.message}`).join('\nError: '), { exit: 1 })
|
|
232
233
|
}
|
|
234
|
+
aioConfigLoader.reload()
|
|
233
235
|
deployedRuntimeEntities = await rtLib.deployActions(config, { filterEntities, useForce: flags['force-deploy'] }, onProgress)
|
|
234
236
|
}
|
|
235
237
|
|
package/src/commands/app/init.js
CHANGED
|
@@ -192,6 +192,9 @@ class InitCommand extends TemplatesCommand {
|
|
|
192
192
|
this.error(`Extension(s) '${notFound.join(', ')}' not found in the Template Registry.`)
|
|
193
193
|
}
|
|
194
194
|
return extensionTemplates.map(t => t.name)
|
|
195
|
+
} else if (flags.yes) {
|
|
196
|
+
// with --yes and no explicit template, default to standalone app (no prompts)
|
|
197
|
+
return []
|
|
195
198
|
} else if (!flags['standalone-app']) {
|
|
196
199
|
const noLogin = flags.import || !flags.login
|
|
197
200
|
let [searchCriteria, orderByCriteria] = await this.getSearchCriteria(orgSupportedServices)
|
|
@@ -210,9 +213,12 @@ class InitCommand extends TemplatesCommand {
|
|
|
210
213
|
}
|
|
211
214
|
}
|
|
212
215
|
|
|
213
|
-
async ensureDevTermAccepted (consoleCLI, orgId) {
|
|
216
|
+
async ensureDevTermAccepted (consoleCLI, orgId, skipPrompts = false) {
|
|
214
217
|
const isTermAccepted = await consoleCLI.checkDevTermsForOrg(orgId)
|
|
215
218
|
if (!isTermAccepted) {
|
|
219
|
+
if (skipPrompts) {
|
|
220
|
+
this.error('Developer Terms of Service have not been accepted for this organization. Please run `aio app init` without --yes to accept the terms first.')
|
|
221
|
+
}
|
|
216
222
|
const terms = await consoleCLI.getDevTermsForOrg()
|
|
217
223
|
const confirmDevTerms = await consoleCLI.prompt.promptConfirm(`${terms.text}
|
|
218
224
|
\nYou have not accepted the Developer Terms of Service. Go to ${hyperlinker('https://www.adobe.com/go/developer-terms', 'https://www.adobe.com/go/developer-terms')} to view the terms. Do you accept the terms? (y/n):`)
|
|
@@ -294,26 +300,110 @@ class InitCommand extends TemplatesCommand {
|
|
|
294
300
|
|
|
295
301
|
async selectConsoleOrg (consoleCLI, flags) {
|
|
296
302
|
const organizations = await consoleCLI.getOrganizations()
|
|
297
|
-
|
|
298
|
-
|
|
303
|
+
if (!organizations || organizations.length === 0) {
|
|
304
|
+
this.error('No organizations found for the logged-in user')
|
|
305
|
+
}
|
|
306
|
+
// If --org was supplied, validate it against the full list regardless of how many orgs
|
|
307
|
+
// exist. This prevents silent mismatches when there is only one org but the caller
|
|
308
|
+
// passed a wrong id or code.
|
|
309
|
+
let selectedOrg
|
|
310
|
+
if (flags.org) {
|
|
311
|
+
selectedOrg = organizations.find(o => o.id === flags.org || o.code === flags.org)
|
|
312
|
+
if (!selectedOrg) {
|
|
313
|
+
this.error(`--org ${flags.org} not found`)
|
|
314
|
+
}
|
|
315
|
+
} else if (organizations.length > 1 && !flags.yes) {
|
|
316
|
+
// Multiple orgs and no --org: prompt interactively (only when not in --yes mode).
|
|
317
|
+
selectedOrg = await consoleCLI.promptForSelectOrganization(organizations, {})
|
|
318
|
+
} else {
|
|
319
|
+
// Single org, or --yes with no --org: auto-select the first (and likely only) org.
|
|
320
|
+
selectedOrg = organizations[0]
|
|
321
|
+
this.log(`Auto-selecting organization: '${selectedOrg.name || selectedOrg.id}'`)
|
|
322
|
+
}
|
|
323
|
+
await this.ensureDevTermAccepted(consoleCLI, selectedOrg.id, flags.yes)
|
|
299
324
|
return selectedOrg
|
|
300
325
|
}
|
|
301
326
|
|
|
302
327
|
async selectOrCreateConsoleProject (consoleCLI, org, flags) {
|
|
328
|
+
// Fetch all projects in the org upfront. This list is used both for uniqueness
|
|
329
|
+
// checks (--yes path) and for the interactive selection prompt (non-yes path).
|
|
303
330
|
const projects = await consoleCLI.getProjects(org.id)
|
|
331
|
+
|
|
332
|
+
if (flags.yes) {
|
|
333
|
+
// Non-interactive path: no prompts are shown. Behavior depends on whether
|
|
334
|
+
// --project was explicitly supplied by the caller.
|
|
335
|
+
|
|
336
|
+
if (flags.project) {
|
|
337
|
+
// --project was supplied. Try to find it in the existing list by id or name.
|
|
338
|
+
// Matching by id supports callers who pass a project id rather than a name.
|
|
339
|
+
const existing = projects.find(p => p.id === flags.project || p.name === flags.project)
|
|
340
|
+
if (existing) {
|
|
341
|
+
// Project already exists — return it as-is. isNew is intentionally NOT set
|
|
342
|
+
// so downstream code knows not to treat this as a newly created project.
|
|
343
|
+
this.log(`Using existing project: '${existing.name}'`)
|
|
344
|
+
return existing
|
|
345
|
+
}
|
|
346
|
+
// Project does not exist — create it using the caller-supplied name directly.
|
|
347
|
+
// title and description are derived from the name since no other info is available.
|
|
348
|
+
this.log(`Project '${flags.project}' not found, creating it`)
|
|
349
|
+
const project = await consoleCLI.createProject(org.id, {
|
|
350
|
+
name: flags.project,
|
|
351
|
+
title: flags.project,
|
|
352
|
+
description: `App Builder Project ${flags.project} - generated by an agent`
|
|
353
|
+
})
|
|
354
|
+
project.isNew = true
|
|
355
|
+
return project
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// No --project supplied. Auto-generate a unique name of the form "App{N}"
|
|
359
|
+
// where N is the lowest positive integer not already used by an existing project.
|
|
360
|
+
// This mimics sequential behaviour (App1, App2, ...) and fills
|
|
361
|
+
// gaps left by deleted projects (e.g. if App2 was deleted, it is reused
|
|
362
|
+
// before App4 is attempted).
|
|
363
|
+
const existingNames = new Set(projects.map(p => p.name))
|
|
364
|
+
const MAX_SUFFIX = 10000
|
|
365
|
+
let suffix = 1
|
|
366
|
+
while (existingNames.has(`App${suffix}`)) {
|
|
367
|
+
suffix++
|
|
368
|
+
if (suffix > MAX_SUFFIX) {
|
|
369
|
+
this.error(`Could not find an available generated App name after ${MAX_SUFFIX} attempts`)
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const generatedName = `App${suffix}`
|
|
374
|
+
const generatedTitle = `App Builder Project ${suffix}`
|
|
375
|
+
const generatedDescription = `App Builder Project ${suffix} - generated`
|
|
376
|
+
|
|
377
|
+
this.log(`Auto-generating project name: '${generatedName}'`)
|
|
378
|
+
const project = await consoleCLI.createProject(org.id, {
|
|
379
|
+
name: generatedName,
|
|
380
|
+
title: generatedTitle,
|
|
381
|
+
description: generatedDescription
|
|
382
|
+
})
|
|
383
|
+
project.isNew = true
|
|
384
|
+
return project
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Interactive path: prompt the user to select an existing project or create a new one.
|
|
388
|
+
// If --project was supplied it is used to pre-populate the selection (by id or name)
|
|
389
|
+
// but the prompt is still shown so the user can confirm or change it.
|
|
304
390
|
let project = await consoleCLI.promptForSelectProject(
|
|
305
391
|
projects,
|
|
306
392
|
{ projectId: flags.project, projectName: flags.project },
|
|
307
393
|
{ allowCreate: true }
|
|
308
394
|
)
|
|
309
395
|
if (!project) {
|
|
396
|
+
// promptForSelectProject returns null when the user selects "Create new project" or
|
|
397
|
+
// escapes the prompt. If --project was explicitly provided but not found/selected,
|
|
398
|
+
// always error — never silently create a different project.
|
|
310
399
|
if (flags.project) {
|
|
311
400
|
this.error(`--project ${flags.project} not found`)
|
|
401
|
+
} else {
|
|
402
|
+
// User chose to create a new project — collect details interactively and create it.
|
|
403
|
+
const projectDetails = await consoleCLI.promptForCreateProjectDetails()
|
|
404
|
+
project = await consoleCLI.createProject(org.id, projectDetails)
|
|
405
|
+
project.isNew = true
|
|
312
406
|
}
|
|
313
|
-
// user has escaped project selection prompt, let's create a new one
|
|
314
|
-
const projectDetails = await consoleCLI.promptForCreateProjectDetails()
|
|
315
|
-
project = await consoleCLI.createProject(org.id, projectDetails)
|
|
316
|
-
project.isNew = true
|
|
317
407
|
}
|
|
318
408
|
return project
|
|
319
409
|
}
|
|
@@ -324,7 +414,7 @@ class InitCommand extends TemplatesCommand {
|
|
|
324
414
|
const workspaces = await consoleCLI.getWorkspaces(org.id, project.id)
|
|
325
415
|
let workspace = workspaces.find(w => w.name.toLowerCase() === workspaceName.toLowerCase())
|
|
326
416
|
if (!workspace) {
|
|
327
|
-
if (flags['confirm-new-workspace']) {
|
|
417
|
+
if (!flags.yes && flags['confirm-new-workspace']) {
|
|
328
418
|
const shouldNewWorkspace = await consoleCLI.prompt.promptConfirm(`Workspace '${workspaceName}' does not exist \n > Do you wish to create a new workspace?`)
|
|
329
419
|
if (!shouldNewWorkspace) {
|
|
330
420
|
this.error(`Workspace '${workspaceName}' does not exist and creation aborted`)
|
|
@@ -22,7 +22,6 @@ const jsYaml = require('js-yaml')
|
|
|
22
22
|
const { USER_CONFIG_FILE, DEPLOY_CONFIG_FILE, PACKAGE_LOCK_FILE } = require('../../lib/defaults')
|
|
23
23
|
const ora = require('ora')
|
|
24
24
|
|
|
25
|
-
// eslint-disable-next-line node/no-missing-require
|
|
26
25
|
const libConfig = require('@adobe/aio-cli-lib-app-config')
|
|
27
26
|
|
|
28
27
|
class InstallCommand extends BaseCommand {
|
package/src/commands/app/pack.js
CHANGED
|
@@ -22,7 +22,6 @@ const { getObjectValue } = require('../../lib/app-helper')
|
|
|
22
22
|
const ora = require('ora')
|
|
23
23
|
const junk = require('junk')
|
|
24
24
|
|
|
25
|
-
// eslint-disable-next-line node/no-missing-require
|
|
26
25
|
const libConfig = require('@adobe/aio-cli-lib-app-config')
|
|
27
26
|
|
|
28
27
|
const DIST_FOLDER = 'dist'
|
package/src/lib/cleanup.js
CHANGED
|
@@ -40,11 +40,11 @@ class Cleanup {
|
|
|
40
40
|
try {
|
|
41
41
|
await this.run()
|
|
42
42
|
aioLogger.info('exiting!')
|
|
43
|
-
process.exit(0)
|
|
43
|
+
process.exit(0)
|
|
44
44
|
} catch (e) {
|
|
45
45
|
aioLogger.error('unexpected error while cleaning up!')
|
|
46
46
|
aioLogger.error(e)
|
|
47
|
-
process.exit(1)
|
|
47
|
+
process.exit(1)
|
|
48
48
|
}
|
|
49
49
|
})
|
|
50
50
|
}
|
|
@@ -20,7 +20,6 @@ const ajvAddFormats = require('ajv-formats')
|
|
|
20
20
|
* @returns {object} with keys valid (boolean) and errors (object). errors is null if no errors
|
|
21
21
|
*/
|
|
22
22
|
function validateJsonWithSchema (fileJson, schemaName) {
|
|
23
|
-
/* eslint-disable-next-line node/no-unpublished-require */
|
|
24
23
|
const schemas = require('../../schema/index')
|
|
25
24
|
const ajv = new Ajv({
|
|
26
25
|
allErrors: true,
|
package/src/lib/run-dev.js
CHANGED
|
@@ -9,7 +9,6 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA
|
|
|
9
9
|
OF ANY KIND, either express or implied. See the License for the specific language
|
|
10
10
|
governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
|
-
/* eslint-disable no-template-curly-in-string */
|
|
13
12
|
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:runDev', { provider: 'debug' })
|
|
14
13
|
const rtLib = require('@adobe/aio-lib-runtime')
|
|
15
14
|
const rtLibUtils = rtLib.utils
|