diff --git a/packages/amplify-category-storage/Readme.md b/packages/amplify-category-storage/Readme.md index 905823e9b27..74f38c6a255 100644 --- a/packages/amplify-category-storage/Readme.md +++ b/packages/amplify-category-storage/Readme.md @@ -10,3 +10,4 @@ The following table lists the current set of commands supported by the Amplify S | amplify storage update | Takes you through steps in the CLI to update a storage resource. | | amplify storage push | Provisions only storage cloud resources with the latest local developments. | | amplify storage remove | Removes storage resource from your local backend. The resources are removed from the cloud on the next push command. | +| amplify storage override | Generates 'overrides.ts' for storage resource in your local backend. The resource properties can be overridden by editing this file. The resource is overridden in the cloud on the next push command. | diff --git a/packages/amplify-category-storage/src/commands/storage.ts b/packages/amplify-category-storage/src/commands/storage.ts index 5803418acbc..1e487cd7dbd 100644 --- a/packages/amplify-category-storage/src/commands/storage.ts +++ b/packages/amplify-category-storage/src/commands/storage.ts @@ -38,6 +38,10 @@ export async function run(context: $TSContext) { name: 'remove', description: `Removes ${categoryName} resource from your local backend. The resource is removed from the cloud on the next push command.`, }, + { + name: 'override', + description: `Generates 'overrides.ts' for ${categoryName} resource in your local backend. The resource properties can be overridden by editing this file. The resource is overridden in the cloud on the next push command. `, + }, ]; context.amplify.showHelp(header, commands); diff --git a/packages/amplify-e2e-core/src/categories/storage.ts b/packages/amplify-e2e-core/src/categories/storage.ts index 91347ec36c8..20b3e5c6881 100644 --- a/packages/amplify-e2e-core/src/categories/storage.ts +++ b/packages/amplify-e2e-core/src/categories/storage.ts @@ -1,5 +1,5 @@ -import { nspawn as spawn, KEY_DOWN_ARROW, getCLIPath } from '..'; -import { singleSelect, multiSelect } from '../utils/selectors'; +import { getCLIPath, KEY_DOWN_ARROW, nspawn as spawn } from '..'; +import { singleSelect } from '../utils/selectors'; export type AddStorageSettings = { resourceName: string; @@ -245,10 +245,9 @@ export function buildOverrideStorage(cwd: string, settings: {}) { return new Promise((resolve, reject) => { // Add 'storage' as a category param once implemented const args = ['build']; - - spawn(getCLIPath(), args, { cwd, stripColors: true }) - .sendEof() - .run((err: Error) => { + const chain = spawn(getCLIPath(), args, { cwd, stripColors: true }) + chain + .run((err: Error) => { if (!err) { resolve({}); } else { @@ -408,19 +407,13 @@ export function addS3WithGuestAccess(cwd: string, settings: any): Promise .wait('Provide bucket name') .sendCarriageReturn() // Default name .wait('Who should have access') - .send(KEY_DOWN_ARROW) + .sendKeyDown() .sendCarriageReturn() // Auth and guest users - .wait('What kind of access do you want for') - .send(' ') // Create - .send(KEY_DOWN_ARROW) - .send(' ') // Read - .send(KEY_DOWN_ARROW) - .send(' ') // Delete - .send(KEY_DOWN_ARROW) + .wait('What kind of access do you want for Authenticated users?') + .sendCtrlA() .sendCarriageReturn() - .wait('What kind of access do you want for') - .send(KEY_DOWN_ARROW) - .send(' ') // Select read + .wait('What kind of access do you want for Guest users?') + .sendCtrlA() .sendCarriageReturn() .wait('Do you want to add a Lambda Trigger for your S3 Bucket') .sendConfirmNo() @@ -446,21 +439,18 @@ export function addS3WithGroupAccess(cwd: string, settings: any): Promise .wait('Provide bucket name') .sendCarriageReturn() // Default name .wait('Restrict access by') - .send(KEY_DOWN_ARROW) + .sendKeyDown() .sendCarriageReturn() // Individual groups .wait('Select groups') - .send(' ') - .send(KEY_DOWN_ARROW) //select Admin - .send(' ') - .send(KEY_DOWN_ARROW) //select User + .send(' ') //select Admin + .sendKeyDown() + .send(' ')//select User .sendCarriageReturn() .wait('What kind of access do you want') // for users? .sendCtrlA() // Select all permissions .sendCarriageReturn() .wait('What kind of access do you want') // for users? - .send(' ') // Select create/update - .send(KEY_DOWN_ARROW) - .send(' ') // Select read + .sendCtrlA() // Select all permissions .sendCarriageReturn() .wait('Do you want to add a Lambda Trigger for your S3 Bucket') .sendConfirmNo() @@ -511,7 +501,37 @@ export function updateS3AddTrigger(cwd: string, settings: any): Promise { .wait('Select from one of the below mentioned services') .sendCarriageReturn() // Content .wait('Restrict access by') - .send(KEY_DOWN_ARROW) + .sendKeyDown() + .sendCarriageReturn() // Individual groups + .wait('Select groups') + .sendCarriageReturn() + .wait('What kind of access do you want') // for users? + .sendCarriageReturn() + .wait('What kind of access do you want') // for users? + .sendCarriageReturn() + .wait('Do you want to add a Lambda Trigger for your S3 Bucket') + .sendConfirmYes() + .wait('Do you want to edit the local') + .sendConfirmNo() + .sendCarriageReturn() + .sendEof() + .run((err: Error) => { + if (!err) { + resolve(); + } else { + reject(err); + } + }); + }); +} + +export function updateS3AddTriggerWithExistingFunction(cwd: string, settings: any): Promise { + return new Promise((resolve, reject) => { + spawn(getCLIPath(), ['update', 'storage'], { cwd, stripColors: true }) + .wait('Select from one of the below mentioned services') + .sendCarriageReturn() // Content + .wait('Restrict access by') + .sendKeyDown() .sendCarriageReturn() // Individual groups .wait('Select groups') .sendCarriageReturn() @@ -522,7 +542,7 @@ export function updateS3AddTrigger(cwd: string, settings: any): Promise { .wait('Do you want to add a Lambda Trigger for your S3 Bucket') .sendConfirmYes() .wait('Select from the following options') - .send(KEY_DOWN_ARROW) + .sendKeyDown() .sendCarriageReturn() //Create a new function .wait('Do you want to edit the local') .sendConfirmNo() @@ -554,11 +574,6 @@ export function addS3StorageWithIdpAuth(projectDir: string): Promise { .wait('Who should have access:') .sendCarriageReturn(); - multiSelect( - chain.wait('What kind of access do you want for Authenticated users?'), - ['create/update', 'read', 'delete'], - ['create/update', 'read', 'delete'], - ); chain.wait('What kind of access do you want for Authenticated users?') .send(' ') //'create/update' .sendKeyDown() diff --git a/packages/amplify-e2e-tests/src/__tests__/storage-1.test.ts b/packages/amplify-e2e-tests/src/__tests__/storage-1.test.ts index 961fa6c615b..2638b2c8923 100644 --- a/packages/amplify-e2e-tests/src/__tests__/storage-1.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/storage-1.test.ts @@ -13,8 +13,7 @@ import { deleteProjectDir, getProjectMeta, initFlutterProjectWithProfile, - initJSProjectWithProfile, - updateS3AddTrigger, + initJSProjectWithProfile, updateS3AddTriggerWithExistingFunction } from 'amplify-e2e-core'; import * as fs from 'fs-extra'; import * as path from 'path'; @@ -94,7 +93,7 @@ describe('amplify add/update storage(S3)', () => { await initJSProjectWithProfile(projRoot, {}); await addAuthWithGroupsAndAdminAPI(projRoot, {}); await addS3WithGroupAccess(projRoot, {}); - await updateS3AddTrigger(projRoot, {}); + await updateS3AddTriggerWithExistingFunction(projRoot, {}); await amplifyPushAuth(projRoot); await validate(projRoot); }); diff --git a/packages/amplify-e2e-tests/src/__tests__/storage-5.test.ts b/packages/amplify-e2e-tests/src/__tests__/storage-5.test.ts index 4aba2a481d4..f90903913a0 100644 --- a/packages/amplify-e2e-tests/src/__tests__/storage-5.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/storage-5.test.ts @@ -1,22 +1,5 @@ import { $TSAny, JSONUtilities } from 'amplify-cli-core'; -import { initJSProjectWithProfile, initFlutterProjectWithProfile, deleteProject, amplifyPushAuth } from 'amplify-e2e-core'; -import { addAuthWithDefault, addAuthWithGroupsAndAdminAPI } from 'amplify-e2e-core'; -import { - addSimpleDDB, - overrideDDB, - buildOverrideStorage, - addDDBWithTrigger, - updateDDBWithTrigger, - addSimpleDDBwithGSI, - updateSimpleDDBwithGSI, - overrideS3, - addS3AndAuthWithAuthOnlyAccess, - addS3WithGuestAccess, - addS3WithGroupAccess, - addS3WithTrigger, - updateS3AddTrigger, -} from 'amplify-e2e-core'; -import { createNewProjectDir, deleteProjectDir, getProjectMeta, getDDBTable, checkIfBucketExists } from 'amplify-e2e-core'; +import { addAuthWithDefault, addDDBWithTrigger, addS3WithGuestAccess, addSimpleDDB, addSimpleDDBwithGSI, amplifyPushAuth, buildOverrideStorage, checkIfBucketExists, createNewProjectDir, deleteProject, deleteProjectDir, getDDBTable, getProjectMeta, initJSProjectWithProfile, overrideDDB, overrideS3, updateDDBWithTrigger, updateSimpleDDBwithGSI } from 'amplify-e2e-core'; import * as fs from 'fs-extra'; import * as path from 'path'; import uuid from 'uuid'; @@ -145,6 +128,7 @@ describe('amplify add/update storage(DDB)', () => { }); }); + describe('ddb override tests', () => { let projRoot: string; beforeEach(async () => { @@ -164,23 +148,18 @@ describe('ddb override tests', () => { const srcOverrideFilePath = path.join(__dirname, '..', '..', 'overrides', 'override-storage-ddb.ts'); const destOverrideFilePath = path.join(projRoot, 'amplify', 'backend', 'storage', resourceName, 'override.ts'); - const cfnFilePath = path.join(projRoot, 'amplify', 'backend', 'storage', resourceName, 'build', 'cloudformation-template.json'); + const cfnFilePath = path.join(projRoot, 'amplify', 'backend', 'storage', resourceName, 'build', `${resourceName}-cloudformation-template.json`); fs.copyFileSync(srcOverrideFilePath, destOverrideFilePath); - await buildOverrideStorage(projRoot, {}); - let ddbCFNFileJSON: any = JSONUtilities.readJson(cfnFilePath); - // check if overrides are applied to the cfn file expect(ddbCFNFileJSON?.Resources?.DynamoDBTable?.Properties?.StreamSpecification?.StreamViewType).toEqual('NEW_AND_OLD_IMAGES'); - await updateDDBWithTrigger(projRoot, {}); // check if override persists after an update ddbCFNFileJSON = JSONUtilities.readJson(cfnFilePath); expect(ddbCFNFileJSON?.Resources?.DynamoDBTable?.Properties?.StreamSpecification?.StreamViewType).toEqual('NEW_AND_OLD_IMAGES'); - await amplifyPushAuth(projRoot); const meta = getProjectMeta(projRoot);