From 558f848e2aec9c4905576b8fa987f5b5ca5fb8c0 Mon Sep 17 00:00:00 2001 From: Stephen Rugh Date: Tue, 4 Feb 2025 15:17:37 -0600 Subject: [PATCH 1/7] adds mesh retry async using child process. also adds prod ims org compatibility and instructions for setting up cli Signed-off-by: Stephen Rugh --- src/commands/commerce/init.js | 28 ++++++++++++++++++++++++---- src/commands/commerce/mesh-verify.js | 27 +++++++++++++++++++++++++++ src/commands/commerce/test.js | 28 ++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 src/commands/commerce/mesh-verify.js diff --git a/src/commands/commerce/init.js b/src/commands/commerce/init.js index 5faeef3..d84c022 100644 --- a/src/commands/commerce/init.js +++ b/src/commands/commerce/init.js @@ -17,7 +17,11 @@ import { promptConfirm } from '../../utils/prompt.js' import config from '@adobe/aio-lib-core-config' import { createRepo, modifyFstab, modifySidekickConfig } from '../../utils/github.js' import { initialization } from '../../utils/initialization.js' -import { createMesh, checkAndRetryMeshUpdate, getMeshDetailsPage, confirmAPIMeshCreation } from '../../utils/mesh.js' +import { createMesh, getMeshDetailsPage, confirmAPIMeshCreation } from '../../utils/mesh.js' +import { spawn } from 'child_process' +import { openSync } from 'fs' +import Logger from '@adobe/aio-lib-core-logging' +const aioLogger = Logger('commerce:init.js') const reset = '\x1b[0m' const boldWhite = '\x1b[1m\x1b[37m' @@ -81,10 +85,26 @@ export class InitCommand extends Command { console.log(`${boldWhite}Run locally:${reset} "aio commerce:dev"`) console.log('For next steps, including how to customize your storefront and make it your own, check out our docs:\nhttps://experienceleague.adobe.com/developer/commerce/storefront/') - // if we created a mesh, wait for verification to complete before exiting - // TODO: Replace with detached childProcess. if (shouldCreateMesh) { - await checkAndRetryMeshUpdate(runAIOCommand) + // Spawn detached child process to verify mesh in the background, without disrupting user's CLI session. + try { + const out = openSync('./mesh-verify.log', 'w') + const err = openSync('./mesh-verify.log', 'a') + + const childProcess = spawn( + 'aio', + ['commerce:mesh-verify'], + { + detached: true, + stdio: ['ignore', out, err] + } + ) + // Detach from the parent process + childProcess.unref() + } catch (error) { + aioLogger.debug(error) + console.log('❌ Unable to verify mesh provisioning. Please try again with "aio commerce:mesh-verify"') + } } // cleanup diff --git a/src/commands/commerce/mesh-verify.js b/src/commands/commerce/mesh-verify.js new file mode 100644 index 0000000..23f2d42 --- /dev/null +++ b/src/commands/commerce/mesh-verify.js @@ -0,0 +1,27 @@ +/* +Copyright 2024 Adobe. All rights reserved. +This file is licensed to you under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. You may obtain a copy +of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under +the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ +import { Command, Help } from '@oclif/core' +import { checkAndRetryMeshUpdate } from '../../utils/mesh.js' + +const MESH_RETRIES = 2 +const MESH_RETRY_INTERVAL = 60000 + +export class MeshVerify extends Command { + async run () { + const runAIOCommand = async (command, args) => { + return await this.config.runCommand(command, args) + } + await checkAndRetryMeshUpdate(runAIOCommand, MESH_RETRIES, MESH_RETRY_INTERVAL) + } +} + +MeshVerify.description = 'Verifies that the Mesh is deployed and attempts to recreate it if deployment fails.' diff --git a/src/commands/commerce/test.js b/src/commands/commerce/test.js index 64ccf47..d6cd089 100644 --- a/src/commands/commerce/test.js +++ b/src/commands/commerce/test.js @@ -10,15 +10,31 @@ OF ANY KIND, either express or implied. See the License for the specific languag governing permissions and limitations under the License. */ import { Command, Help } from '@oclif/core' -import { checkAndRetryMeshUpdate } from '../../utils/mesh.js' +import { spawn } from 'child_process' +import { openSync } from 'fs' + export class TestCommand extends Command { async run () { - const runAIOCommand = async (command, args) => { - return await this.config.runCommand(command, args) - } - await checkAndRetryMeshUpdate(runAIOCommand) + const { args } = this.parse(TestCommand) + + // Spawn a detached child process to run the background task + try { + const out = openSync('./mesh-verify.log', 'w') + const err = openSync('./mesh-verify.log', 'a') + const childProcess = spawn( + 'aio', + ['commerce:mesh-verify'], + { + detached: true, + stdio: ['ignore', out, err] + } + ) + // Detach from the parent process + childProcess.unref() + } catch (error) {} } } -TestCommand.description = 'Spin up an Adobe Commerce Storefront on EDS using this CLI tool' +TestCommand.description = + "Spin up an Adobe Commerce Storefront on EDS using this CLI tool"; From 8320fbf056b93c6a9ec683449ace75c96579fa7d Mon Sep 17 00:00:00 2001 From: Stephen Rugh Date: Wed, 5 Feb 2025 14:08:32 -0600 Subject: [PATCH 2/7] move mesh log above final logs Signed-off-by: Stephen Rugh --- src/commands/commerce/init.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/commands/commerce/init.js b/src/commands/commerce/init.js index d84c022..037f30a 100644 --- a/src/commands/commerce/init.js +++ b/src/commands/commerce/init.js @@ -73,19 +73,8 @@ export class InitCommand extends Command { // 2025-02-04T17:42:36.664Z [commerce:mesh.js] error: TypeError: Cannot read properties of undefined (reading 'id') // at getMeshDetailsPage (aio-cli-plugin-commerce/src/utils/mesh.js:378:35) // const meshDetailsPageURL = getMeshDetailsPage() - const meshUrl = config.get('commerce.datasource.meshUrl') - - console.log(`🎉 ${boldWhite}Setup complete!${reset} 🎉`) - console.log(`${boldWhite}Customize your code:${reset} https://github.com/${githubOrg}/${githubRepo}`) - console.log(`${boldWhite}Edit your content:${reset} https://da.live/#/${githubOrg}/${githubRepo}`) - console.log(`${boldWhite}Manage your config:${reset} https://da.live/sheet#/${githubOrg}/${githubRepo}/configs-stage`) - console.log(`${boldWhite}Preview your storefront:${reset} https://main--${githubRepo}--${githubOrg}.aem.page/`) - meshUrl && console.log(`${boldWhite}Try out your API:${reset} ${meshUrl}`) - // meshDetailsPageURL && console.log(`${boldWhite}View your Mesh details:${reset} ${meshDetailsPageURL}`) - console.log(`${boldWhite}Run locally:${reset} "aio commerce:dev"`) - console.log('For next steps, including how to customize your storefront and make it your own, check out our docs:\nhttps://experienceleague.adobe.com/developer/commerce/storefront/') - if (shouldCreateMesh) { + console.log('⏳ Verifying Mesh provisioning behind the scenes. Please check mesh-verify.log for details, or run "aio commerce:mesh-verify" if there are failures.') // Spawn detached child process to verify mesh in the background, without disrupting user's CLI session. try { const out = openSync('./mesh-verify.log', 'w') @@ -107,6 +96,17 @@ export class InitCommand extends Command { } } + const meshUrl = config.get('commerce.datasource.meshUrl') + console.log(`🎉 ${boldWhite}Setup complete!${reset} 🎉`) + console.log(`${boldWhite}Customize your code:${reset} https://github.com/${githubOrg}/${githubRepo}`) + console.log(`${boldWhite}Edit your content:${reset} https://da.live/#/${githubOrg}/${githubRepo}`) + console.log(`${boldWhite}Manage your config:${reset} https://da.live/sheet#/${githubOrg}/${githubRepo}/configs-stage`) + console.log(`${boldWhite}Preview your storefront:${reset} https://main--${githubRepo}--${githubOrg}.aem.page/`) + meshUrl && console.log(`${boldWhite}Try out your API:${reset} ${meshUrl}`) + // meshDetailsPageURL && console.log(`${boldWhite}View your Mesh details:${reset} ${meshDetailsPageURL}`) + console.log(`${boldWhite}Run locally:${reset} "aio commerce:dev"`) + console.log('For next steps, including how to customize your storefront and make it your own, check out our docs:\nhttps://experienceleague.adobe.com/developer/commerce/storefront/') + // cleanup config.delete('commerce') // reset github org and repo, for aio commerce:dev command From 3bfd643617f50f079cf4d5dee565aa9d7c78292e Mon Sep 17 00:00:00 2001 From: Revanth Date: Thu, 6 Feb 2025 14:32:40 -0600 Subject: [PATCH 3/7] Setting detach to false to inherit shell --- src/commands/commerce/init.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/commerce/init.js b/src/commands/commerce/init.js index 037f30a..41fc655 100644 --- a/src/commands/commerce/init.js +++ b/src/commands/commerce/init.js @@ -84,7 +84,7 @@ export class InitCommand extends Command { 'aio', ['commerce:mesh-verify'], { - detached: true, + detached: false, stdio: ['ignore', out, err] } ) From a429fb290649a5e3349b86ffd3d9d7b7a23d8a7c Mon Sep 17 00:00:00 2001 From: Revanth Date: Thu, 6 Feb 2025 14:33:06 -0600 Subject: [PATCH 4/7] Setting retries to 3 --- src/commands/commerce/mesh-verify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/commerce/mesh-verify.js b/src/commands/commerce/mesh-verify.js index 23f2d42..89f2f17 100644 --- a/src/commands/commerce/mesh-verify.js +++ b/src/commands/commerce/mesh-verify.js @@ -9,10 +9,10 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { Command, Help } from '@oclif/core' +import { Command } from '@oclif/core' import { checkAndRetryMeshUpdate } from '../../utils/mesh.js' -const MESH_RETRIES = 2 +const MESH_RETRIES = 3 const MESH_RETRY_INTERVAL = 60000 export class MeshVerify extends Command { From 27b654b3b0caa34d18d57b5db9f86a27e913266e Mon Sep 17 00:00:00 2001 From: Revanth Date: Thu, 6 Feb 2025 20:40:05 -0600 Subject: [PATCH 5/7] Moving mesh verification check into provisioining code block --- src/commands/commerce/init.js | 75 +++++++++++++++++------------------ 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/commands/commerce/init.js b/src/commands/commerce/init.js index 41fc655..77fd924 100644 --- a/src/commands/commerce/init.js +++ b/src/commands/commerce/init.js @@ -42,6 +42,30 @@ export class InitCommand extends Command { if (shouldCreateMesh) { const installedPlugins = this.config.plugins await createMesh(runAIOCommand, installedPlugins) + console.log( + '⏳ Verifying Mesh provisioning behind the scenes. Please check mesh-verify.log for details, or run "aio commerce:mesh-verify" if there are failures.' + ) + // Spawn detached child process to verify mesh in the background, without disrupting user's CLI session. + try { + const out = openSync('./mesh-verify.log', 'w') + const err = openSync('./mesh-verify.log', 'a') + + const childProcess = spawn( + 'aio', + ['commerce:mesh-verify'], + { + detached: false, + stdio: ['ignore', out, err] + } + ) + // Detach from the parent process + childProcess.unref() + } catch (error) { + aioLogger.debug(error) + console.log( + '❌ Unable to verify mesh provisioning. Please try again with "aio commerce:mesh-verify"' + ) + } } else { // this means the user chose a non-demo endpoint and still opted out of // API Mesh creation. Use their endpoints in configs.js @@ -54,6 +78,9 @@ export class InitCommand extends Command { console.log('Not creating API Mesh - will use demo environment.') } + const meshDetailsPageURL = getMeshDetailsPage() + const meshUrl = config.get('commerce.datasource.meshUrl') + await createRepo() await modifyFstab() await modifySidekickConfig() @@ -69,41 +96,13 @@ export class InitCommand extends Command { await previewContent(filePaths) await publishContent() - // TODO: this fails with - // 2025-02-04T17:42:36.664Z [commerce:mesh.js] error: TypeError: Cannot read properties of undefined (reading 'id') - // at getMeshDetailsPage (aio-cli-plugin-commerce/src/utils/mesh.js:378:35) - // const meshDetailsPageURL = getMeshDetailsPage() - if (shouldCreateMesh) { - console.log('⏳ Verifying Mesh provisioning behind the scenes. Please check mesh-verify.log for details, or run "aio commerce:mesh-verify" if there are failures.') - // Spawn detached child process to verify mesh in the background, without disrupting user's CLI session. - try { - const out = openSync('./mesh-verify.log', 'w') - const err = openSync('./mesh-verify.log', 'a') - - const childProcess = spawn( - 'aio', - ['commerce:mesh-verify'], - { - detached: false, - stdio: ['ignore', out, err] - } - ) - // Detach from the parent process - childProcess.unref() - } catch (error) { - aioLogger.debug(error) - console.log('❌ Unable to verify mesh provisioning. Please try again with "aio commerce:mesh-verify"') - } - } - - const meshUrl = config.get('commerce.datasource.meshUrl') console.log(`🎉 ${boldWhite}Setup complete!${reset} 🎉`) console.log(`${boldWhite}Customize your code:${reset} https://github.com/${githubOrg}/${githubRepo}`) console.log(`${boldWhite}Edit your content:${reset} https://da.live/#/${githubOrg}/${githubRepo}`) console.log(`${boldWhite}Manage your config:${reset} https://da.live/sheet#/${githubOrg}/${githubRepo}/configs-stage`) console.log(`${boldWhite}Preview your storefront:${reset} https://main--${githubRepo}--${githubOrg}.aem.page/`) meshUrl && console.log(`${boldWhite}Try out your API:${reset} ${meshUrl}`) - // meshDetailsPageURL && console.log(`${boldWhite}View your Mesh details:${reset} ${meshDetailsPageURL}`) + meshDetailsPageURL && console.log(`${boldWhite}View your Mesh details:${reset} ${meshDetailsPageURL}`) console.log(`${boldWhite}Run locally:${reset} "aio commerce:dev"`) console.log('For next steps, including how to customize your storefront and make it your own, check out our docs:\nhttps://experienceleague.adobe.com/developer/commerce/storefront/') @@ -118,14 +117,14 @@ export class InitCommand extends Command { } InitCommand.flags = { - org: Flags.string({ char: 'o', description: 'your github org, ie "hlxsites"' }), - repo: Flags.string({ char: 'r', description: 'your github repo, ie "aem-boilerplate-commerce"' }) -} + org: Flags.string({ char: 'o', description: 'your github org, ie "hlxsites"' }), + repo: Flags.string({ char: 'r', description: 'your github repo, ie "aem-boilerplate-commerce"' }) + } -InitCommand.args = { -} + InitCommand.args = { + } -InitCommand.description = 'Scaffold your own Adobe Commerce storefront' -InitCommand.examples = [ - '$ aio commerce:init --org sirugh --repo my-storefront' -] + InitCommand.description = 'Scaffold your own Adobe Commerce storefront' + InitCommand.examples = [ + '$ aio commerce:init --org sirugh --repo my-storefront' + ] From 35a046cf9f01e1eacf8d8c011de9b653d1c42361 Mon Sep 17 00:00:00 2001 From: Revanth Date: Thu, 6 Feb 2025 20:41:25 -0600 Subject: [PATCH 6/7] Using longer retry interval --- src/commands/commerce/mesh-verify.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/commerce/mesh-verify.js b/src/commands/commerce/mesh-verify.js index 89f2f17..6ede579 100644 --- a/src/commands/commerce/mesh-verify.js +++ b/src/commands/commerce/mesh-verify.js @@ -12,8 +12,8 @@ governing permissions and limitations under the License. import { Command } from '@oclif/core' import { checkAndRetryMeshUpdate } from '../../utils/mesh.js' -const MESH_RETRIES = 3 -const MESH_RETRY_INTERVAL = 60000 +const MESH_RETRIES = 2 +const MESH_RETRY_INTERVAL = 90000 // 1.5 minutes export class MeshVerify extends Command { async run () { From d2e06e17bc55b97bb4e3b59ee200d2ce6dbcc4c2 Mon Sep 17 00:00:00 2001 From: Revanth Date: Thu, 6 Feb 2025 21:34:23 -0600 Subject: [PATCH 7/7] Added org prj and workspace selection during mesh-verify --- src/commands/commerce/init.js | 24 ++++++++------ src/commands/commerce/mesh-verify.js | 49 ++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/src/commands/commerce/init.js b/src/commands/commerce/init.js index 77fd924..49c7f3e 100644 --- a/src/commands/commerce/init.js +++ b/src/commands/commerce/init.js @@ -49,10 +49,14 @@ export class InitCommand extends Command { try { const out = openSync('./mesh-verify.log', 'w') const err = openSync('./mesh-verify.log', 'a') + const { org, project, workspace } = config.get('console') + const orgID = org.id + const projectID = project.id + const workspaceID = workspace.id const childProcess = spawn( 'aio', - ['commerce:mesh-verify'], + ['commerce:mesh-verify', '--orgId', orgID, '--projectId', projectID, '--workspaceId', workspaceID], { detached: false, stdio: ['ignore', out, err] @@ -117,14 +121,14 @@ export class InitCommand extends Command { } InitCommand.flags = { - org: Flags.string({ char: 'o', description: 'your github org, ie "hlxsites"' }), - repo: Flags.string({ char: 'r', description: 'your github repo, ie "aem-boilerplate-commerce"' }) - } + org: Flags.string({ char: 'o', description: 'your github org, ie "hlxsites"' }), + repo: Flags.string({ char: 'r', description: 'your github repo, ie "aem-boilerplate-commerce"' }) +} - InitCommand.args = { - } +InitCommand.args = { +} - InitCommand.description = 'Scaffold your own Adobe Commerce storefront' - InitCommand.examples = [ - '$ aio commerce:init --org sirugh --repo my-storefront' - ] +InitCommand.description = 'Scaffold your own Adobe Commerce storefront' +InitCommand.examples = [ + '$ aio commerce:init --org sirugh --repo my-storefront' +] diff --git a/src/commands/commerce/mesh-verify.js b/src/commands/commerce/mesh-verify.js index 6ede579..bf96629 100644 --- a/src/commands/commerce/mesh-verify.js +++ b/src/commands/commerce/mesh-verify.js @@ -9,19 +9,62 @@ the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTA OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ -import { Command } from '@oclif/core' +import { Command, Flags } from '@oclif/core' + import { checkAndRetryMeshUpdate } from '../../utils/mesh.js' +import { runCommand } from '../../utils/runCommand.js' const MESH_RETRIES = 2 const MESH_RETRY_INTERVAL = 90000 // 1.5 minutes export class MeshVerify extends Command { async run () { + const { flags } = await this.parse(MeshVerify) const runAIOCommand = async (command, args) => { return await this.config.runCommand(command, args) } - await checkAndRetryMeshUpdate(runAIOCommand, MESH_RETRIES, MESH_RETRY_INTERVAL) + + try { + const { orgId, projectId, workspaceId } = flags + + console.log(`Setting orgId: ${orgId}`) + await runCommand(`aio console org select ${orgId}`) + + console.log(`Setting projectId: ${projectId}`) + await runCommand(`aio console project select ${projectId}`) + + console.log(`Setting workspaceId: ${workspaceId}`) + await runCommand(`aio console workspace select ${workspaceId}`) + } catch (e) { + // If the user does not provide the required arguments, we will not attempt to select them and depend on preselected options from aio config. + } + + await checkAndRetryMeshUpdate( + runAIOCommand, + MESH_RETRIES, + MESH_RETRY_INTERVAL + ) } } -MeshVerify.description = 'Verifies that the Mesh is deployed and attempts to recreate it if deployment fails.' +MeshVerify.flags = { + orgId: Flags.string({ + name: 'orgId', + char: 'o', + required: false, + description: 'Organization ID' + }), + projectId: Flags.string({ + name: 'projectId', + required: false, + description: 'Project ID' + }), + workspaceId: Flags.string({ + name: 'workspaceId', + required: false, + description: 'Workspace ID' + }) +} + +MeshVerify.description = + 'Verifies that the Mesh is deployed and attempts to recreate it if deployment fails.'