From 4eb1063c64741149884cb30095c234b8b6dcf851 Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 09:42:24 -0800 Subject: [PATCH 1/6] fix: client config generation respects sandbox config-out-dir option --- .changeset/strong-plums-explain.md | 5 +++ .../commands/sandbox/sandbox_command.test.ts | 34 +++++++++++++++- .../src/commands/sandbox/sandbox_command.ts | 39 ++++++++++--------- 3 files changed, 59 insertions(+), 19 deletions(-) create mode 100644 .changeset/strong-plums-explain.md diff --git a/.changeset/strong-plums-explain.md b/.changeset/strong-plums-explain.md new file mode 100644 index 0000000000..ef8dfdc0d0 --- /dev/null +++ b/.changeset/strong-plums-explain.md @@ -0,0 +1,5 @@ +--- +'@aws-amplify/backend-cli': patch +--- + +Change sandbox out-dir to config-out-dir and client config generation respects config-out-dir option diff --git a/packages/cli/src/commands/sandbox/sandbox_command.test.ts b/packages/cli/src/commands/sandbox/sandbox_command.test.ts index b48f28eaec..e4dc9b5229 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.test.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.test.ts @@ -105,7 +105,7 @@ void describe('sandbox command', () => { assert.match(output, /--dir-to-watch/); assert.match(output, /--exclude/); assert.match(output, /--format/); - assert.match(output, /--out-dir/); + assert.match(output, /--config-out-dir/); assert.equal(mockHandleProfile.mock.callCount(), 0); }); @@ -251,4 +251,36 @@ void describe('sandbox command', () => { sandboxProfile ); }); + + void it('fails if invalid config-out-dir is provided', async () => { + mock.method(fs, 'lstatSync', () => { + return { + isFile: () => false, + isDir: () => false, + }; + }); + const output = await commandRunner.runCommand( + 'sandbox --config-out-dir nonExistentDir' + ); + assert.match(output, /--config-out-dir nonExistentDir does not exist/); + }); + + void it('fails if a file is provided for config-out-dir', async (contextual) => { + mock.method(fs, 'lstatSync', () => { + return { + isFile: () => true, + isDir: () => false, + }; + }); + contextual.mock.method(fs, 'statSync', () => ({ + isDirectory: () => false, + })); + const output = await commandRunner.runCommand( + 'sandbox --config-out-dir existentFile' + ); + assert.match( + output, + /--config-out-dir existentFile is not a valid directory/ + ); + }); }); diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index 4db91a8f79..a6c83629f8 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -20,7 +20,7 @@ type SandboxCommandOptionsCamelCase = { exclude: string[] | undefined; name: string | undefined; format: ClientConfigFormat | undefined; - outDir: string | undefined; + configOutDir: string | undefined; profile: string | undefined; }; @@ -81,7 +81,8 @@ export class SandboxCommand // attaching event handlers const clientConfigLifecycleHandler = new ClientConfigLifecycleHandler( - this.clientConfigGeneratorAdapter + this.clientConfigGeneratorAdapter, + args['config-out-dir'] ); const eventHandlers = this.sandboxEventHandlerCreator?.({ sandboxName: this.sandboxName, @@ -94,7 +95,7 @@ export class SandboxCommand } const watchExclusions = args.exclude ?? []; const clientConfigWritePath = await getClientConfigPath( - args['out-dir'], + args['config-out-dir'], args.format ); watchExclusions.push(clientConfigWritePath); @@ -143,7 +144,7 @@ export class SandboxCommand choices: Object.values(ClientConfigFormat), global: false, }) - .option('out-dir', { + .option('config-out-dir', { describe: 'A path to directory where config is written. If not provided defaults to current process working directory.', type: 'string', @@ -157,20 +158,10 @@ export class SandboxCommand }) .check((argv) => { if (argv['dir-to-watch']) { - // make sure it's a real directory - let stats; - try { - stats = fs.statSync(argv['dir-to-watch'], {}); - } catch (e) { - throw new Error( - `--dir-to-watch ${argv['dir-to-watch']} does not exist` - ); - } - if (!stats.isDirectory()) { - throw new Error( - `--dir-to-watch ${argv['dir-to-watch']} is not a valid directory` - ); - } + this.validateDirectory('dir-to-watch', argv['dir-to-watch']); + } + if (argv['config-out-dir']) { + this.validateDirectory('config-out-dir', argv['config-out-dir']); } if (argv.name) { const projectNameRegex = /^[a-zA-Z0-9-]{1,15}$/; @@ -201,4 +192,16 @@ export class SandboxCommand await this.sandboxFactory.getInstance() ).delete({ name: this.sandboxName }); }; + + validateDirectory = (option: string, dir: string) => { + let stats; + try { + stats = fs.statSync(dir, {}); + } catch (e) { + throw new Error(`--${option} ${dir} does not exist`); + } + if (!stats.isDirectory()) { + throw new Error(`--${option} ${dir} is not a valid directory`); + } + }; } From 4d691a48c823dce1e6ca32286e0b2e1659fedcc9 Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 10:00:23 -0800 Subject: [PATCH 2/6] fix: client config generation respects sandbox format option --- .changeset/dry-ladybugs-film.md | 5 +++++ packages/cli/src/commands/sandbox/sandbox_command.ts | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .changeset/dry-ladybugs-film.md diff --git a/.changeset/dry-ladybugs-film.md b/.changeset/dry-ladybugs-film.md new file mode 100644 index 0000000000..c9472541f4 --- /dev/null +++ b/.changeset/dry-ladybugs-film.md @@ -0,0 +1,5 @@ +--- +'@aws-amplify/backend-cli': patch +--- + +client config generation respects sandbox format option diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index a6c83629f8..fa3a17db92 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -82,7 +82,8 @@ export class SandboxCommand // attaching event handlers const clientConfigLifecycleHandler = new ClientConfigLifecycleHandler( this.clientConfigGeneratorAdapter, - args['config-out-dir'] + args['config-out-dir'], + args.format ); const eventHandlers = this.sandboxEventHandlerCreator?.({ sandboxName: this.sandboxName, From ece963513ce537adfccc22bd0e4b171674f31ece Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 11:25:15 -0800 Subject: [PATCH 3/6] rename sandbox format to config-format --- .changeset/serious-apricots-love.md | 5 +++++ packages/cli/src/commands/sandbox/sandbox_command.test.ts | 2 +- packages/cli/src/commands/sandbox/sandbox_command.ts | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 .changeset/serious-apricots-love.md diff --git a/.changeset/serious-apricots-love.md b/.changeset/serious-apricots-love.md new file mode 100644 index 0000000000..cbeb3a8b52 --- /dev/null +++ b/.changeset/serious-apricots-love.md @@ -0,0 +1,5 @@ +--- +'@aws-amplify/backend-cli': patch +--- + +Rename sandbox format to config-format diff --git a/packages/cli/src/commands/sandbox/sandbox_command.test.ts b/packages/cli/src/commands/sandbox/sandbox_command.test.ts index e4dc9b5229..b057d8d0e6 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.test.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.test.ts @@ -104,7 +104,7 @@ void describe('sandbox command', () => { assert.match(output, /--name/); assert.match(output, /--dir-to-watch/); assert.match(output, /--exclude/); - assert.match(output, /--format/); + assert.match(output, /--config-format/); assert.match(output, /--config-out-dir/); assert.equal(mockHandleProfile.mock.callCount(), 0); }); diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index fa3a17db92..5f8812760d 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -19,7 +19,7 @@ type SandboxCommandOptionsCamelCase = { dirToWatch: string | undefined; exclude: string[] | undefined; name: string | undefined; - format: ClientConfigFormat | undefined; + configFormat: ClientConfigFormat | undefined; configOutDir: string | undefined; profile: string | undefined; }; @@ -83,7 +83,7 @@ export class SandboxCommand const clientConfigLifecycleHandler = new ClientConfigLifecycleHandler( this.clientConfigGeneratorAdapter, args['config-out-dir'], - args.format + args['config-format'] ); const eventHandlers = this.sandboxEventHandlerCreator?.({ sandboxName: this.sandboxName, @@ -97,7 +97,7 @@ export class SandboxCommand const watchExclusions = args.exclude ?? []; const clientConfigWritePath = await getClientConfigPath( args['config-out-dir'], - args.format + args['config-format'] ); watchExclusions.push(clientConfigWritePath); await sandbox.start({ @@ -138,7 +138,7 @@ export class SandboxCommand array: false, global: false, }) - .option('format', { + .option('config-format', { describe: 'Client config output format', type: 'string', array: false, From 4cb5b72ca62b0f2ee5219b5f4155284602c46de4 Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 14:41:16 -0800 Subject: [PATCH 4/6] make validateDirectory async --- .../commands/sandbox/sandbox_command.test.ts | 74 ++++++++++--------- .../src/commands/sandbox/sandbox_command.ts | 15 ++-- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/packages/cli/src/commands/sandbox/sandbox_command.test.ts b/packages/cli/src/commands/sandbox/sandbox_command.test.ts index b057d8d0e6..06ec87059b 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.test.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.test.ts @@ -6,7 +6,7 @@ import { TestCommandRunner, } from '../../test-utils/command_runner.js'; import assert from 'node:assert'; -import fs from 'fs'; +import fsp from 'fs/promises'; import { EventHandler, SandboxCommand } from './sandbox_command.js'; import { createSandboxCommand } from './sandbox_command_factory.js'; import { SandboxDeleteCommand } from './sandbox-delete/sandbox_delete_command.js'; @@ -115,22 +115,32 @@ void describe('sandbox command', () => { }); void it('fails if invalid dir-to-watch is provided', async () => { - const output = await commandRunner.runCommand( - 'sandbox --dir-to-watch nonExistentDir' + const dirToWatchError = new Error( + '--dir-to-watch nonExistentDir does not exist' + ); + mock.method(fsp, 'stat', () => Promise.reject(dirToWatchError)); + await assert.rejects( + () => commandRunner.runCommand('sandbox --dir-to-watch nonExistentDir'), + (err: TestCommandError) => { + assert.equal(err.error.message, dirToWatchError.message); + return true; + } ); - assert.match(output, /--dir-to-watch nonExistentDir does not exist/); }); void it('fails if a file is provided in the --dir-to-watch flag', async (contextual) => { - contextual.mock.method(fs, 'statSync', () => ({ + const dirToWatchError = new Error( + '--dir-to-watch existentFile is not a valid directory' + ); + contextual.mock.method(fsp, 'stat', () => ({ isDirectory: () => false, })); - const output = await commandRunner.runCommand( - 'sandbox --dir-to-watch existentFile' - ); - assert.match( - output, - /--dir-to-watch existentFile is not a valid directory/ + await assert.rejects( + () => commandRunner.runCommand('sandbox --dir-to-watch existentFile'), + (err: TestCommandError) => { + assert.equal(err.error.message, dirToWatchError.message); + return true; + } ); }); @@ -253,34 +263,32 @@ void describe('sandbox command', () => { }); void it('fails if invalid config-out-dir is provided', async () => { - mock.method(fs, 'lstatSync', () => { - return { - isFile: () => false, - isDir: () => false, - }; - }); - const output = await commandRunner.runCommand( - 'sandbox --config-out-dir nonExistentDir' + const configOutDirError = new Error( + '--config-out-dir nonExistentDir does not exist' + ); + mock.method(fsp, 'stat', () => Promise.reject(configOutDirError)); + await assert.rejects( + () => commandRunner.runCommand('sandbox --config-out-dir nonExistentDir'), + (err: TestCommandError) => { + assert.equal(err.error.message, configOutDirError.message); + return true; + } ); - assert.match(output, /--config-out-dir nonExistentDir does not exist/); }); void it('fails if a file is provided for config-out-dir', async (contextual) => { - mock.method(fs, 'lstatSync', () => { - return { - isFile: () => true, - isDir: () => false, - }; - }); - contextual.mock.method(fs, 'statSync', () => ({ + const configOutDirError = new Error( + '--config-out-dir existentFile is not a valid directory' + ); + contextual.mock.method(fsp, 'stat', () => ({ isDirectory: () => false, })); - const output = await commandRunner.runCommand( - 'sandbox --config-out-dir existentFile' - ); - assert.match( - output, - /--config-out-dir existentFile is not a valid directory/ + await assert.rejects( + () => commandRunner.runCommand('sandbox --config-out-dir existentFile'), + (err: TestCommandError) => { + assert.equal(err.error.message, configOutDirError.message); + return true; + } ); }); }); diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index 5f8812760d..293fb1e6d4 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -1,5 +1,5 @@ import { Argv, CommandModule } from 'yargs'; -import fs from 'fs'; +import fsp from 'fs/promises'; import { AmplifyPrompter } from '@aws-amplify/cli-core'; import { SandboxSingletonFactory } from '@aws-amplify/sandbox'; import { @@ -157,12 +157,15 @@ export class SandboxCommand type: 'string', array: false, }) - .check((argv) => { + .check(async (argv) => { if (argv['dir-to-watch']) { - this.validateDirectory('dir-to-watch', argv['dir-to-watch']); + await this.validateDirectory('dir-to-watch', argv['dir-to-watch']); } if (argv['config-out-dir']) { - this.validateDirectory('config-out-dir', argv['config-out-dir']); + await this.validateDirectory( + 'config-out-dir', + argv['config-out-dir'] + ); } if (argv.name) { const projectNameRegex = /^[a-zA-Z0-9-]{1,15}$/; @@ -194,10 +197,10 @@ export class SandboxCommand ).delete({ name: this.sandboxName }); }; - validateDirectory = (option: string, dir: string) => { + validateDirectory = async (option: string, dir: string) => { let stats; try { - stats = fs.statSync(dir, {}); + stats = await fsp.stat(dir, {}); } catch (e) { throw new Error(`--${option} ${dir} does not exist`); } From 70969c45aace60246430ffb7058fd898ec13f419 Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 14:53:55 -0800 Subject: [PATCH 5/6] add test for client config options --- .../commands/sandbox/sandbox_command.test.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/cli/src/commands/sandbox/sandbox_command.test.ts b/packages/cli/src/commands/sandbox/sandbox_command.test.ts index 06ec87059b..63d8b0dfc7 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.test.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.test.ts @@ -6,6 +6,7 @@ import { TestCommandRunner, } from '../../test-utils/command_runner.js'; import assert from 'node:assert'; +import fs from 'fs'; import fsp from 'fs/promises'; import { EventHandler, SandboxCommand } from './sandbox_command.js'; import { createSandboxCommand } from './sandbox_command_factory.js'; @@ -14,6 +15,7 @@ import { Sandbox, SandboxSingletonFactory } from '@aws-amplify/sandbox'; import { createSandboxSecretCommand } from './sandbox-secret/sandbox_secret_command_factory.js'; import { ClientConfigGeneratorAdapter } from '../../client-config/client_config_generator_adapter.js'; import { CommandMiddleware } from '../../command_middleware.js'; +import path from 'path'; void describe('sandbox command factory', () => { void it('instantiate a sandbox command correctly', () => { @@ -291,4 +293,24 @@ void describe('sandbox command', () => { } ); }); + + void it('starts sandbox with provided client config options as watch exclusions', async (contextual) => { + mock.method(fs, 'lstatSync', () => { + return { + isFile: () => false, + isDir: () => true, + }; + }); + contextual.mock.method(fsp, 'stat', () => ({ + isDirectory: () => true, + })); + await commandRunner.runCommand( + 'sandbox --config-out-dir existentDir --config-format ts' + ); + assert.equal(sandboxStartMock.mock.callCount(), 1); + assert.deepStrictEqual( + sandboxStartMock.mock.calls[0].arguments[0].exclude, + [path.join(process.cwd(), 'existentDir', 'amplifyconfiguration.ts')] + ); + }); }); From 9589b4964742cba6c222fe7689e36366b08fff2c Mon Sep 17 00:00:00 2001 From: Roshane Pascual Date: Tue, 14 Nov 2023 21:20:30 -0800 Subject: [PATCH 6/6] make validateDirectory private --- packages/cli/src/commands/sandbox/sandbox_command.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/commands/sandbox/sandbox_command.ts b/packages/cli/src/commands/sandbox/sandbox_command.ts index 293fb1e6d4..d2fc5183ec 100644 --- a/packages/cli/src/commands/sandbox/sandbox_command.ts +++ b/packages/cli/src/commands/sandbox/sandbox_command.ts @@ -197,7 +197,7 @@ export class SandboxCommand ).delete({ name: this.sandboxName }); }; - validateDirectory = async (option: string, dir: string) => { + private validateDirectory = async (option: string, dir: string) => { let stats; try { stats = await fsp.stat(dir, {});