From ebb835d66cbb8107206fd74ce4096f1fa5c950cc Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Mon, 7 Oct 2024 22:25:39 +0530 Subject: [PATCH 01/11] failed e2e tests fix --- src/commands/app/deploy.js | 12 ++-- src/commands/app/undeploy.js | 9 +-- src/lib/app-helper.js | 32 ++++++++++- src/lib/audit-logger.js | 2 +- test/commands/app/deploy.test.js | 38 +++++++++++++ test/commands/app/undeploy.test.js | 35 ++++++++++++ test/commands/lib/app-helper.test.js | 82 +++++++++++++++++++++++----- 7 files changed, 185 insertions(+), 25 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index 7781f11a..bf16f2d4 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -18,7 +18,7 @@ const BaseCommand = require('../../BaseCommand') const BuildCommand = require('./build') const webLib = require('@adobe/aio-lib-web') const { Flags } = require('@oclif/core') -const { createWebExportFilter, runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getCliInfo } = require('../../lib/app-helper') +const { createWebExportFilter, runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getCliInfo, checkifAccessTokenExists } = require('../../lib/app-helper') const rtLib = require('@adobe/aio-lib-runtime') const LogForwarding = require('../../lib/log-forwarding') const { sendAuditLogs, getAuditLogEvent, getFilesCountWithExtension } = require('../../lib/audit-logger') @@ -35,6 +35,8 @@ class Deploy extends BuildCommand { flags['web-assets'] = flags['web-assets'] && !flags.action flags.publish = flags.publish && !flags.action + const doesTokenExists = await checkifAccessTokenExists() + const deployConfigs = await this.getAppExtConfigs(flags) const keys = Object.keys(deployConfigs) const values = Object.values(deployConfigs) @@ -52,7 +54,7 @@ class Deploy extends BuildCommand { try { const aioConfig = (await this.getFullConfig()).aio - const cliDetails = await getCliInfo() + const cliDetails = doesTokenExists ? await getCliInfo() : null // 1. update log forwarding configuration // note: it is possible that .aio file does not exist, which means there is no local lg config @@ -64,7 +66,7 @@ class Deploy extends BuildCommand { const lfConfig = lf.getLocalConfigWithSecrets() if (lfConfig.isDefined()) { await lf.updateServerConfig(lfConfig) - spinner.succeed(chalk.green(`Log forwarding is set to '${lfConfig.getDestination()}'`)) + spinner.succeed(chalk.green(`\nLog forwarding is set to '${lfConfig.getDestination()}'`)) } else { if (flags.verbose) { spinner.info(chalk.dim('Log forwarding is not updated: no configuration is provided')) @@ -94,7 +96,7 @@ class Deploy extends BuildCommand { // 3. send deploy log event const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') - if (logEvent) { + if (logEvent && cliDetails) { await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) } else { this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) @@ -111,7 +113,7 @@ class Deploy extends BuildCommand { if (v.app.hasFrontend && flags['web-assets']) { const opItems = getFilesCountWithExtension(v.web.distProd) const assetDeployedLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_DEPLOYED') - if (assetDeployedLogEvent) { + if (assetDeployedLogEvent && cliDetails) { assetDeployedLogEvent.data.opItems = opItems await sendAuditLogs(cliDetails.accessToken, assetDeployedLogEvent, cliDetails.env) } diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index f11d25ce..e53586a6 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -17,7 +17,7 @@ const { Flags } = require('@oclif/core') const BaseCommand = require('../../BaseCommand') const webLib = require('@adobe/aio-lib-web') -const { runInProcess, buildExtensionPointPayloadWoMetadata, getCliInfo } = require('../../lib/app-helper') +const { runInProcess, buildExtensionPointPayloadWoMetadata, getCliInfo, checkifAccessTokenExists } = require('../../lib/app-helper') const rtLib = require('@adobe/aio-lib-runtime') const { sendAuditLogs, getAuditLogEvent } = require('../../lib/audit-logger') @@ -25,6 +25,7 @@ class Undeploy extends BaseCommand { async run () { // cli input const { flags } = await this.parse(Undeploy) + const doesTokenExists = await checkifAccessTokenExists() const undeployConfigs = await this.getAppExtConfigs(flags) let libConsoleCLI @@ -46,11 +47,11 @@ class Undeploy extends BaseCommand { const spinner = ora() try { const aioConfig = (await this.getFullConfig()).aio - const cliDetails = await getCliInfo() + const cliDetails = doesTokenExists ? await getCliInfo() : null const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_UNDEPLOY') // 1.1. send audit log event for successful undeploy - if (logEvent) { + if (logEvent && cliDetails) { await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) } else { this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) @@ -61,7 +62,7 @@ class Undeploy extends BaseCommand { const v = values[i] await this.undeployOneExt(k, v, flags, spinner) const assetUndeployLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_UNDEPLOYED') - if (assetUndeployLogEvent) { + if (assetUndeployLogEvent && cliDetails) { await sendAuditLogs(cliDetails.accessToken, assetUndeployLogEvent, cliDetails.env) } } diff --git a/src/lib/app-helper.js b/src/lib/app-helper.js index a323c2c6..bfd30367 100644 --- a/src/lib/app-helper.js +++ b/src/lib/app-helper.js @@ -24,6 +24,9 @@ const { EOL } = require('os') const { getCliEnv } = require('@adobe/aio-lib-env') const yaml = require('js-yaml') const RuntimeLib = require('@adobe/aio-lib-runtime') +const { exec } = require('child_process') +const util = require('util') +const execAsync = util.promisify(exec) /** @private */ function isNpmInstalled () { @@ -155,7 +158,7 @@ async function runScript (command, dir, cmdArgs = []) { aioLogger.debug(`Killing ${command} event hook long-running process (pid: ${pid})`) process.kill(pid, 'SIGTERM') } catch (_) { - // do nothing if pid not found + // do nothing if pid not found } }) } @@ -567,6 +570,30 @@ function getObjectValue (obj, key) { return keys.filter(o => o.trim()).reduce((o, i) => o && getObjectProp(o, i), obj) } +/** + * Function to run `aio config get ims.contexts.cli.access_token.token` command and retrieve the token + * This function is used to check if the access token exists in the CLI context or not + * @returns {Promise} Resolves to the access token if it exists, else false + */ +const checkifAccessTokenExists = async () => { + try { + const { stdout, stderr } = await execAsync('aio config get ims.contexts.cli.access_token.token') + if (stderr) { + console.warn(`Warning: ${stderr}`) + return false + } + if (!stdout || stdout === '') { + console.info('No token found') + return false + } + console.log(`Access token found: ${stdout}`) + return true + } catch (error) { + console.error(`Error retrieving token: ${error.message}`) + return false + } +} + module.exports = { getObjectValue, getObjectProp, @@ -596,5 +623,6 @@ module.exports = { buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, atLeastOne, - deleteUserConfig + deleteUserConfig, + checkifAccessTokenExists } diff --git a/src/lib/audit-logger.js b/src/lib/audit-logger.js index 24a1fd86..67443521 100644 --- a/src/lib/audit-logger.js +++ b/src/lib/audit-logger.js @@ -33,7 +33,7 @@ const AUDIT_SERVICE_ENPOINTS = { * @param {string} env valid env stage|prod */ async function sendAuditLogs (accessToken, logEvent, env = 'prod') { - const url = AUDIT_SERVICE_ENPOINTS[env] + const url = AUDIT_SERVICE_ENPOINTS[env] ?? AUDIT_SERVICE_ENPOINTS.prod const payload = { event: logEvent } diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index e4ea014b..03ce98ee 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -198,6 +198,7 @@ beforeEach(() => { } }) LogForwarding.init.mockResolvedValue(mockLogForwarding) + helpers.checkifAccessTokenExists.mockResolvedValue(true) }) test('exports', async () => { @@ -1338,6 +1339,43 @@ describe('run', () => { expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) }) + test('Do not send audit logs for successful app deploy, if no-login case', async () => { + const mockToken = 'mocktoken' + const mockEnv = 'stage' + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + helpers.getCliInfo.mockResolvedValueOnce({ + accessToken: mockToken, + env: mockEnv + }) + helpers.checkifAccessTokenExists.mockResolvedValueOnce(false); + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + + auditLogger.getAuditLogEvent.mockImplementation((flags, project, event) => null) + + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + + await command.run() + expect(command.error).toHaveBeenCalledTimes(0) + expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) + }) + test('Send audit logs for successful app deploy + web assets', async () => { const mockToken = 'mocktoken' const mockEnv = 'stage' diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index ee40f37e..42830037 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -476,6 +476,8 @@ describe('run', () => { const mockWorkspaceId = 'mockworkspaceid' const mockWorkspaceName = 'mockworkspacename' + helpers.checkifAccessTokenExists.mockResolvedValue(true) + command.getFullConfig = jest.fn().mockReturnValue({ aio: { project: { @@ -500,6 +502,39 @@ describe('run', () => { expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) + test('Do not Send audit logs for successful app undeploy if no-login case', async () => { + const mockToken = 'mocktoken' + const mockEnv = 'stage' + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + + helpers.checkifAccessTokenExists.mockResolvedValue(false) + + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + + await command.run() + expect(command.error).toHaveBeenCalledTimes(0) + expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) + }) + test('Do not Send audit logs for successful app undeploy', async () => { const mockOrg = 'mockorg' const mockProject = 'mockproject' diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index cfc59a99..cfbd94e2 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -37,6 +37,8 @@ const appHelper = require('../../../src/lib/app-helper') const aioConfig = require('@adobe/aio-lib-core-config') const libEnv = require('@adobe/aio-lib-env') const libIms = require('@adobe/aio-lib-ims') +const util = require('util'); + beforeEach(() => { Object.defineProperty(process, 'platform', { value: 'linux' }) @@ -293,7 +295,7 @@ test('runPackageScript logs if package.json does not have matching script', asyn test('runInProcess with script should call runScript', async () => { expect(appHelper.runInProcess).toBeDefined() expect(appHelper.runInProcess).toBeInstanceOf(Function) - execa.command.mockReturnValue({ on: () => {} }) + execa.command.mockReturnValue({ on: () => { } }) await appHelper.runInProcess('echo new command who dis?', {}) expect(mockLogger.debug).toHaveBeenCalledWith('runInProcess: error running project hook in process, running as package script instead') expect(execa.command).toHaveBeenCalledWith('echo new command who dis?', expect.any(Object)) @@ -308,7 +310,7 @@ test('runInProcess with require', async () => { ) expect(appHelper.runInProcess).toBeDefined() expect(appHelper.runInProcess).toBeInstanceOf(Function) - execa.command.mockReturnValue({ on: () => {} }) + execa.command.mockReturnValue({ on: () => { } }) await appHelper.runInProcess('does-not-exist', {}) expect(mockReq).toHaveBeenCalled() expect(mockLogger.debug).toHaveBeenCalledWith('runInProcess: running project hook in process') @@ -328,13 +330,13 @@ test('runScript with empty command', async () => { }) test('runScript with defined dir', async () => { - execa.command.mockReturnValue({ on: () => {} }) + execa.command.mockReturnValue({ on: () => { } }) await appHelper.runScript('somecommand', 'somedir') expect(execa.command).toHaveBeenCalledWith('somecommand', expect.objectContaining({ cwd: 'somedir' })) }) test('runScript with empty dir => process.cwd', async () => { - execa.command.mockReturnValue({ on: () => {} }) + execa.command.mockReturnValue({ on: () => { } }) await appHelper.runScript('somecommand', undefined) expect(execa.command).toHaveBeenCalledWith('somecommand', expect.objectContaining({ cwd: process.cwd() })) }) @@ -589,9 +591,9 @@ test('setWorkspaceServicesConfig', () => { appHelper.setWorkspaceServicesConfig(fakeServiceProps) expect(aioConfig.set).toHaveBeenCalledWith( 'project.workspace.details.services', [ - { name: 'first', code: 'firsts' }, - { name: 'sec', code: 'secs' } - ], + { name: 'first', code: 'firsts' }, + { name: 'sec', code: 'secs' } + ], true ) }) @@ -605,10 +607,10 @@ test('setOrgServicesConfig', () => { appHelper.setOrgServicesConfig(fakeOrgServices) expect(aioConfig.set).toHaveBeenCalledWith( 'project.org.details.services', [ - { name: 'first', code: 'firsts', type: 'entp' }, - { name: 'sec', code: 'secs', type: 'entp' }, - { name: 'third', code: 'thirds', type: 'entp' } - ], + { name: 'first', code: 'firsts', type: 'entp' }, + { name: 'sec', code: 'secs', type: 'entp' }, + { name: 'third', code: 'thirds', type: 'entp' } + ], true ) }) @@ -870,8 +872,8 @@ describe('serviceToGeneratorInput', () => { test('list with empty codes', () => { expect(appHelper.servicesToGeneratorInput( [{ name: 'hello', code: 'hellocode' }, - { name: 'bonjour', code: 'bonjourcode' }, - { name: 'nocode' }] + { name: 'bonjour', code: 'bonjourcode' }, + { name: 'nocode' }] )).toEqual('hellocode,bonjourcode') }) }) @@ -988,3 +990,57 @@ describe('object values', () => { expect(appHelper.getObjectValue(obj)).toEqual(obj) }) }) + +describe.only('checkifAccessTokenExists', () => { + // let mockExec; + + // beforeEach(() => { + // // Step 1: Create a mock for exec + // mockExec = jest.fn((command, callback) => { + // // Step 2: Call the callback with null error and desired stdout + // callback(null, { stdout: 'someAccessToken', stderr: '' }); + // }); + + // // Step 3: Replace the exec function in child_process with the mock + // jest.spyOn(require('child_process'), 'exec').mockImplementation(mockExec); + + // // Step 4: Mock util.promisify to return the mocked exec + // util.promisify = jest.fn().mockReturnValue(mockExec); + // }); + + // afterEach(() => { + // jest.restoreAllMocks(); // Restore all mocks after each test + // }); + + // test('should return true when token is found', async () => { + // // Step 5: Call the function + // const result = await appHelper.checkifAccessTokenExists(); + + // // Assert that exec was called with the correct command + // expect(mockExec).toHaveBeenCalledWith('aio config get ims.contexts.cli.access_token.token', expect.any(Function)); + + // // Assert the result is true (token was found) + // expect(result).toBe(true); + + // // Assert that the log was called with the expected message + // expect(console.log).toHaveBeenCalledWith('Access token found: someAccessToken'); + // }); + jest.mock('util', () => ({ + promisify: jest.fn(() => jest.fn()), + })); + + const { execAsync } = jest.mock('util'); + + beforeEach(() => { + execAsync.mockClear(); // Clear mock calls before each test + }); + + test('returns true when access token is found', async () => { + const mockStdout = 'some_access_token'; + execAsync.mockResolvedValueOnce({ stdout: mockStdout, stderr: '' }); + const result = await appHelper.checkifAccessTokenExists(); + expect(result).toBe(true); + expect(execAsync).toHaveBeenCalledTimes(1); + expect(execAsync).toHaveBeenCalledWith('aio config get ims.contexts.cli.access_token.token'); + }); +}); \ No newline at end of file From 3cdcbb20f33d5c28b3e1c08a41b5e0233a6441e3 Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Thu, 10 Oct 2024 15:53:54 +0530 Subject: [PATCH 02/11] e2e test failures fix --- src/commands/app/deploy.js | 12 ++- src/commands/app/undeploy.js | 12 ++- src/lib/audit-logger.js | 2 +- test/commands/app/deploy.test.js | 51 ++++++++++- test/commands/app/undeploy.test.js | 42 ++++++++- test/commands/lib/app-helper.test.js | 116 +++++++++++++------------ test/commands/lib/audit-logger.test.js | 15 ++++ 7 files changed, 185 insertions(+), 65 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index bf16f2d4..b0262483 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -97,7 +97,11 @@ class Deploy extends BuildCommand { // 3. send deploy log event const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') if (logEvent && cliDetails) { - await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + try { + await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + } catch (error) { + this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + } } else { this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) } @@ -115,7 +119,11 @@ class Deploy extends BuildCommand { const assetDeployedLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_DEPLOYED') if (assetDeployedLogEvent && cliDetails) { assetDeployedLogEvent.data.opItems = opItems - await sendAuditLogs(cliDetails.accessToken, assetDeployedLogEvent, cliDetails.env) + try { + await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + } catch (error) { + this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + } } } } diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index e53586a6..3ee4a3e0 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -52,7 +52,11 @@ class Undeploy extends BaseCommand { // 1.1. send audit log event for successful undeploy if (logEvent && cliDetails) { - await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + try { + await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + } catch (error) { + this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + } } else { this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) } @@ -63,7 +67,11 @@ class Undeploy extends BaseCommand { await this.undeployOneExt(k, v, flags, spinner) const assetUndeployLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_UNDEPLOYED') if (assetUndeployLogEvent && cliDetails) { - await sendAuditLogs(cliDetails.accessToken, assetUndeployLogEvent, cliDetails.env) + try { + await sendAuditLogs(cliDetails.accessToken, assetUndeployLogEvent, cliDetails.env) + } catch (error) { + this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + } } } diff --git a/src/lib/audit-logger.js b/src/lib/audit-logger.js index 67443521..4665259c 100644 --- a/src/lib/audit-logger.js +++ b/src/lib/audit-logger.js @@ -16,7 +16,7 @@ const chalk = require('chalk') const OPERATIONS = { AB_APP_DEPLOY: 'ab_app_deploy', AB_APP_UNDEPLOY: 'ab_app_undeploy', - AB_APP_TEST: 'ab_app_test', // todo : remove after testing + AB_APP_TEST: 'ab_app_test', AB_APP_ASSETS_DEPLOYED: 'ab_app_assets_deployed', AB_APP_ASSETS_UNDEPLOYED: 'ab_app_assets_undeployed' } diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index 03ce98ee..bfd6895a 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -1303,7 +1303,7 @@ describe('run', () => { expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) - test('Do not send audit logs for successful app deploy', async () => { + test('Do not send audit logs for successful app deploy, if no logevent is present', async () => { const mockToken = 'mocktoken' const mockEnv = 'stage' const mockOrg = 'mockorg' @@ -1350,7 +1350,7 @@ describe('run', () => { accessToken: mockToken, env: mockEnv }) - helpers.checkifAccessTokenExists.mockResolvedValueOnce(false); + helpers.checkifAccessTokenExists.mockResolvedValueOnce(false) command.getFullConfig = jest.fn().mockReturnValue({ aio: { project: { @@ -1415,4 +1415,51 @@ describe('run', () => { expect(auditLogger.getFilesCountWithExtension).toHaveBeenCalledTimes(2) expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) + + test('Should deploy successfully even if Audit log service is unavailable', async () => { + const mockToken = 'mocktoken' + const mockEnv = 'stage' + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + helpers.getCliInfo.mockResolvedValueOnce({ + accessToken: mockToken, + env: mockEnv + }) + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + + auditLogger.sendAuditLogs.mockRejectedValue({ + message: 'Internal Server Error', + status: 500 + }) + + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + + await command.run() + expect(command.log).toHaveBeenCalledWith( + expect.stringContaining('skipping publish phase...') + ) + + expect(command.log).toHaveBeenCalledWith( + expect.stringContaining('Successful deployment 🏄') + ) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(2) + expect(command.error).toHaveBeenCalledTimes(0) + expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) + }) }) diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index 42830037..58719ed4 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -503,14 +503,12 @@ describe('run', () => { }) test('Do not Send audit logs for successful app undeploy if no-login case', async () => { - const mockToken = 'mocktoken' - const mockEnv = 'stage' const mockOrg = 'mockorg' const mockProject = 'mockproject' const mockWorkspaceId = 'mockworkspaceid' const mockWorkspaceName = 'mockworkspacename' - helpers.checkifAccessTokenExists.mockResolvedValue(false) + helpers.checkifAccessTokenExists.mockResolvedValueOnce(false) command.getFullConfig = jest.fn().mockReturnValue({ aio: { @@ -535,7 +533,7 @@ describe('run', () => { expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) }) - test('Do not Send audit logs for successful app undeploy', async () => { + test('Do not Send audit logs for successful app undeploy, if no logevent is present', async () => { const mockOrg = 'mockorg' const mockProject = 'mockproject' const mockWorkspaceId = 'mockworkspaceid' @@ -566,4 +564,40 @@ describe('run', () => { expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) expect(command.log).toHaveBeenCalledWith(expect.stringMatching(/Warning: No valid config data found to send audit log event for deployment/)) }) + + test('Should app undeploy successfully even if Audit Log Service is not available', async () => { + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + helpers.checkifAccessTokenExists.mockResolvedValue(true) + + auditLogger.sendAuditLogs.mockRejectedValue({ + message: 'Internal Server Error', + status: 500 + }) + + await command.run() + expect(command.error).toHaveBeenCalledTimes(0) + expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(2) + expect(command.log).toHaveBeenCalledWith(expect.stringMatching('Error: Audit Log Service Error: Failed to send audit log event for deployment.')) + }) }) diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index cfbd94e2..e46ba96f 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -37,8 +37,11 @@ const appHelper = require('../../../src/lib/app-helper') const aioConfig = require('@adobe/aio-lib-core-config') const libEnv = require('@adobe/aio-lib-env') const libIms = require('@adobe/aio-lib-ims') -const util = require('util'); +const { exec } = require('child_process') +jest.mock('child_process', () => ({ + exec: jest.fn() +})) beforeEach(() => { Object.defineProperty(process, 'platform', { value: 'linux' }) @@ -591,9 +594,9 @@ test('setWorkspaceServicesConfig', () => { appHelper.setWorkspaceServicesConfig(fakeServiceProps) expect(aioConfig.set).toHaveBeenCalledWith( 'project.workspace.details.services', [ - { name: 'first', code: 'firsts' }, - { name: 'sec', code: 'secs' } - ], + { name: 'first', code: 'firsts' }, + { name: 'sec', code: 'secs' } + ], true ) }) @@ -607,10 +610,10 @@ test('setOrgServicesConfig', () => { appHelper.setOrgServicesConfig(fakeOrgServices) expect(aioConfig.set).toHaveBeenCalledWith( 'project.org.details.services', [ - { name: 'first', code: 'firsts', type: 'entp' }, - { name: 'sec', code: 'secs', type: 'entp' }, - { name: 'third', code: 'thirds', type: 'entp' } - ], + { name: 'first', code: 'firsts', type: 'entp' }, + { name: 'sec', code: 'secs', type: 'entp' }, + { name: 'third', code: 'thirds', type: 'entp' } + ], true ) }) @@ -872,8 +875,8 @@ describe('serviceToGeneratorInput', () => { test('list with empty codes', () => { expect(appHelper.servicesToGeneratorInput( [{ name: 'hello', code: 'hellocode' }, - { name: 'bonjour', code: 'bonjourcode' }, - { name: 'nocode' }] + { name: 'bonjour', code: 'bonjourcode' }, + { name: 'nocode' }] )).toEqual('hellocode,bonjourcode') }) }) @@ -991,56 +994,61 @@ describe('object values', () => { }) }) -describe.only('checkifAccessTokenExists', () => { - // let mockExec; +describe('checkifAccessTokenExists', () => { + let consoleLogSpy, consoleWarnSpy, consoleInfoSpy, consoleErrorSpy - // beforeEach(() => { - // // Step 1: Create a mock for exec - // mockExec = jest.fn((command, callback) => { - // // Step 2: Call the callback with null error and desired stdout - // callback(null, { stdout: 'someAccessToken', stderr: '' }); - // }); + beforeEach(() => { + consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { }) + consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { }) + consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => { }) + consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { }) + }) - // // Step 3: Replace the exec function in child_process with the mock - // jest.spyOn(require('child_process'), 'exec').mockImplementation(mockExec); + afterEach(() => { + jest.restoreAllMocks() + }) - // // Step 4: Mock util.promisify to return the mocked exec - // util.promisify = jest.fn().mockReturnValue(mockExec); - // }); + test('should return true when access token is found', async () => { + exec.mockImplementation((command, callback) => { + callback(null, { stdout: 'mock_access_token', stderr: '' }) + }) - // afterEach(() => { - // jest.restoreAllMocks(); // Restore all mocks after each test - // }); + const result = await appHelper.checkifAccessTokenExists() - // test('should return true when token is found', async () => { - // // Step 5: Call the function - // const result = await appHelper.checkifAccessTokenExists(); + expect(result).toBe(true) + expect(consoleLogSpy).toHaveBeenCalledWith('Access token found: mock_access_token') + }) - // // Assert that exec was called with the correct command - // expect(mockExec).toHaveBeenCalledWith('aio config get ims.contexts.cli.access_token.token', expect.any(Function)); + test('should return false when access token is not found', async () => { + exec.mockImplementation((command, callback) => { + callback(null, { stdout: '', stderr: '' }) + }) - // // Assert the result is true (token was found) - // expect(result).toBe(true); + const result = await appHelper.checkifAccessTokenExists() - // // Assert that the log was called with the expected message - // expect(console.log).toHaveBeenCalledWith('Access token found: someAccessToken'); - // }); - jest.mock('util', () => ({ - promisify: jest.fn(() => jest.fn()), - })); - - const { execAsync } = jest.mock('util'); + expect(result).toBe(false) + expect(consoleInfoSpy).toHaveBeenCalledWith('No token found') + }) - beforeEach(() => { - execAsync.mockClear(); // Clear mock calls before each test - }); - - test('returns true when access token is found', async () => { - const mockStdout = 'some_access_token'; - execAsync.mockResolvedValueOnce({ stdout: mockStdout, stderr: '' }); - const result = await appHelper.checkifAccessTokenExists(); - expect(result).toBe(true); - expect(execAsync).toHaveBeenCalledTimes(1); - expect(execAsync).toHaveBeenCalledWith('aio config get ims.contexts.cli.access_token.token'); - }); -}); \ No newline at end of file + test('should return false and warn when there is an stderr', async () => { + exec.mockImplementation((command, callback) => { + callback(null, { stdout: 'mock_access_token', stderr: 'Some error occurred' }) + }) + + const result = await appHelper.checkifAccessTokenExists() + + expect(result).toBe(false) + expect(consoleWarnSpy).toHaveBeenCalledWith('Warning: Some error occurred') + }) + + test('should return false when an error occurs', async () => { + exec.mockImplementation((command, callback) => { + callback(new Error('Failed to execute command')) + }) + + const result = await appHelper.checkifAccessTokenExists() + + expect(result).toBe(false) + expect(consoleErrorSpy).toHaveBeenCalledWith('Error retrieving token: Failed to execute command') + }) +}) diff --git a/test/commands/lib/audit-logger.test.js b/test/commands/lib/audit-logger.test.js index 52f49472..2e178d3d 100644 --- a/test/commands/lib/audit-logger.test.js +++ b/test/commands/lib/audit-logger.test.js @@ -90,6 +90,21 @@ test('sendAuditLogs with default params', async () => { expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS.prod, options) }) +test('should take prod endpoint if calling sendAuditLogs with non-exisiting env', async () => { + fetch.mockReturnValue(mockResponse) + const options = { + method: 'POST', + headers: { + Authorization: 'Bearer ' + mockToken, + 'Content-type': 'application/json' + }, + body: JSON.stringify({ event: mockLogEvent }) + } + await auditLogger.sendAuditLogs(mockToken, mockLogEvent, 'dev') + expect(fetch).toHaveBeenCalledTimes(1) + expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS.prod, options) +}) + test('sendAuditLogs error response', async () => { fetch.mockReturnValue(mockErrorResponse) const options = { From c9734099a0f34ae0abb8daa6bde52392a9e9863b Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Mon, 14 Oct 2024 14:40:02 +0530 Subject: [PATCH 03/11] PR comments fixed --- src/commands/app/deploy.js | 18 +++++--- src/commands/app/undeploy.js | 25 +++++++---- src/lib/app-helper.js | 6 +-- src/lib/audit-logger.js | 6 +-- test/commands/app/deploy.test.js | 55 ++++++++++++++++++++--- test/commands/app/undeploy.test.js | 56 ++++++++++++++++++++--- test/commands/lib/app-helper.test.js | 61 +++++++++++++++----------- test/commands/lib/audit-logger.test.js | 8 ++-- 8 files changed, 169 insertions(+), 66 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index b0262483..b14cf803 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -35,7 +35,13 @@ class Deploy extends BuildCommand { flags['web-assets'] = flags['web-assets'] && !flags.action flags.publish = flags.publish && !flags.action - const doesTokenExists = await checkifAccessTokenExists() + const isValidCommand = this.config.findCommand('config:get') + + if (!isValidCommand) { + this.error('The config:get command is not available. Please update the aio-cli to the latest version.') + } + + const doesTokenExists = isValidCommand ? await checkifAccessTokenExists() : false const deployConfigs = await this.getAppExtConfigs(flags) const keys = Object.keys(deployConfigs) @@ -54,7 +60,7 @@ class Deploy extends BuildCommand { try { const aioConfig = (await this.getFullConfig()).aio - const cliDetails = doesTokenExists ? await getCliInfo() : null + const loginCredentials = doesTokenExists ? await getCliInfo() : null // 1. update log forwarding configuration // note: it is possible that .aio file does not exist, which means there is no local lg config @@ -96,9 +102,9 @@ class Deploy extends BuildCommand { // 3. send deploy log event const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') - if (logEvent && cliDetails) { + if (logEvent && loginCredentials) { try { - await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) } catch (error) { this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) } @@ -117,10 +123,10 @@ class Deploy extends BuildCommand { if (v.app.hasFrontend && flags['web-assets']) { const opItems = getFilesCountWithExtension(v.web.distProd) const assetDeployedLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_DEPLOYED') - if (assetDeployedLogEvent && cliDetails) { + if (assetDeployedLogEvent && loginCredentials) { assetDeployedLogEvent.data.opItems = opItems try { - await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) } catch (error) { this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) } diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index 3ee4a3e0..fc162411 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -25,7 +25,14 @@ class Undeploy extends BaseCommand { async run () { // cli input const { flags } = await this.parse(Undeploy) - const doesTokenExists = await checkifAccessTokenExists() + + const isValidCommand = this.config.findCommand('config:get') + + if (!isValidCommand) { + this.error('The config:get command is not available. Please update the aio-cli to the latest version.') + } + + const doesTokenExists = isValidCommand ? await checkifAccessTokenExists() : false const undeployConfigs = await this.getAppExtConfigs(flags) let libConsoleCLI @@ -47,18 +54,18 @@ class Undeploy extends BaseCommand { const spinner = ora() try { const aioConfig = (await this.getFullConfig()).aio - const cliDetails = doesTokenExists ? await getCliInfo() : null + const loginCredentials = doesTokenExists ? await getCliInfo() : null const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_UNDEPLOY') // 1.1. send audit log event for successful undeploy - if (logEvent && cliDetails) { + if (logEvent && loginCredentials) { try { - await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) + await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) } catch (error) { - this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.') } } else { - this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) + this.warn('Warning: No valid config data found to send audit log event for un-deployment.') } for (let i = 0; i < keys.length; ++i) { @@ -66,11 +73,11 @@ class Undeploy extends BaseCommand { const v = values[i] await this.undeployOneExt(k, v, flags, spinner) const assetUndeployLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_UNDEPLOYED') - if (assetUndeployLogEvent && cliDetails) { + if (assetUndeployLogEvent && loginCredentials) { try { - await sendAuditLogs(cliDetails.accessToken, assetUndeployLogEvent, cliDetails.env) + await sendAuditLogs(loginCredentials.accessToken, assetUndeployLogEvent, loginCredentials.env) } catch (error) { - this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.') } } } diff --git a/src/lib/app-helper.js b/src/lib/app-helper.js index bfd30367..64f30f8b 100644 --- a/src/lib/app-helper.js +++ b/src/lib/app-helper.js @@ -24,9 +24,6 @@ const { EOL } = require('os') const { getCliEnv } = require('@adobe/aio-lib-env') const yaml = require('js-yaml') const RuntimeLib = require('@adobe/aio-lib-runtime') -const { exec } = require('child_process') -const util = require('util') -const execAsync = util.promisify(exec) /** @private */ function isNpmInstalled () { @@ -577,7 +574,7 @@ function getObjectValue (obj, key) { */ const checkifAccessTokenExists = async () => { try { - const { stdout, stderr } = await execAsync('aio config get ims.contexts.cli.access_token.token') + const { stdout, stderr } = await execa('aio', ['config', 'get', 'ims.contexts.cli.access_token.token']) if (stderr) { console.warn(`Warning: ${stderr}`) return false @@ -586,7 +583,6 @@ const checkifAccessTokenExists = async () => { console.info('No token found') return false } - console.log(`Access token found: ${stdout}`) return true } catch (error) { console.error(`Error retrieving token: ${error.message}`) diff --git a/src/lib/audit-logger.js b/src/lib/audit-logger.js index 4665259c..c2f4d28b 100644 --- a/src/lib/audit-logger.js +++ b/src/lib/audit-logger.js @@ -21,7 +21,7 @@ const OPERATIONS = { AB_APP_ASSETS_UNDEPLOYED: 'ab_app_assets_undeployed' } -const AUDIT_SERVICE_ENPOINTS = { +const AUDIT_SERVICE_ENDPOINTS = { stage: 'https://adp-auditlog-service-stage.adobeioruntime.net/api/v1/web/audit-log-api/event-post', prod: 'https://adp-auditlog-service-prod.adobeioruntime.net/api/v1/web/audit-log-api/event-post' } @@ -33,7 +33,7 @@ const AUDIT_SERVICE_ENPOINTS = { * @param {string} env valid env stage|prod */ async function sendAuditLogs (accessToken, logEvent, env = 'prod') { - const url = AUDIT_SERVICE_ENPOINTS[env] ?? AUDIT_SERVICE_ENPOINTS.prod + const url = AUDIT_SERVICE_ENDPOINTS[env] ?? AUDIT_SERVICE_ENDPOINTS.prod const payload = { event: logEvent } @@ -139,6 +139,6 @@ function getFilesCountWithExtension (directory) { module.exports = { sendAuditLogs, getAuditLogEvent, - AUDIT_SERVICE_ENPOINTS, + AUDIT_SERVICE_ENDPOINTS, getFilesCountWithExtension } diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index bfd6895a..ba729819 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -218,7 +218,7 @@ test('flags', async () => { expect(typeof TheCommand.flags.action).toBe('object') expect(TheCommand.flags.action.char).toBe('a') expect(typeof TheCommand.flags.action.description).toBe('string') - expect(JSON.stringify(TheCommand.flags.action.exclusive)).toStrictEqual(JSON.stringify(['extension', { name: 'publish', when: () => {} }])) + expect(JSON.stringify(TheCommand.flags.action.exclusive)).toStrictEqual(JSON.stringify(['extension', { name: 'publish', when: () => { } }])) expect(typeof TheCommand.flags['web-assets']).toBe('object') expect(typeof TheCommand.flags['web-assets'].description).toBe('string') @@ -280,7 +280,7 @@ describe('run', () => { command.appConfig = cloneDeep(mockConfigData) command.appConfig.actions = { dist: 'actions' } command.appConfig.web.distProd = 'dist' - command.config = { runCommand: jest.fn(), runHook: jest.fn() } + command.config = { runCommand: jest.fn(), runHook: jest.fn(), findCommand: jest.fn().mockReturnValue({}) } command.buildOneExt = jest.fn() command.getAppExtConfigs = jest.fn() command.getLibConsoleCLI = jest.fn(() => mockLibConsoleCLI) @@ -1195,7 +1195,8 @@ describe('run', () => { test('does NOT fire `event` hooks when feature flag is NOT enabled', async () => { const runHook = jest.fn() - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({ enabled: false }) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) command.argv = [] await command.run() @@ -1206,7 +1207,8 @@ describe('run', () => { test('DOES fire `event` hooks when feature flag IS enabled', async () => { const runHook = jest.fn() - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -1219,7 +1221,8 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1238,7 +1241,8 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1260,7 +1264,8 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1462,4 +1467,40 @@ describe('run', () => { expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) }) + + test('Should not send audit logs, if findComand does not exist in app deploy', async () => { + const mockToken = 'mocktoken' + const mockEnv = 'stage' + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + helpers.getCliInfo.mockResolvedValueOnce({ + accessToken: mockToken, + env: mockEnv + }) + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + command.config = { runCommand: jest.fn(), runHook: jest.fn(), findCommand: jest.fn().mockReturnValue(null) } + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + + await command.run() + expect(command.error).toHaveBeenCalledTimes(1) + expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs.mock.calls.length).toBeLessThanOrEqual(0) + expect(auditLogger.sendAuditLogs).not.toHaveBeenCalledWith() + }) }) diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index 58719ed4..28054d99 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -143,7 +143,13 @@ describe('run', () => { command.error = jest.fn() command.log = jest.fn() command.appConfig = mockConfigData - command.config = { runCommand: jest.fn(), runHook: jest.fn() } + command.config = { + runCommand: jest.fn(), + runHook: jest.fn(), + findCommand: jest.fn().mockReturnValue({ + enabled: true + }) + } command.getLibConsoleCLI = jest.fn(() => mockLibConsoleCLI) command.getAppExtConfigs = jest.fn() command.getFullConfig = jest.fn().mockReturnValue({ @@ -425,7 +431,8 @@ describe('run', () => { test('does NOT fire `event` hooks when feature flag is NOT enabled', async () => { const runHook = jest.fn() - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({}) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) command.argv = [] await command.run() @@ -435,7 +442,8 @@ describe('run', () => { test('does NOT fire `event` hooks when events flag is false', async () => { const runHook = jest.fn() - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({}) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -448,7 +456,8 @@ describe('run', () => { successes: ['ok'], failures: [] }) - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({}) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -461,7 +470,8 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - command.config = { runHook } + const findCommand = jest.fn().mockReturnValueOnce({}) + command.config = { runHook, findCommand } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-undeploy-event-reg', expect.any(Object)) @@ -562,7 +572,40 @@ describe('run', () => { expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) - expect(command.log).toHaveBeenCalledWith(expect.stringMatching(/Warning: No valid config data found to send audit log event for deployment/)) + }) + + test('Do not Send audit logs for successful app undeploy, if no findCommand is not present', async () => { + const mockOrg = 'mockorg' + const mockProject = 'mockproject' + const mockWorkspaceId = 'mockworkspaceid' + const mockWorkspaceName = 'mockworkspacename' + + command.getFullConfig = jest.fn().mockReturnValue({ + aio: { + project: { + id: mockProject, + org: { + id: mockOrg + }, + workspace: { + id: mockWorkspaceId, + name: mockWorkspaceName + } + } + } + }) + command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + + const findCommand = jest.fn().mockReturnValueOnce(null) + command.config = { findCommand } + + auditLogger.getAuditLogEvent.mockImplementation((flags, project, event) => null) + + await command.run() + expect(command.error).toHaveBeenCalledTimes(1) + expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) + expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) }) test('Should app undeploy successfully even if Audit Log Service is not available', async () => { @@ -598,6 +641,5 @@ describe('run', () => { expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(2) - expect(command.log).toHaveBeenCalledWith(expect.stringMatching('Error: Audit Log Service Error: Failed to send audit log event for deployment.')) }) }) diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index e46ba96f..ab44a71b 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -37,7 +37,6 @@ const appHelper = require('../../../src/lib/app-helper') const aioConfig = require('@adobe/aio-lib-core-config') const libEnv = require('@adobe/aio-lib-env') const libIms = require('@adobe/aio-lib-ims') -const { exec } = require('child_process') jest.mock('child_process', () => ({ exec: jest.fn() @@ -995,60 +994,72 @@ describe('object values', () => { }) describe('checkifAccessTokenExists', () => { - let consoleLogSpy, consoleWarnSpy, consoleInfoSpy, consoleErrorSpy - - beforeEach(() => { - consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { }) - consoleWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => { }) - consoleInfoSpy = jest.spyOn(console, 'info').mockImplementation(() => { }) - consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { }) - }) - afterEach(() => { jest.restoreAllMocks() }) test('should return true when access token is found', async () => { - exec.mockImplementation((command, callback) => { - callback(null, { stdout: 'mock_access_token', stderr: '' }) + execa.mockImplementationOnce((cmd, args, options) => { + expect(cmd).toEqual('aio') + expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) + return Promise.resolve({ + stdout: 'mock_access_token' + }) }) const result = await appHelper.checkifAccessTokenExists() - expect(result).toBe(true) - expect(consoleLogSpy).toHaveBeenCalledWith('Access token found: mock_access_token') }) test('should return false when access token is not found', async () => { - exec.mockImplementation((command, callback) => { - callback(null, { stdout: '', stderr: '' }) + execa.mockImplementationOnce((cmd, args, options) => { + expect(cmd).toEqual('aio') + expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) + return Promise.resolve({ + stdout: '' + }) }) const result = await appHelper.checkifAccessTokenExists() expect(result).toBe(false) - expect(consoleInfoSpy).toHaveBeenCalledWith('No token found') }) - test('should return false and warn when there is an stderr', async () => { - exec.mockImplementation((command, callback) => { - callback(null, { stdout: 'mock_access_token', stderr: 'Some error occurred' }) + test('should return false when stdout is null', async () => { + execa.mockImplementationOnce((cmd, args, options) => { + expect(cmd).toEqual('aio') + expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) + return Promise.resolve({ + stdout: null + }) }) const result = await appHelper.checkifAccessTokenExists() expect(result).toBe(false) - expect(consoleWarnSpy).toHaveBeenCalledWith('Warning: Some error occurred') }) - test('should return false when an error occurs', async () => { - exec.mockImplementation((command, callback) => { - callback(new Error('Failed to execute command')) + test('should return false and warn when there is an stderr', async () => { + execa.mockImplementationOnce((cmd, args, options) => { + expect(cmd).toEqual('aio') + expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) + return Promise.resolve({ + stderr: 'error_got_null' + }) }) const result = await appHelper.checkifAccessTokenExists() expect(result).toBe(false) - expect(consoleErrorSpy).toHaveBeenCalledWith('Error retrieving token: Failed to execute command') + }) + + test('should return false when an error occurs', async () => { + execa.mockImplementationOnce((cmd, args, options) => { + expect(cmd).toEqual('aio') + expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) + return Promise.reject(new Error('error_got_null')) + }) + const result = await appHelper.checkifAccessTokenExists() + expect(result).toBe(false) }) }) diff --git a/test/commands/lib/audit-logger.test.js b/test/commands/lib/audit-logger.test.js index 2e178d3d..ec05f758 100644 --- a/test/commands/lib/audit-logger.test.js +++ b/test/commands/lib/audit-logger.test.js @@ -72,7 +72,7 @@ test('sendAuditLogs with valid params', async () => { } await auditLogger.sendAuditLogs(mockToken, mockLogEvent, mockEnv) expect(fetch).toHaveBeenCalledTimes(1) - expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS[mockEnv], options) + expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENDPOINTS[mockEnv], options) }) test('sendAuditLogs with default params', async () => { @@ -87,7 +87,7 @@ test('sendAuditLogs with default params', async () => { } await auditLogger.sendAuditLogs(mockToken, mockLogEvent) expect(fetch).toHaveBeenCalledTimes(1) - expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS.prod, options) + expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENDPOINTS.prod, options) }) test('should take prod endpoint if calling sendAuditLogs with non-exisiting env', async () => { @@ -102,7 +102,7 @@ test('should take prod endpoint if calling sendAuditLogs with non-exisiting env' } await auditLogger.sendAuditLogs(mockToken, mockLogEvent, 'dev') expect(fetch).toHaveBeenCalledTimes(1) - expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS.prod, options) + expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENDPOINTS.prod, options) }) test('sendAuditLogs error response', async () => { @@ -117,7 +117,7 @@ test('sendAuditLogs error response', async () => { } await expect(auditLogger.sendAuditLogs(mockToken, mockLogEvent, mockEnv)).rejects.toThrow('Failed to send audit log - 400') expect(fetch).toHaveBeenCalledTimes(1) - expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENPOINTS[mockEnv], options) + expect(fetch).toHaveBeenCalledWith(auditLogger.AUDIT_SERVICE_ENDPOINTS[mockEnv], options) }) describe('getAuditLogEvent', () => { From d85786d903d6ce98c215c4e2e026d8a7bbd6d3cd Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Mon, 21 Oct 2024 18:07:46 +0530 Subject: [PATCH 04/11] fixed PR comments --- src/commands/app/deploy.js | 9 +---- src/commands/app/undeploy.js | 8 +---- src/lib/app-helper.js | 13 +++---- test/commands/app/deploy.test.js | 53 ++++------------------------ test/commands/app/undeploy.test.js | 51 +++----------------------- test/commands/lib/app-helper.test.js | 51 +++----------------------- 6 files changed, 21 insertions(+), 164 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index b14cf803..a2cad022 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -35,14 +35,7 @@ class Deploy extends BuildCommand { flags['web-assets'] = flags['web-assets'] && !flags.action flags.publish = flags.publish && !flags.action - const isValidCommand = this.config.findCommand('config:get') - - if (!isValidCommand) { - this.error('The config:get command is not available. Please update the aio-cli to the latest version.') - } - - const doesTokenExists = isValidCommand ? await checkifAccessTokenExists() : false - + const doesTokenExists = await checkifAccessTokenExists() const deployConfigs = await this.getAppExtConfigs(flags) const keys = Object.keys(deployConfigs) const values = Object.values(deployConfigs) diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index fc162411..fc87329c 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -26,13 +26,7 @@ class Undeploy extends BaseCommand { // cli input const { flags } = await this.parse(Undeploy) - const isValidCommand = this.config.findCommand('config:get') - - if (!isValidCommand) { - this.error('The config:get command is not available. Please update the aio-cli to the latest version.') - } - - const doesTokenExists = isValidCommand ? await checkifAccessTokenExists() : false + const doesTokenExists = await checkifAccessTokenExists() const undeployConfigs = await this.getAppExtConfigs(flags) let libConsoleCLI diff --git a/src/lib/app-helper.js b/src/lib/app-helper.js index 64f30f8b..742cb229 100644 --- a/src/lib/app-helper.js +++ b/src/lib/app-helper.js @@ -574,16 +574,11 @@ function getObjectValue (obj, key) { */ const checkifAccessTokenExists = async () => { try { - const { stdout, stderr } = await execa('aio', ['config', 'get', 'ims.contexts.cli.access_token.token']) - if (stderr) { - console.warn(`Warning: ${stderr}`) - return false - } - if (!stdout || stdout === '') { - console.info('No token found') - return false + const token = aioConfig.get('ims.contexts.cli.access_token.token') + if (token) { + return true } - return true + return false } catch (error) { console.error(`Error retrieving token: ${error.message}`) return false diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index ba729819..3d48f3eb 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -280,7 +280,7 @@ describe('run', () => { command.appConfig = cloneDeep(mockConfigData) command.appConfig.actions = { dist: 'actions' } command.appConfig.web.distProd = 'dist' - command.config = { runCommand: jest.fn(), runHook: jest.fn(), findCommand: jest.fn().mockReturnValue({}) } + command.config = { runCommand: jest.fn(), runHook: jest.fn() } command.buildOneExt = jest.fn() command.getAppExtConfigs = jest.fn() command.getLibConsoleCLI = jest.fn(() => mockLibConsoleCLI) @@ -1195,8 +1195,7 @@ describe('run', () => { test('does NOT fire `event` hooks when feature flag is NOT enabled', async () => { const runHook = jest.fn() - const findCommand = jest.fn().mockReturnValueOnce({ enabled: false }) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) command.argv = [] await command.run() @@ -1207,8 +1206,7 @@ describe('run', () => { test('DOES fire `event` hooks when feature flag IS enabled', async () => { const runHook = jest.fn() - const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -1221,8 +1219,7 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1241,8 +1238,7 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1264,8 +1260,7 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - const findCommand = jest.fn().mockReturnValueOnce({ enabled: true }) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-deploy-event-reg', expect.any(Object)) @@ -1467,40 +1462,4 @@ describe('run', () => { expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) }) - - test('Should not send audit logs, if findComand does not exist in app deploy', async () => { - const mockToken = 'mocktoken' - const mockEnv = 'stage' - const mockOrg = 'mockorg' - const mockProject = 'mockproject' - const mockWorkspaceId = 'mockworkspaceid' - const mockWorkspaceName = 'mockworkspacename' - helpers.getCliInfo.mockResolvedValueOnce({ - accessToken: mockToken, - env: mockEnv - }) - command.getFullConfig = jest.fn().mockReturnValue({ - aio: { - project: { - id: mockProject, - org: { - id: mockOrg - }, - workspace: { - id: mockWorkspaceId, - name: mockWorkspaceName - } - } - } - }) - command.config = { runCommand: jest.fn(), runHook: jest.fn(), findCommand: jest.fn().mockReturnValue(null) } - command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) - - await command.run() - expect(command.error).toHaveBeenCalledTimes(1) - expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) - expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) - expect(auditLogger.sendAuditLogs.mock.calls.length).toBeLessThanOrEqual(0) - expect(auditLogger.sendAuditLogs).not.toHaveBeenCalledWith() - }) }) diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index 28054d99..235c223a 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -145,10 +145,7 @@ describe('run', () => { command.appConfig = mockConfigData command.config = { runCommand: jest.fn(), - runHook: jest.fn(), - findCommand: jest.fn().mockReturnValue({ - enabled: true - }) + runHook: jest.fn() } command.getLibConsoleCLI = jest.fn(() => mockLibConsoleCLI) command.getAppExtConfigs = jest.fn() @@ -431,8 +428,7 @@ describe('run', () => { test('does NOT fire `event` hooks when feature flag is NOT enabled', async () => { const runHook = jest.fn() - const findCommand = jest.fn().mockReturnValueOnce({}) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) command.argv = [] await command.run() @@ -442,8 +438,7 @@ describe('run', () => { test('does NOT fire `event` hooks when events flag is false', async () => { const runHook = jest.fn() - const findCommand = jest.fn().mockReturnValueOnce({}) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -456,8 +451,7 @@ describe('run', () => { successes: ['ok'], failures: [] }) - const findCommand = jest.fn().mockReturnValueOnce({}) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(command.error).not.toHaveBeenCalled() @@ -470,8 +464,7 @@ describe('run', () => { successes: [], failures: [{ plugin: { name: 'ifailedu' }, error: 'some error' }] }) - const findCommand = jest.fn().mockReturnValueOnce({}) - command.config = { runHook, findCommand } + command.config = { runHook } command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() expect(runHook).toHaveBeenCalledWith('pre-undeploy-event-reg', expect.any(Object)) @@ -574,40 +567,6 @@ describe('run', () => { expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) }) - test('Do not Send audit logs for successful app undeploy, if no findCommand is not present', async () => { - const mockOrg = 'mockorg' - const mockProject = 'mockproject' - const mockWorkspaceId = 'mockworkspaceid' - const mockWorkspaceName = 'mockworkspacename' - - command.getFullConfig = jest.fn().mockReturnValue({ - aio: { - project: { - id: mockProject, - org: { - id: mockOrg - }, - workspace: { - id: mockWorkspaceId, - name: mockWorkspaceName - } - } - } - }) - command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) - - const findCommand = jest.fn().mockReturnValueOnce(null) - command.config = { findCommand } - - auditLogger.getAuditLogEvent.mockImplementation((flags, project, event) => null) - - await command.run() - expect(command.error).toHaveBeenCalledTimes(1) - expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) - expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) - expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(0) - }) - test('Should app undeploy successfully even if Audit Log Service is not available', async () => { const mockOrg = 'mockorg' const mockProject = 'mockproject' diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index ab44a71b..7f69e85e 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -999,54 +999,13 @@ describe('checkifAccessTokenExists', () => { }) test('should return true when access token is found', async () => { - execa.mockImplementationOnce((cmd, args, options) => { - expect(cmd).toEqual('aio') - expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) - return Promise.resolve({ - stdout: 'mock_access_token' - }) - }) - + aioConfig.get.mockReturnValueOnce('dummytesttoken') const result = await appHelper.checkifAccessTokenExists() expect(result).toBe(true) }) test('should return false when access token is not found', async () => { - execa.mockImplementationOnce((cmd, args, options) => { - expect(cmd).toEqual('aio') - expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) - return Promise.resolve({ - stdout: '' - }) - }) - - const result = await appHelper.checkifAccessTokenExists() - - expect(result).toBe(false) - }) - - test('should return false when stdout is null', async () => { - execa.mockImplementationOnce((cmd, args, options) => { - expect(cmd).toEqual('aio') - expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) - return Promise.resolve({ - stdout: null - }) - }) - - const result = await appHelper.checkifAccessTokenExists() - - expect(result).toBe(false) - }) - - test('should return false and warn when there is an stderr', async () => { - execa.mockImplementationOnce((cmd, args, options) => { - expect(cmd).toEqual('aio') - expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) - return Promise.resolve({ - stderr: 'error_got_null' - }) - }) + aioConfig.get.mockReturnValueOnce(null) const result = await appHelper.checkifAccessTokenExists() @@ -1054,10 +1013,8 @@ describe('checkifAccessTokenExists', () => { }) test('should return false when an error occurs', async () => { - execa.mockImplementationOnce((cmd, args, options) => { - expect(cmd).toEqual('aio') - expect(args).toEqual(['config', 'get', 'ims.contexts.cli.access_token.token']) - return Promise.reject(new Error('error_got_null')) + aioConfig.get.mockImplementationOnce(() => { + throw new Error('some error') }) const result = await appHelper.checkifAccessTokenExists() expect(result).toBe(false) From 9f4337c295e7a5a9ab0871c21d893aa9b4590182 Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Mon, 21 Oct 2024 19:22:29 +0530 Subject: [PATCH 05/11] ticket ACNA-3240 : commented out code --- src/commands/app/deploy.js | 28 +++++++++++++++++----------- src/commands/app/undeploy.js | 28 +++++++++++++++++----------- test/commands/app/deploy.test.js | 6 ++++-- test/commands/app/undeploy.test.js | 4 ++-- 4 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index a2cad022..89c14c3e 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -94,16 +94,21 @@ class Deploy extends BuildCommand { } // 3. send deploy log event - const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') - if (logEvent && loginCredentials) { - try { - await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) - } catch (error) { - this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) - } - } else { - this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) - } + + // TODO: We will need this code running when Once Runtime events start showing up, + // we'll decide on the fate of the 'Starting deployment/undeplpyment' messages. + // JIRA: https://jira.corp.adobe.com/browse/ACNA-3240 + + // const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') + // if (logEvent && loginCredentials) { + // try { + // await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) + // } catch (error) { + // this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + // } + // } else { + // this.log(chalk.red(chalk.bold('Warning: No valid config data found to send audit log event for deployment.'))) + // } // 4. deploy actions and web assets for each extension // Possible improvements: @@ -119,7 +124,8 @@ class Deploy extends BuildCommand { if (assetDeployedLogEvent && loginCredentials) { assetDeployedLogEvent.data.opItems = opItems try { - await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) + // only send logs in case of web-assets deployment + await sendAuditLogs(loginCredentials.accessToken, assetDeployedLogEvent, loginCredentials.env) } catch (error) { this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) } diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index fc87329c..16d11c2d 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -49,24 +49,30 @@ class Undeploy extends BaseCommand { try { const aioConfig = (await this.getFullConfig()).aio const loginCredentials = doesTokenExists ? await getCliInfo() : null - const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_UNDEPLOY') - // 1.1. send audit log event for successful undeploy - if (logEvent && loginCredentials) { - try { - await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) - } catch (error) { - this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.') - } - } else { - this.warn('Warning: No valid config data found to send audit log event for un-deployment.') - } + // TODO: We will need this code running when Once Runtime events start showing up, + // we'll decide on the fate of the 'Starting deployment/undeplpyment' messages. + // JIRA: https://jira.corp.adobe.com/browse/ACNA-3240 + + // const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_UNDEPLOY') + + // // 1.1. send audit log event for successful undeploy + // if (logEvent && loginCredentials) { + // try { + // await sendAuditLogs(loginCredentials.accessToken, logEvent, loginCredentials.env) + // } catch (error) { + // this.warn('Warning: Audit Log Service Error: Failed to send audit log event for un-deployment.') + // } + // } else { + // this.warn('Warning: No valid config data found to send audit log event for un-deployment.') + // } for (let i = 0; i < keys.length; ++i) { const k = keys[i] const v = values[i] await this.undeployOneExt(k, v, flags, spinner) const assetUndeployLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_UNDEPLOYED') + // send logs for case of web-assets undeployment if (assetUndeployLogEvent && loginCredentials) { try { await sendAuditLogs(loginCredentials.accessToken, assetUndeployLogEvent, loginCredentials.env) diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index 3d48f3eb..2e5cfd26 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -1299,7 +1299,7 @@ describe('run', () => { expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) - expect(auditLogger.sendAuditLogs.mock.calls.length).toBeLessThanOrEqual(2) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(1) expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) @@ -1337,6 +1337,7 @@ describe('run', () => { expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(0) }) test('Do not send audit logs for successful app deploy, if no-login case', async () => { @@ -1374,6 +1375,7 @@ describe('run', () => { expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(0) }) test('Send audit logs for successful app deploy + web assets', async () => { @@ -1457,7 +1459,7 @@ describe('run', () => { expect(command.log).toHaveBeenCalledWith( expect.stringContaining('Successful deployment 🏄') ) - expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(2) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(1) expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.deployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.deployWeb).toHaveBeenCalledTimes(1) diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index 235c223a..f0575be1 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -501,7 +501,7 @@ describe('run', () => { expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) - expect(auditLogger.sendAuditLogs.mock.calls.length).toBeGreaterThan(1) + expect(auditLogger.sendAuditLogs.mock.calls.length).toBe(1) expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) @@ -599,6 +599,6 @@ describe('run', () => { expect(command.error).toHaveBeenCalledTimes(0) expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(1) expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(1) - expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(2) + expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(1) }) }) From 65124f3f558fa8d8cf5da67af87297ffbb1a3557 Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Wed, 13 Nov 2024 02:30:54 +0530 Subject: [PATCH 06/11] e2e test failures fix --- src/lib/audit-logger.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/audit-logger.js b/src/lib/audit-logger.js index b6bd4eec..c2f4d28b 100644 --- a/src/lib/audit-logger.js +++ b/src/lib/audit-logger.js @@ -60,7 +60,6 @@ async function sendAuditLogs (accessToken, logEvent, env = 'prod') { * @returns {object} logEvent */ function getAuditLogEvent (flags, project, event) { - let logEvent, logStrMsg if (project && project.org && project.workspace) { if (event === 'AB_APP_DEPLOY') { From 31b7a9e7599d639ba2d312530d8e788d15bcc269 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 14 Nov 2024 17:06:02 -0800 Subject: [PATCH 07/11] do not force login if deploy with --no-publish (#819) --- src/commands/app/deploy.js | 3 +-- src/lib/app-helper.js | 31 +++++++++++++++++++++------- test/commands/lib/app-helper.test.js | 7 +++++++ 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index ba3333bf..3b8a2224 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -43,7 +43,6 @@ class Deploy extends BuildCommand { // if there are no extensions, then set publish to false flags.publish = flags.publish && !isStandaloneApp - if ( (!flags.publish && !flags['web-assets'] && !flags.actions) ) { @@ -53,7 +52,7 @@ class Deploy extends BuildCommand { try { const aioConfig = (await this.getFullConfig()).aio - const cliDetails = await getCliInfo() + const cliDetails = await getCliInfo(flags.publish) // 1. update log forwarding configuration // note: it is possible that .aio file does not exist, which means there is no local lg config diff --git a/src/lib/app-helper.js b/src/lib/app-helper.js index a323c2c6..c2b4b3c5 100644 --- a/src/lib/app-helper.js +++ b/src/lib/app-helper.js @@ -180,15 +180,30 @@ function wrapError (err) { return new Error(message) } -/** @private */ -async function getCliInfo () { - await context.setCli({ 'cli.bare-output': true }, false) // set this globally - +/** + * getCliInfo + * + * @private + * + * @param {boolean} useForce - if true, user will be forced to login if not already logged in + * @returns {Promise<{accessToken: string, env: string}>} accessToken and env +*/ +async function getCliInfo (useForce = true) { const env = getCliEnv() - - aioLogger.debug(`Retrieving CLI Token using env=${env}`) - const accessToken = await getToken(CLI) - + let accessToken + await context.setCli({ 'cli.bare-output': true }, false) // set this globally + if (useForce) { + aioLogger.debug('Retrieving CLI Token using force=true') + accessToken = await getToken(CLI) + } else { + aioLogger.debug('Retrieving CLI Token using force=false') + // in this case, the user might be logged in, but we don't want to force them + // we just check the config for the token ( we still use the cli context so we don't need to know + // the inner workings of ims-lib and where it stores access tokens) + // todo: this is a workaround, we should have a better way to check if the user is logged in (in ims-lib) + const contextConfig = await context.getCli() + accessToken = contextConfig?.access_token?.token + } return { accessToken, env } } diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index cfc59a99..c6f92ce9 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -906,6 +906,13 @@ describe('getCliInfo', () => { { accessToken: 'stoken', env: 'stage' } ) }) + test('useForceFalse', async () => { + libEnv.getCliEnv.mockReturnValue('prod') + libIms.getToken.mockResolvedValue('asdasd') + const res = await appHelper.getCliInfo(false) + expect(res).toEqual({ accessToken: undefined, env: 'prod' }) + expect(libIms.getToken).toHaveBeenCalledTimes(0) + }) }) describe('createWebExportFilter', () => { From fff25048d2a506acd825761f049a103e490821f8 Mon Sep 17 00:00:00 2001 From: Jesse MacFadyen Date: Thu, 14 Nov 2024 17:07:57 -0800 Subject: [PATCH 08/11] 13.1.1 --- README.md | 58 ++++++++++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d978a845..d17df80e 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ DESCRIPTION Create, run, test, and deploy Adobe I/O Apps ``` -_See code: [src/commands/app/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/index.js)_ +_See code: [src/commands/app/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/index.js)_ ## `aio app add` @@ -90,7 +90,7 @@ DESCRIPTION Add a new component to an existing Adobe I/O App ``` -_See code: [src/commands/app/add/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/index.js)_ +_See code: [src/commands/app/add/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/index.js)_ ## `aio app add action` @@ -115,7 +115,7 @@ ALIASES $ aio app add actions ``` -_See code: [src/commands/app/add/action.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/action.js)_ +_See code: [src/commands/app/add/action.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/action.js)_ ## `aio app add ci` @@ -133,7 +133,7 @@ DESCRIPTION Add CI files ``` -_See code: [src/commands/app/add/ci.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/ci.js)_ +_See code: [src/commands/app/add/ci.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/ci.js)_ ## `aio app add event` @@ -158,7 +158,7 @@ ALIASES $ aio app add events ``` -_See code: [src/commands/app/add/event.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/event.js)_ +_See code: [src/commands/app/add/event.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/event.js)_ ## `aio app add extension` @@ -184,7 +184,7 @@ ALIASES $ aio app add extensions ``` -_See code: [src/commands/app/add/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/extension.js)_ +_See code: [src/commands/app/add/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/extension.js)_ ## `aio app add service` @@ -208,7 +208,7 @@ ALIASES $ aio app add services ``` -_See code: [src/commands/app/add/service.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/service.js)_ +_See code: [src/commands/app/add/service.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/service.js)_ ## `aio app add web-assets` @@ -229,7 +229,7 @@ DESCRIPTION Add web assets support ``` -_See code: [src/commands/app/add/web-assets.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/add/web-assets.js)_ +_See code: [src/commands/app/add/web-assets.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/add/web-assets.js)_ ## `aio app build` @@ -259,7 +259,7 @@ DESCRIPTION Use the --force-build flag to force a build even if one already exists. ``` -_See code: [src/commands/app/build.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/build.js)_ +_See code: [src/commands/app/build.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/build.js)_ ## `aio app create [PATH]` @@ -281,7 +281,7 @@ DESCRIPTION Create a new Adobe I/O App with default parameters ``` -_See code: [src/commands/app/create.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/create.js)_ +_See code: [src/commands/app/create.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/create.js)_ ## `aio app delete` @@ -299,7 +299,7 @@ DESCRIPTION Delete a component from an existing Adobe I/O App ``` -_See code: [src/commands/app/delete/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/index.js)_ +_See code: [src/commands/app/delete/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/index.js)_ ## `aio app delete action [ACTION-NAME]` @@ -325,7 +325,7 @@ ALIASES $ aio app delete actions ``` -_See code: [src/commands/app/delete/action.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/action.js)_ +_See code: [src/commands/app/delete/action.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/action.js)_ ## `aio app delete ci` @@ -344,7 +344,7 @@ DESCRIPTION Delete existing CI files ``` -_See code: [src/commands/app/delete/ci.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/ci.js)_ +_See code: [src/commands/app/delete/ci.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/ci.js)_ ## `aio app delete extension` @@ -370,7 +370,7 @@ ALIASES $ aio app delete extensions ``` -_See code: [src/commands/app/delete/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/extension.js)_ +_See code: [src/commands/app/delete/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/extension.js)_ ## `aio app delete service` @@ -394,7 +394,7 @@ ALIASES $ aio app delete services ``` -_See code: [src/commands/app/delete/service.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/service.js)_ +_See code: [src/commands/app/delete/service.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/service.js)_ ## `aio app delete web-assets` @@ -413,7 +413,7 @@ DESCRIPTION Delete existing web assets ``` -_See code: [src/commands/app/delete/web-assets.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/delete/web-assets.js)_ +_See code: [src/commands/app/delete/web-assets.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/delete/web-assets.js)_ ## `aio app deploy` @@ -459,7 +459,7 @@ DESCRIPTION Use the --force-deploy flag to force deploy changes, regardless of production Workspace being published in Exchange. ``` -_See code: [src/commands/app/deploy.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/deploy.js)_ +_See code: [src/commands/app/deploy.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/deploy.js)_ ## `aio app get-url [ACTION]` @@ -482,7 +482,7 @@ DESCRIPTION Get action URLs ``` -_See code: [src/commands/app/get-url.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/get-url.js)_ +_See code: [src/commands/app/get-url.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/get-url.js)_ ## `aio app info` @@ -504,7 +504,7 @@ DESCRIPTION Display settings/configuration in use by an Adobe I/O App ``` -_See code: [src/commands/app/info.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/info.js)_ +_See code: [src/commands/app/info.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/info.js)_ ## `aio app init [PATH]` @@ -543,7 +543,7 @@ DESCRIPTION Create a new Adobe I/O App ``` -_See code: [src/commands/app/init.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/init.js)_ +_See code: [src/commands/app/init.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/init.js)_ ## `aio app install PATH` @@ -566,7 +566,7 @@ DESCRIPTION This command will support installing apps packaged by 'aio app pack'. ``` -_See code: [src/commands/app/install.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/install.js)_ +_See code: [src/commands/app/install.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/install.js)_ ## `aio app list` @@ -584,7 +584,7 @@ DESCRIPTION List components for Adobe I/O App ``` -_See code: [src/commands/app/list/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/list/index.js)_ +_See code: [src/commands/app/list/index.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/list/index.js)_ ## `aio app list extension` @@ -609,7 +609,7 @@ ALIASES $ aio app list extensions ``` -_See code: [src/commands/app/list/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/list/extension.js)_ +_See code: [src/commands/app/list/extension.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/list/extension.js)_ ## `aio app logs` @@ -633,7 +633,7 @@ DESCRIPTION Fetch logs for an Adobe I/O App ``` -_See code: [src/commands/app/logs.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/logs.js)_ +_See code: [src/commands/app/logs.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/logs.js)_ ## `aio app pack [PATH]` @@ -655,7 +655,7 @@ DESCRIPTION This command will support packaging apps for redistribution. ``` -_See code: [src/commands/app/pack.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/pack.js)_ +_See code: [src/commands/app/pack.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/pack.js)_ ## `aio app run` @@ -679,7 +679,7 @@ DESCRIPTION Run an Adobe I/O App ``` -_See code: [src/commands/app/run.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/run.js)_ +_See code: [src/commands/app/run.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/run.js)_ ## `aio app test` @@ -707,7 +707,7 @@ DESCRIPTION If the extension has a hook called 'test' in its 'ext.config.yaml', the script specified will be run instead. ``` -_See code: [src/commands/app/test.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/test.js)_ +_See code: [src/commands/app/test.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/test.js)_ ## `aio app undeploy` @@ -732,7 +732,7 @@ DESCRIPTION Undeploys an Adobe I/O App ``` -_See code: [src/commands/app/undeploy.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/undeploy.js)_ +_See code: [src/commands/app/undeploy.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/undeploy.js)_ ## `aio app use [CONFIG_FILE_PATH]` @@ -779,5 +779,5 @@ DESCRIPTION page in https://developer.adobe.com/console/ ``` -_See code: [src/commands/app/use.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.0/src/commands/app/use.js)_ +_See code: [src/commands/app/use.js](https://github.com/adobe/aio-cli-plugin-app/blob/13.1.1/src/commands/app/use.js)_ diff --git a/package.json b/package.json index 8fcb9dfb..5454916d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@adobe/aio-cli-plugin-app", "description": "Create, Build and Deploy Adobe I/O Applications", - "version": "13.1.0", + "version": "13.1.1", "author": "Adobe Inc.", "bugs": "https://github.com/adobe/aio-cli-plugin-app/issues", "dependencies": { From 0f18ab0d3985821ef488b9c34f1d149f4052730f Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Thu, 21 Nov 2024 19:13:00 +0530 Subject: [PATCH 09/11] tested for standalone scenario --- src/commands/app/deploy.js | 7 +++---- src/commands/app/undeploy.js | 4 ++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index 45b7cdbc..a3ce10b2 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -18,7 +18,7 @@ const BaseCommand = require('../../BaseCommand') const BuildCommand = require('./build') const webLib = require('@adobe/aio-lib-web') const { Flags } = require('@oclif/core') -const { createWebExportFilter, runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getCliInfo, checkifAccessTokenExists } = require('../../lib/app-helper') +const { createWebExportFilter, runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getCliInfo } = require('../../lib/app-helper') const rtLib = require('@adobe/aio-lib-runtime') const LogForwarding = require('../../lib/log-forwarding') const { sendAuditLogs, getAuditLogEvent, getFilesCountWithExtension } = require('../../lib/audit-logger') @@ -36,7 +36,6 @@ class Deploy extends BuildCommand { // Deploy only a specific action, the flags can be specified multiple times, this will set --no-publish flags.publish = flags.publish && !flags.action - const doesTokenExists = await checkifAccessTokenExists() const deployConfigs = await this.getAppExtConfigs(flags) const keys = Object.keys(deployConfigs) const values = Object.values(deployConfigs) @@ -101,7 +100,7 @@ class Deploy extends BuildCommand { // JIRA: https://jira.corp.adobe.com/browse/ACNA-3240 // const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_DEPLOY') - // if (logEvent && cliDetails) { + // if (logEvent && cliDetails?.accessToken) { // try { // await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) // } catch (error) { @@ -122,7 +121,7 @@ class Deploy extends BuildCommand { if (v.app.hasFrontend && flags['web-assets']) { const opItems = getFilesCountWithExtension(v.web.distProd) const assetDeployedLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_DEPLOYED') - if (assetDeployedLogEvent && cliDetails) { + if (assetDeployedLogEvent && cliDetails?.accessToken) { assetDeployedLogEvent.data.opItems = opItems try { // only send logs in case of web-assets deployment diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index 3328f7c6..aa9d0bca 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -55,7 +55,7 @@ class Undeploy extends BaseCommand { // const logEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_UNDEPLOY') // // 1.1. send audit log event for successful undeploy - // if (logEvent && cliDetails) { + // if (logEvent && cliDetails.accessToken) { // try { // await sendAuditLogs(cliDetails.accessToken, logEvent, cliDetails.env) // } catch (error) { @@ -71,7 +71,7 @@ class Undeploy extends BaseCommand { await this.undeployOneExt(k, v, flags, spinner) const assetUndeployLogEvent = getAuditLogEvent(flags, aioConfig.project, 'AB_APP_ASSETS_UNDEPLOYED') // send logs for case of web-assets undeployment - if (assetUndeployLogEvent && cliDetails) { + if (assetUndeployLogEvent && cliDetails?.accessToken) { try { await sendAuditLogs(cliDetails.accessToken, assetUndeployLogEvent, cliDetails.env) } catch (error) { From 3f34f84aa836d41b3b0a4f78c0ef24f2e8d765b4 Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Thu, 21 Nov 2024 20:43:46 +0530 Subject: [PATCH 10/11] removed non-required token check function && fixed the undeploy no-login/standalone case --- src/commands/app/undeploy.js | 20 +++++++++++++------- src/lib/app-helper.js | 21 +-------------------- test/commands/app/deploy.test.js | 11 ++++------- test/commands/app/undeploy.test.js | 11 ++++------- test/commands/lib/app-helper.test.js | 28 ---------------------------- 5 files changed, 22 insertions(+), 69 deletions(-) diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index aa9d0bca..fc80f4fc 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -22,20 +22,26 @@ const rtLib = require('@adobe/aio-lib-runtime') const { sendAuditLogs, getAuditLogEvent } = require('../../lib/audit-logger') class Undeploy extends BaseCommand { - async run() { + async run () { // cli input const { flags } = await this.parse(Undeploy) const undeployConfigs = await this.getAppExtConfigs(flags) + + // 1. undeploy actions and web assets for each extension + const keys = Object.keys(undeployConfigs) + const values = Object.values(undeployConfigs) + + // if it is standalone app, unpublish it without token + const isStandaloneApp = (keys.length === 1 && keys[0] === 'application') + flags.unpublish = flags.unpublish && !isStandaloneApp + let libConsoleCLI if (flags.unpublish) { // force login at beginning (if required) libConsoleCLI = await this.getLibConsoleCLI() } - // 1. undeploy actions and web assets for each extension - const keys = Object.keys(undeployConfigs) - const values = Object.values(undeployConfigs) if ( (!flags.unpublish && !flags['web-assets'] && !flags.actions) @@ -81,7 +87,7 @@ class Undeploy extends BaseCommand { } // 1.2. unpublish extension manifest - if (flags.unpublish && !(keys.length === 1 && keys[0] === 'application')) { + if (flags.unpublish) { const payload = await this.unpublishExtensionPoints(libConsoleCLI, undeployConfigs, aioConfig, flags['force-unpublish']) this.log(chalk.blue(chalk.bold(`New Extension Point(s) in Workspace '${aioConfig.project.workspace.name}': '${Object.keys(payload.endpoints)}'`))) } else { @@ -96,7 +102,7 @@ class Undeploy extends BaseCommand { this.log(chalk.green(chalk.bold('Undeploy done !'))) } - async undeployOneExt(extName, config, flags, spinner) { + async undeployOneExt (extName, config, flags, spinner) { const onProgress = !flags.verbose ? info => { spinner.text = info @@ -158,7 +164,7 @@ class Undeploy extends BaseCommand { } } - async unpublishExtensionPoints(libConsoleCLI, deployConfigs, aioConfig, force) { + async unpublishExtensionPoints (libConsoleCLI, deployConfigs, aioConfig, force) { const payload = buildExtensionPointPayloadWoMetadata(deployConfigs) let res if (force) { diff --git a/src/lib/app-helper.js b/src/lib/app-helper.js index c99b5ab3..9b7c3c9e 100644 --- a/src/lib/app-helper.js +++ b/src/lib/app-helper.js @@ -582,24 +582,6 @@ function getObjectValue (obj, key) { return keys.filter(o => o.trim()).reduce((o, i) => o && getObjectProp(o, i), obj) } -/** - * Function to run `aio config get ims.contexts.cli.access_token.token` command and retrieve the token - * This function is used to check if the access token exists in the CLI context or not - * @returns {Promise} Resolves to the access token if it exists, else false - */ -const checkifAccessTokenExists = async () => { - try { - const token = aioConfig.get('ims.contexts.cli.access_token.token') - if (token) { - return true - } - return false - } catch (error) { - console.error(`Error retrieving token: ${error.message}`) - return false - } -} - module.exports = { getObjectValue, getObjectProp, @@ -629,6 +611,5 @@ module.exports = { buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, atLeastOne, - deleteUserConfig, - checkifAccessTokenExists + deleteUserConfig } diff --git a/test/commands/app/deploy.test.js b/test/commands/app/deploy.test.js index fcb656bf..c22e39d6 100644 --- a/test/commands/app/deploy.test.js +++ b/test/commands/app/deploy.test.js @@ -198,7 +198,6 @@ beforeEach(() => { } }) LogForwarding.init.mockResolvedValue(mockLogForwarding) - helpers.checkifAccessTokenExists.mockResolvedValue(true) }) test('exports', async () => { @@ -1366,18 +1365,19 @@ describe('run', () => { expect(auditLogger.sendAuditLogs).toHaveBeenCalledTimes(0) }) - test('Do not send audit logs for successful app deploy, if no-login case', async () => { - const mockToken = 'mocktoken' + test('Do not send audit logs for successful app deploy, if case of no token', async () => { + const mockToken = null const mockEnv = 'stage' const mockOrg = 'mockorg' const mockProject = 'mockproject' const mockWorkspaceId = 'mockworkspaceid' const mockWorkspaceName = 'mockworkspacename' + helpers.getCliInfo.mockResolvedValueOnce({ accessToken: mockToken, env: mockEnv }) - helpers.checkifAccessTokenExists.mockResolvedValueOnce(false) + command.getFullConfig = jest.fn().mockReturnValue({ aio: { project: { @@ -1392,9 +1392,6 @@ describe('run', () => { } } }) - - auditLogger.getAuditLogEvent.mockImplementation((flags, project, event) => null) - command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) await command.run() diff --git a/test/commands/app/undeploy.test.js b/test/commands/app/undeploy.test.js index f0575be1..ba908bb0 100644 --- a/test/commands/app/undeploy.test.js +++ b/test/commands/app/undeploy.test.js @@ -192,7 +192,8 @@ describe('run', () => { command.argv = ['--no-actions', '--no-web-assets'] await command.run() - expect(command.error).toHaveBeenCalledTimes(0) + expect(command.error).toHaveBeenCalledTimes(1) + expect(command.error).toHaveBeenCalledWith('Nothing to be done 🚫') expect(mockRuntimeLib.undeployActions).toHaveBeenCalledTimes(0) expect(mockWebLib.undeployWeb).toHaveBeenCalledTimes(0) @@ -479,8 +480,6 @@ describe('run', () => { const mockWorkspaceId = 'mockworkspaceid' const mockWorkspaceName = 'mockworkspacename' - helpers.checkifAccessTokenExists.mockResolvedValue(true) - command.getFullConfig = jest.fn().mockReturnValue({ aio: { project: { @@ -505,14 +504,12 @@ describe('run', () => { expect(auditLogger.sendAuditLogs).toHaveBeenCalledWith(mockToken, expect.objectContaining({ orgId: mockOrg, projectId: mockProject, workspaceId: mockWorkspaceId, workspaceName: mockWorkspaceName }), mockEnv) }) - test('Do not Send audit logs for successful app undeploy if no-login case', async () => { + test('Do not Send audit logs for successful app undeploy if case of no-token', async () => { const mockOrg = 'mockorg' const mockProject = 'mockproject' const mockWorkspaceId = 'mockworkspaceid' const mockWorkspaceName = 'mockworkspacename' - helpers.checkifAccessTokenExists.mockResolvedValueOnce(false) - command.getFullConfig = jest.fn().mockReturnValue({ aio: { project: { @@ -528,6 +525,7 @@ describe('run', () => { } }) command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) + helpers.getCliInfo.mockImplementationOnce(() => null) await command.run() expect(command.error).toHaveBeenCalledTimes(0) @@ -588,7 +586,6 @@ describe('run', () => { } }) command.getAppExtConfigs.mockResolvedValueOnce(createAppConfig(command.appConfig)) - helpers.checkifAccessTokenExists.mockResolvedValue(true) auditLogger.sendAuditLogs.mockRejectedValue({ message: 'Internal Server Error', diff --git a/test/commands/lib/app-helper.test.js b/test/commands/lib/app-helper.test.js index d4c91c73..26b8129f 100644 --- a/test/commands/lib/app-helper.test.js +++ b/test/commands/lib/app-helper.test.js @@ -999,31 +999,3 @@ describe('object values', () => { expect(appHelper.getObjectValue(obj)).toEqual(obj) }) }) - -describe('checkifAccessTokenExists', () => { - afterEach(() => { - jest.restoreAllMocks() - }) - - test('should return true when access token is found', async () => { - aioConfig.get.mockReturnValueOnce('dummytesttoken') - const result = await appHelper.checkifAccessTokenExists() - expect(result).toBe(true) - }) - - test('should return false when access token is not found', async () => { - aioConfig.get.mockReturnValueOnce(null) - - const result = await appHelper.checkifAccessTokenExists() - - expect(result).toBe(false) - }) - - test('should return false when an error occurs', async () => { - aioConfig.get.mockImplementationOnce(() => { - throw new Error('some error') - }) - const result = await appHelper.checkifAccessTokenExists() - expect(result).toBe(false) - }) -}) From 9a61a5792f6c5526399f4f2d2b23f28cd5d744cb Mon Sep 17 00:00:00 2001 From: Amulya Kashyap Date: Thu, 21 Nov 2024 20:47:54 +0530 Subject: [PATCH 11/11] added lint --- src/commands/app/deploy.js | 2 +- src/commands/app/undeploy.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/commands/app/deploy.js b/src/commands/app/deploy.js index a3ce10b2..c9ee40b3 100644 --- a/src/commands/app/deploy.js +++ b/src/commands/app/deploy.js @@ -127,7 +127,7 @@ class Deploy extends BuildCommand { // only send logs in case of web-assets deployment await sendAuditLogs(cliDetails.accessToken, assetDeployedLogEvent, cliDetails.env) } catch (error) { - this.log(chalk.red(chalk.bold('Error: Audit Log Service Error: Failed to send audit log event for deployment.'))) + this.warn('Error: Audit Log Service Error: Failed to send audit log event for deployment.') } } } diff --git a/src/commands/app/undeploy.js b/src/commands/app/undeploy.js index fc80f4fc..bf0503b2 100644 --- a/src/commands/app/undeploy.js +++ b/src/commands/app/undeploy.js @@ -42,7 +42,6 @@ class Undeploy extends BaseCommand { libConsoleCLI = await this.getLibConsoleCLI() } - if ( (!flags.unpublish && !flags['web-assets'] && !flags.actions) ) {