@adobe/aio-cli-plugin-app 9.2.0 → 10.0.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.
@@ -0,0 +1,256 @@
1
+ /*
2
+ Copyright 2021 Adobe. All rights reserved.
3
+ This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License. You may obtain a copy
5
+ of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ Unless required by applicable law or agreed to in writing, software distributed under
7
+ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
8
+ OF ANY KIND, either express or implied. See the License for the specific language
9
+ governing permissions and limitations under the License.
10
+ */
11
+
12
+ const AddCommand = require('./AddCommand')
13
+ const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:TemplatesCommand', { provider: 'debug' })
14
+ const inquirerTableCheckbox = require('@adobe/inquirer-table-checkbox')
15
+ const inquirer = require('inquirer')
16
+ const TemplateRegistryAPI = require('@adobe/aio-lib-templates')
17
+ const hyperlinker = require('hyperlinker')
18
+ const ora = require('ora')
19
+ const terminalSize = require('term-size')
20
+
21
+ class TemplatesCommand extends AddCommand {
22
+ /**
23
+ * Gets a list of templates from the Template Registry API using the criteria provided.
24
+ *
25
+ * @param {object} searchCriteria the Template Registry API search criteria
26
+ * @param {object} orderByCriteria the Template Registry API orderBy criteria
27
+ * @param {object} [templateRegistryConfig={}] the optional Template Registry API config
28
+ * @returns {Array<object>} list of templates
29
+ */
30
+ async getTemplates (searchCriteria, orderByCriteria, templateRegistryConfig = {}) {
31
+ const templateRegistryClient = TemplateRegistryAPI.init(templateRegistryConfig)
32
+ const templateList = []
33
+
34
+ const templatesIterator = templateRegistryClient.getTemplates(searchCriteria, orderByCriteria)
35
+
36
+ for await (const templates of templatesIterator) {
37
+ for (const template of templates) {
38
+ templateList.push(template)
39
+ }
40
+ }
41
+ aioLogger.debug('template list', JSON.stringify(templateList, null, 2))
42
+
43
+ return templateList
44
+ }
45
+
46
+ /**
47
+ * Select templates from the Template Registry API, via a cli table.
48
+ *
49
+ * @param {object} searchCriteria the Template Registry API search criteria
50
+ * @param {object} orderByCriteria the Template Registry API orderBy criteria
51
+ * @param {Array<object>} orgSupportedServices Services supported by the org
52
+ * @param {object} [templateRegistryConfig={}] the optional Template Registry API config
53
+ * @returns {Array<string>} an array of selected template module name(s)
54
+ */
55
+ async selectTemplates (searchCriteria, orderByCriteria, orgSupportedServices = undefined, templateRegistryConfig = {}) {
56
+ aioLogger.debug('searchCriteria', JSON.stringify(searchCriteria, null, 2))
57
+ aioLogger.debug('orderByCriteria', JSON.stringify(orderByCriteria, null, 2))
58
+ let supportedServiceCodes
59
+ if (orgSupportedServices) {
60
+ supportedServiceCodes = new Set(orgSupportedServices.map(s => s.code))
61
+ }
62
+
63
+ const spinner = ora()
64
+ spinner.start('Getting available templates')
65
+
66
+ const templateList = await this.getTemplates(searchCriteria, orderByCriteria, templateRegistryConfig)
67
+ aioLogger.debug('templateList', JSON.stringify(templateList, null, 2))
68
+ spinner.succeed('Downloaded the list of templates')
69
+
70
+ if (templateList.length === 0) {
71
+ throw new Error('There are no templates that match the query for selection')
72
+ }
73
+
74
+ const { columns: terminalColumns } = terminalSize()
75
+
76
+ const colPadding = 3
77
+ const colWidths = [
78
+ Math.round(0.3 * terminalColumns) - colPadding,
79
+ Math.round(0.3 * terminalColumns) - colPadding,
80
+ Math.round(0.2 * terminalColumns) - colPadding,
81
+ Math.round(0.2 * terminalColumns) - colPadding]
82
+
83
+ const COLUMNS = {
84
+ COL_TEMPLATE: 'Template',
85
+ COL_DESCRIPTION: 'Description',
86
+ COL_EXTENSION_POINT: 'Extension Point',
87
+ COL_CATEGORIES: 'Categories'
88
+ }
89
+
90
+ const rows = templateList.map(template => {
91
+ const extensionPoint = template.extensions ? template.extensions.map(ext => ext.extensionPointId).join(',') : 'N/A'
92
+ const name = template.adobeRecommended ? `${template.name} *` : template.name
93
+ let disabled = false
94
+ if (template.apis && supportedServiceCodes) {
95
+ disabled = !template.apis.map(api => api.code).every(code => supportedServiceCodes.has(code))
96
+ }
97
+ return {
98
+ value: template.name,
99
+ disabled,
100
+ [COLUMNS.COL_TEMPLATE]: name,
101
+ [COLUMNS.COL_DESCRIPTION]: template.description,
102
+ [COLUMNS.COL_EXTENSION_POINT]: extensionPoint,
103
+ [COLUMNS.COL_CATEGORIES]: template?.categories?.join(', ')
104
+ }
105
+ })
106
+ const promptName = 'select template'
107
+
108
+ inquirer.registerPrompt('table', inquirerTableCheckbox)
109
+ const answers = await inquirer
110
+ .prompt([
111
+ {
112
+ type: 'table',
113
+ name: promptName,
114
+ bottomContent: `* = recommended by Adobe; to learn more about the templates, go to ${hyperlinker('https://adobe.ly/templates', 'https://adobe.ly/templates')}`,
115
+ message: 'Choose the template(s) to install:',
116
+ style: { head: [], border: [] },
117
+ wordWrap: true,
118
+ wrapOnWordBoundary: false,
119
+ colWidths,
120
+ columns: [
121
+ { name: COLUMNS.COL_TEMPLATE },
122
+ { name: COLUMNS.COL_DESCRIPTION, wrapOnWordBoundary: true },
123
+ { name: COLUMNS.COL_EXTENSION_POINT },
124
+ { name: COLUMNS.COL_CATEGORIES, wrapOnWordBoundary: false }
125
+ ],
126
+ rows
127
+ }
128
+ ])
129
+
130
+ return answers[promptName]
131
+ }
132
+
133
+ /**
134
+ * Install the templates.
135
+ *
136
+ * @param {object} templateData the template data
137
+ * @param {boolean} [templateData.useDefaultValues=false] use default values when installing the template
138
+ * @param {boolean} [templateData.installConfig=true] process the install.yml of the template
139
+ * @param {boolean} [templateData.installNpm=true] run npm install after installing the template
140
+ * @param {object} [templateData.templateOptions=null] set the template options for installation
141
+ * @param {Array} templateData.templates the list of templates to install
142
+ */
143
+ async installTemplates ({
144
+ useDefaultValues = false,
145
+ installConfig = true,
146
+ installNpm = true,
147
+ templateOptions = null,
148
+ templates = []
149
+ } = {}) {
150
+ const spinner = ora()
151
+
152
+ // install the templates in sequence
153
+ for (const template of templates) {
154
+ spinner.info(`Installing template ${template}`)
155
+ const installArgs = [template]
156
+ if (useDefaultValues) {
157
+ installArgs.push('--yes')
158
+ }
159
+ if (!installConfig) {
160
+ installArgs.push('--no-process-install-config')
161
+ }
162
+ if (!installNpm) {
163
+ installArgs.push('--no-install')
164
+ }
165
+
166
+ if (templateOptions) {
167
+ if (typeof templateOptions !== 'object' || Array.isArray(templateOptions)) { // must be a non-array object
168
+ aioLogger.debug('malformed templateOptions', templateOptions)
169
+ throw new Error('The templateOptions is not a JavaScript object.')
170
+ }
171
+ const jsonString = JSON.stringify(templateOptions)
172
+ installArgs.push(`--template-options=${Buffer.from(jsonString).toString('base64')}`)
173
+ }
174
+
175
+ await this.config.runCommand('templates:install', installArgs)
176
+ spinner.succeed(`Installed template ${template}`)
177
+ }
178
+ }
179
+
180
+ /** @private */
181
+ _uniqueArray (array) {
182
+ return Array.from(new Set(array))
183
+ }
184
+
185
+ /**
186
+ * Get templates by extension point ids.
187
+ *
188
+ * @param {Array<string>} extensionsToInstall an array of extension point ids to install.
189
+ * @param {object} [templateRegistryConfig={}] the optional Template Registry API config
190
+ * @returns {object} returns the result
191
+ */
192
+ async getTemplatesByExtensionPointIds (extensionsToInstall, templateRegistryConfig = {}) {
193
+ const orderByCriteria = {
194
+ [TemplateRegistryAPI.ORDER_BY_CRITERIA_PUBLISH_DATE]: TemplateRegistryAPI.ORDER_BY_CRITERIA_SORT_DESC
195
+ }
196
+
197
+ const searchCriteria = {
198
+ [TemplateRegistryAPI.SEARCH_CRITERIA_STATUSES]: TemplateRegistryAPI.TEMPLATE_STATUS_APPROVED,
199
+ [TemplateRegistryAPI.SEARCH_CRITERIA_EXTENSIONS]: extensionsToInstall
200
+ }
201
+
202
+ const templates = await this.getTemplates(searchCriteria, orderByCriteria, templateRegistryConfig)
203
+ aioLogger.debug('templateList', JSON.stringify(templates, null, 2))
204
+
205
+ // check whether we got all extensions
206
+ const found = this._uniqueArray(templates
207
+ .map(t => t.extensions.map(e => e.extensionPointId)) // array of array of extensionPointIds
208
+ .filter(ids => extensionsToInstall.some(item => ids.includes(item)))
209
+ .flat()
210
+ )
211
+
212
+ const notFound = this._uniqueArray(extensionsToInstall).filter(ext => !found.includes(ext))
213
+
214
+ return {
215
+ found,
216
+ notFound,
217
+ templates
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Install templates by extension point ids.
223
+ *
224
+ * @param {Array<string>} extensionsToInstall an array of extension point ids to install.
225
+ * @param {Array<string>} extensionsAlreadyImplemented an array of extension point ids that have already been implemented (to filter)
226
+ * @param {boolean} [useDefaultValues=false] use default values when installing the template
227
+ * @param {boolean} [installNpm=true] run npm install after installing the template
228
+ * @param {object} [templateRegistryConfig={}] the optional Template Registry API config
229
+ */
230
+ async installTemplatesByExtensionPointIds (extensionsToInstall, extensionsAlreadyImplemented, useDefaultValues = false, installNpm = true, templateRegistryConfig = {}) {
231
+ // no prompt
232
+ const alreadyThere = extensionsToInstall.filter(i => extensionsAlreadyImplemented.includes(i))
233
+ if (alreadyThere.length > 0) {
234
+ throw new Error(`'${alreadyThere.join(', ')}' extension(s) are already implemented in this project.`)
235
+ }
236
+
237
+ const { found, notFound, templates } = await this.getTemplatesByExtensionPointIds(extensionsToInstall, templateRegistryConfig)
238
+
239
+ if (notFound.length > 0) {
240
+ this.error(`Extension(s) '${notFound.join(', ')}' not found in the Template Registry.`)
241
+ }
242
+
243
+ this.log(`Extension(s) '${found.join(', ')}' found in the Template Registry. Installing...`)
244
+ await this.installTemplates({
245
+ useDefaultValues,
246
+ installNpm,
247
+ templates: templates.map(t => t.name)
248
+ })
249
+ }
250
+ }
251
+
252
+ TemplatesCommand.flags = {
253
+ ...AddCommand.flags
254
+ }
255
+
256
+ module.exports = TemplatesCommand
@@ -9,22 +9,19 @@ OF ANY KIND, either express or implied. See the License for the specific languag
9
9
  governing permissions and limitations under the License.
10
10
  */
11
11
 
12
- const AddCommand = require('../../../AddCommand')
13
- const yeoman = require('yeoman-environment')
12
+ const TemplatesCommand = require('../../../TemplatesCommand')
14
13
  const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:add:action', { provider: 'debug' })
15
14
  const { Flags } = require('@oclif/core')
16
- const ora = require('ora')
17
15
  const path = require('path')
18
- const generators = require('@adobe/generator-aio-app')
19
- const { servicesToGeneratorInput } = require('../../../lib/app-helper')
20
16
  const aioConfigLoader = require('@adobe/aio-lib-core-config')
17
+ const TemplateRegistryAPI = require('@adobe/aio-lib-templates')
18
+ const inquirer = require('inquirer')
21
19
 
22
- class AddActionCommand extends AddCommand {
20
+ class AddActionCommand extends TemplatesCommand {
23
21
  async run () {
24
22
  const { flags } = await this.parse(AddActionCommand)
25
23
 
26
24
  aioLogger.debug(`add actions with flags: ${JSON.stringify(flags)}`)
27
- const spinner = ora()
28
25
 
29
26
  // guaranteed to have at least one, otherwise would throw in config load or in matching the ext name
30
27
  const entries = Object.entries(this.getAppExtConfigs(flags))
@@ -35,33 +32,90 @@ class AddActionCommand extends AddCommand {
35
32
  const config = entries[0][1]
36
33
 
37
34
  const actionFolder = path.relative(config.root, config.actions.src)
38
-
39
35
  const configData = this.getRuntimeManifestConfigFile(configName)
40
36
 
41
- // NOTE: we could get fresh data from console if we know that user is logged in
42
- const workspaceServices =
43
- aioConfigLoader.get('services') || // legacy
44
- aioConfigLoader.get('project.workspace.details.services') ||
45
- []
46
- const supportedOrgServices = aioConfigLoader.get('project.org.details.services') || []
47
-
48
- const env = yeoman.createEnv()
49
- // by default yeoman runs the install, we control installation from the app plugin
50
- env.options = { skipInstall: true }
51
- const addActionGen = env.instantiate(generators['add-action'], {
52
- options: {
53
- 'skip-prompt': flags.yes,
54
- 'action-folder': actionFolder,
55
- 'config-path': configData.file,
56
- 'adobe-services': servicesToGeneratorInput(workspaceServices),
57
- 'supported-adobe-services': servicesToGeneratorInput(supportedOrgServices),
58
- 'full-key-to-manifest': configData.key
59
- // force: true
37
+ const projectOrgId = aioConfigLoader.get('project.org.id')
38
+ if (!projectOrgId) {
39
+ this.error(`Incomplete .aio configuration, please import a valid Adobe Developer Console configuration via \`${this.config.bin} app use\` first.`)
40
+ }
41
+
42
+ const consoleCLI = await this.getLibConsoleCLI()
43
+ const orgSupportedServices = await consoleCLI.getEnabledServicesForOrg(projectOrgId)
44
+
45
+ const templateOptions = {
46
+ 'skip-prompt': flags.yes,
47
+ 'action-folder': actionFolder,
48
+ 'config-path': configData.file,
49
+ 'full-key-to-manifest': configData.key
50
+ }
51
+
52
+ const [searchCriteria, orderByCriteria] = await this.getSearchCriteria(orgSupportedServices)
53
+ const templates = await this.selectTemplates(searchCriteria, orderByCriteria, orgSupportedServices)
54
+ if (templates.length === 0) {
55
+ this.error('No action templates were chosen to be installed.')
56
+ } else {
57
+ await this.installTemplates({
58
+ useDefaultValues: flags.yes,
59
+ installNpm: flags.install,
60
+ templateOptions,
61
+ templates
62
+ })
63
+ }
64
+ }
65
+
66
+ async getSearchCriteria (orgSupportedServices) {
67
+ const choices = [
68
+ {
69
+ name: 'All Action Templates',
70
+ value: 'allActionTemplates',
71
+ checked: true
60
72
  }
61
- })
62
- await env.runGenerator(addActionGen)
73
+ ]
74
+
75
+ if (orgSupportedServices) {
76
+ choices.push({
77
+ name: 'Only Action Templates Supported By My Org',
78
+ value: 'orgActionTemplates',
79
+ checked: false
80
+ })
81
+ }
82
+
83
+ const { components: selection } = await inquirer.prompt([
84
+ {
85
+ type: 'list',
86
+ name: 'components',
87
+ message: 'What action templates do you want to search for?',
88
+ loop: false,
89
+ choices
90
+ }
91
+ ])
92
+
93
+ const TEMPLATE_CATEGORIES = ['action', 'helper-template']
94
+ const searchCriteria = {
95
+ [TemplateRegistryAPI.SEARCH_CRITERIA_STATUSES]: TemplateRegistryAPI.TEMPLATE_STATUS_APPROVED,
96
+ [TemplateRegistryAPI.SEARCH_CRITERIA_CATEGORIES]: TEMPLATE_CATEGORIES,
97
+ [TemplateRegistryAPI.SEARCH_CRITERIA_EXTENSIONS]: TemplateRegistryAPI.SEARCH_CRITERIA_FILTER_NONE
98
+ }
99
+
100
+ switch (selection) {
101
+ case 'orgActionTemplates': {
102
+ const supportedServiceCodes = new Set(orgSupportedServices.map(s => `|${s.code}`)) // | symbol denotes an OR clause
103
+ searchCriteria[TemplateRegistryAPI.SEARCH_CRITERIA_APIS] = Array.from(supportedServiceCodes)
104
+ }
105
+ break
106
+ case 'allActionTemplates':
107
+ default:
108
+ break
109
+ }
110
+
111
+ const { name: selectionLabel } = choices.find(item => item.value === selection)
112
+
113
+ // an optional OrderBy Criteria object
114
+ const orderByCriteria = {
115
+ [TemplateRegistryAPI.ORDER_BY_CRITERIA_PUBLISH_DATE]: TemplateRegistryAPI.ORDER_BY_CRITERIA_SORT_DESC
116
+ }
63
117
 
64
- await this.runInstallPackages(flags, spinner)
118
+ return [searchCriteria, orderByCriteria, selection, selectionLabel]
65
119
  }
66
120
  }
67
121
 
@@ -80,7 +134,7 @@ AddActionCommand.flags = {
80
134
  multiple: false,
81
135
  parse: str => [str]
82
136
  }),
83
- ...AddCommand.flags
137
+ ...TemplatesCommand.flags
84
138
  }
85
139
 
86
140
  AddActionCommand.aliases = ['app:add:actions']
@@ -9,107 +9,57 @@ OF ANY KIND, either express or implied. See the License for the specific languag
9
9
  governing permissions and limitations under the License.
10
10
  */
11
11
 
12
- const AddCommand = require('../../../AddCommand')
13
- const yeoman = require('yeoman-environment')
12
+ const TemplatesCommand = require('../../../TemplatesCommand')
14
13
  const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:add:action', { provider: 'debug' })
15
14
  const { Flags } = require('@oclif/core')
16
- const ora = require('ora')
15
+ const TemplateRegistryAPI = require('@adobe/aio-lib-templates')
17
16
 
18
- const { atLeastOne } = require('../../../lib/app-helper')
19
- const aioConfigLoader = require('@adobe/aio-lib-core-config')
20
- const { implPromptChoices } = require('../../../lib/defaults')
21
- const chalk = require('chalk')
22
-
23
- class AddExtensionCommand extends AddCommand {
17
+ class AddExtensionCommand extends TemplatesCommand {
24
18
  async run () {
25
19
  const { flags } = await this.parse(AddExtensionCommand)
26
20
 
27
21
  aioLogger.debug(`add extensions with flags: ${JSON.stringify(flags)}`)
28
- const spinner = ora()
29
22
 
30
23
  if (flags.yes && !flags.extension) {
31
24
  this.error('--extension= must also be provided when using --yes')
32
25
  }
33
26
 
34
27
  const fullConfig = this.getFullConfig({ allowNoImpl: true })
35
- const implementationsToAdd = await this.selectImplementations(flags, fullConfig)
36
-
37
- await this.runCodeGenerators(flags, implementationsToAdd)
38
-
39
- await this.runInstallPackages(flags, spinner)
28
+ const alreadyImplemented = fullConfig.implements
40
29
 
41
- // warn about services to add
42
- const workspaceServices =
43
- aioConfigLoader.get('services') || // legacy
44
- aioConfigLoader.get('project.workspace.details.services') ||
45
- []
46
-
47
- const supportedServiceCodesInWorkspace = new Set(workspaceServices.map(s => s.code))
48
- implementationsToAdd.forEach(i => {
49
- const missingServices = i.requiredServices.filter(s => !supportedServiceCodesInWorkspace.has(s))
50
- if (missingServices.length > 0) {
51
- this.warn(`Please add missing services '${missingServices}' required by '${i.name}'`)
52
- }
53
- })
30
+ if (flags.extension) {
31
+ await this.installTemplatesByExtensionPointIds(flags.extension, alreadyImplemented, flags.yes, flags.install)
32
+ } else {
33
+ await this.selectExtensionsToInstall(alreadyImplemented, flags.yes, flags.install)
34
+ }
54
35
  }
55
36
 
56
- async selectImplementations (flags, config) {
57
- const alreadyImplemented = config.implements
58
- const availableChoices = implPromptChoices
59
- const availableImplementations = availableChoices.map(i => i.value.name)
37
+ async selectExtensionsToInstall (alreadyImplemented, useDefaultValues, installNpm) {
38
+ const excludeExtensions = alreadyImplemented.map(e => `${TemplateRegistryAPI.SEARCH_CRITERIA_FILTER_NOT}${e}`)
60
39
 
61
- const possibleChoices = availableChoices.filter(i => !alreadyImplemented.includes(i.value.name))
62
- if (possibleChoices.length <= 0) {
63
- throw new Error('All available extensions are already implemented in this project.')
40
+ const orderByCriteria = {
41
+ [TemplateRegistryAPI.ORDER_BY_CRITERIA_PUBLISH_DATE]: TemplateRegistryAPI.ORDER_BY_CRITERIA_SORT_DESC
64
42
  }
65
43
 
66
- if (flags.extension) {
67
- // no prompt
68
- const alreadyThere = flags.extension.filter(i => alreadyImplemented.includes(i))
69
- if (alreadyThere.length > 0) {
70
- throw new Error(`'${alreadyThere}' is/are already implemented by this project`)
71
- }
72
- const invalid = flags.extension.filter(i => !availableImplementations.includes(i))
73
- if (invalid.length > 0) {
74
- throw new Error(`Invalid extension(s) '${invalid}', available implementations are '${availableImplementations}'`)
75
- }
76
-
77
- return flags.extension.map(i => possibleChoices.find(c => c.value.name === i).value)
44
+ const searchCriteria = {
45
+ [TemplateRegistryAPI.SEARCH_CRITERIA_STATUSES]: TemplateRegistryAPI.TEMPLATE_STATUS_APPROVED,
46
+ [TemplateRegistryAPI.SEARCH_CRITERIA_EXTENSIONS]: excludeExtensions
78
47
  }
79
48
 
80
- // prompt
81
- const answers = await this.prompt([{
82
- type: 'checkbox',
83
- name: 'res',
84
- message: 'Which new implementation(s) do you wish to add to the project ?',
85
- choices: possibleChoices,
86
- validate: atLeastOne
87
- }])
88
-
89
- return answers.res
90
- }
91
-
92
- async runCodeGenerators (flags, implementations) {
93
- const env = yeoman.createEnv()
94
- // by default yeoman runs the install, we control installation from the app plugin
95
- env.options = { skipInstall: true }
96
- for (let i = 0; i < implementations.length; ++i) {
97
- const implementation = implementations[i]
98
- const gen = env.instantiate(implementation.generator,
99
- {
100
- options: {
101
- 'skip-prompt': flags.yes,
102
- // no yeoman overwrite prompts
103
- force: true
104
- }
105
- })
106
- this.log(chalk.blue(chalk.bold(`Running generator for ${implementation.name}`)))
107
- await env.runGenerator(gen)
49
+ const templates = await this.selectTemplates(searchCriteria, orderByCriteria)
50
+ if (templates.length === 0) {
51
+ this.error('No extensions were chosen to be installed.')
52
+ } else {
53
+ await this.installTemplates({
54
+ useDefaultValues,
55
+ installNpm,
56
+ templates
57
+ })
108
58
  }
109
59
  }
110
60
  }
111
61
 
112
- AddExtensionCommand.description = `Add new extensions or a standalone application to the project
62
+ AddExtensionCommand.description = `Add new extensions to the project
113
63
  `
114
64
  AddExtensionCommand.flags = {
115
65
  yes: Flags.boolean({
@@ -122,7 +72,7 @@ AddExtensionCommand.flags = {
122
72
  char: 'e',
123
73
  multiple: true
124
74
  }),
125
- ...AddCommand.flags
75
+ ...TemplatesCommand.flags
126
76
  }
127
77
 
128
78
  AddExtensionCommand.aliases = ['app:add:ext', 'app:add:extensions']
@@ -37,7 +37,7 @@ class AddServiceCommand extends BaseCommand {
37
37
  // load console configuration from .aio and .env files
38
38
  const projectConfig = config.get('project')
39
39
  if (!projectConfig) {
40
- this.error('Incomplete .aio configuration, please import a valid Adobe Developer Console configuration via `aio app use` first.')
40
+ this.error(`Incomplete .aio configuration, please import a valid Adobe Developer Console configuration via \`${this.config.bin} app use\` first.`)
41
41
  }
42
42
  const orgId = projectConfig.org.id
43
43
  const project = { name: projectConfig.name, id: projectConfig.id }
@@ -9,19 +9,14 @@ OF ANY KIND, either express or implied. See the License for the specific languag
9
9
  governing permissions and limitations under the License.
10
10
  */
11
11
 
12
- const AddCommand = require('../../../AddCommand')
13
- const yeoman = require('yeoman-environment')
12
+ const TemplatesCommand = require('../../../TemplatesCommand')
14
13
  const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:add:web-assets', { provider: 'debug' })
15
14
  const { Flags } = require('@oclif/core')
16
- const ora = require('ora')
17
- const generators = require('@adobe/generator-aio-app')
18
- const aioConfigLoader = require('@adobe/aio-lib-core-config')
19
- const { servicesToGeneratorInput } = require('../../../lib/app-helper')
15
+ const TemplateRegistryAPI = require('@adobe/aio-lib-templates')
20
16
 
21
- class AddWebAssetsCommand extends AddCommand {
17
+ class AddWebAssetsCommand extends TemplatesCommand {
22
18
  async run () {
23
19
  const { flags } = await this.parse(AddWebAssetsCommand)
24
- const spinner = ora()
25
20
  aioLogger.debug(`add web-assets with flags: ${JSON.stringify(flags)}`)
26
21
 
27
22
  const projectName = this.getFullConfig().packagejson.name
@@ -33,26 +28,32 @@ class AddWebAssetsCommand extends AddCommand {
33
28
  const config = entries[0][1]
34
29
  const webSrcFolder = config.web.src
35
30
 
36
- const workspaceServices =
37
- aioConfigLoader.get('services') || // legacy
38
- aioConfigLoader.get('project.workspace.details.services') ||
39
- []
40
-
41
- const env = yeoman.createEnv()
42
- // by default yeoman runs the install, we control installation from the app plugin
43
- env.options = { skipInstall: true }
44
- const gen = env.instantiate(generators['add-web-assets'], {
45
- options: {
46
- 'skip-prompt': flags.yes,
47
- 'project-name': projectName,
48
- 'web-src-folder': webSrcFolder,
49
- 'adobe-services': servicesToGeneratorInput(workspaceServices)
50
- // force: true
51
- }
52
- })
53
- await env.runGenerator(gen)
31
+ const templateOptions = {
32
+ 'skip-prompt': flags.yes,
33
+ 'project-name': projectName,
34
+ 'web-src-folder': webSrcFolder
35
+ }
54
36
 
55
- await this.runInstallPackages(flags, spinner)
37
+ const TEMPLATE_CATEGORIES = ['ui', 'helper-template']
38
+ const searchCriteria = {
39
+ [TemplateRegistryAPI.SEARCH_CRITERIA_STATUSES]: TemplateRegistryAPI.TEMPLATE_STATUS_APPROVED,
40
+ [TemplateRegistryAPI.SEARCH_CRITERIA_CATEGORIES]: TEMPLATE_CATEGORIES,
41
+ [TemplateRegistryAPI.SEARCH_CRITERIA_EXTENSIONS]: TemplateRegistryAPI.SEARCH_CRITERIA_FILTER_NONE
42
+ }
43
+ const orderByCriteria = {
44
+ [TemplateRegistryAPI.ORDER_BY_CRITERIA_PUBLISH_DATE]: TemplateRegistryAPI.ORDER_BY_CRITERIA_SORT_DESC
45
+ }
46
+ const templates = await this.selectTemplates(searchCriteria, orderByCriteria)
47
+ if (templates.length === 0) {
48
+ this.error('No web-asset templates were chosen to be installed.')
49
+ } else {
50
+ await this.installTemplates({
51
+ useDefaultValues: flags.yes,
52
+ installNpm: flags.install,
53
+ templateOptions,
54
+ templates
55
+ })
56
+ }
56
57
  }
57
58
  }
58
59
 
@@ -71,7 +72,7 @@ AddWebAssetsCommand.flags = {
71
72
  multiple: false,
72
73
  parse: str => [str]
73
74
  }),
74
- ...AddCommand.flags
75
+ ...TemplatesCommand.flags
75
76
  }
76
77
 
77
78
  AddWebAssetsCommand.args = []
@@ -26,8 +26,7 @@ class Build extends BaseCommand {
26
26
  // cli input
27
27
  const { flags } = await this.parse(Build)
28
28
  // flags
29
- flags['web-assets'] = flags['web-assets'] && !flags['skip-static'] && !flags['skip-web-assets'] && !flags.action
30
- flags.actions = flags.actions && !flags['skip-actions']
29
+ flags['web-assets'] = flags['web-assets'] && !flags.action
31
30
 
32
31
  const buildConfigs = this.getAppExtConfigs(flags)
33
32
 
@@ -144,15 +143,6 @@ This will always force a rebuild unless --no-force-build is set.
144
143
 
145
144
  Build.flags = {
146
145
  ...BaseCommand.flags,
147
- 'skip-static': Flags.boolean({
148
- description: '[deprecated] Please use --no-web-assets'
149
- }),
150
- 'skip-web-assets': Flags.boolean({
151
- description: '[deprecated] Please use --no-web-assets'
152
- }),
153
- 'skip-actions': Flags.boolean({
154
- description: '[deprecated] Please use --no-actions'
155
- }),
156
146
  actions: Flags.boolean({
157
147
  description: '[default: true] Build actions if any',
158
148
  default: true,