From be7edde0f213e120101cd048fa8098f54183494f Mon Sep 17 00:00:00 2001 From: John Hockett Date: Tue, 9 Nov 2021 19:56:51 -0800 Subject: [PATCH] fix: amplify meta output for imported ddb, type fixes (#8767) --- .../import/import-dynamodb.ts | 60 ++++++++++++------- .../dynamoDB-input-state.ts | 34 +++++++---- .../dynamoDb-walkthrough.ts | 44 +++++++------- .../src/__tests__/import_dynamodb_2.test.ts | 2 +- 4 files changed, 82 insertions(+), 58 deletions(-) diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/import/import-dynamodb.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/import/import-dynamodb.ts index f87e2b99ba5..1c541d0b925 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/import/import-dynamodb.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/import/import-dynamodb.ts @@ -1,10 +1,10 @@ -import { $TSContext, ServiceSelection, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, ServiceSelection, stateManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import { IDynamoDBService } from 'amplify-util-import'; import Enquirer from 'enquirer'; import _ from 'lodash'; import { importMessages } from './messages'; import { - ImportDynamoDBHeadlessParameters, - ProviderUtils, DynamoDBBackendConfiguration, DynamoDBEnvSpecificResourceParameters, DynamoDBImportAnswers, @@ -12,8 +12,22 @@ import { DynamoDBMetaConfiguration, DynamoDBMetaOutput, DynamoDBResourceParameters, + ImportDynamoDBHeadlessParameters, + ProviderUtils, } from './types'; -import { IDynamoDBService } from 'amplify-util-import'; + +const attrReverseMap: $TSObject = { + S: 'string', + N: 'number', + B: 'binary', + BOOL: 'boolean', + L: 'list', + M: 'map', + NULL: null, + SS: 'string-set', + NS: 'number-set', + BS: 'binary-set', +}; export const importDynamoDB = async ( context: $TSContext, @@ -23,7 +37,7 @@ export const importDynamoDB = async ( printSuccessMessage: boolean = true, ): Promise<{ envSpecificParameters: DynamoDBEnvSpecificResourceParameters } | undefined> => { // Load provider - const providerPlugin = providerPluginInstance || require(serviceSelection.provider); + const providerPlugin = providerPluginInstance || (await import(serviceSelection.provider)); const providerUtils = providerPlugin as ProviderUtils; const importServiceWalkthroughResult = await importServiceWalkthrough( @@ -45,7 +59,7 @@ export const importDynamoDB = async ( const { envSpecificParameters } = await updateStateFiles(context, questionParameters, answers, persistEnvParameters); if (printSuccessMessage) { - printSuccess(context, answers.tableName!); + printSuccess(answers.tableName!); } return { @@ -53,12 +67,12 @@ export const importDynamoDB = async ( }; }; -const printSuccess = (context: $TSContext, tableName: string) => { - context.print.info(''); - context.print.info(`✅ DynamoDB Table '${tableName}' was successfully imported.`); - context.print.info(''); - context.print.info('Next steps:'); - context.print.info(`- This resource can now be accessed from REST APIs (‘amplify add api’) and Functions (‘amplify add function’)`); +const printSuccess = (tableName: string) => { + printer.blankLine(); + printer.info(`✅ DynamoDB Table '${tableName}' was successfully imported.`); + printer.blankLine(); + printer.info('Next steps:'); + printer.info(`- This resource can now be accessed from REST APIs (‘amplify add api’) and Functions (‘amplify add function’)`); }; const importServiceWalkthrough = async ( @@ -82,7 +96,7 @@ const importServiceWalkthrough = async ( // Return it no userpools found in the project's region if (_.isEmpty(tableList)) { - context.print.info(importMessages.NoDynamoDBTablesToImport); + printer.info(importMessages.NoDynamoDBTablesToImport); return; } @@ -105,7 +119,7 @@ const importServiceWalkthrough = async ( answers.resourceName = answers.tableName.replace(/[\W_]+/g, ''); answers.tableDescription = await dynamoDB.getTableDetails(answers.tableName); - context.print.info(importMessages.OneTable(answers.tableName)); + printer.info(importMessages.OneTable(answers.tableName)); } else { const tableNameQuestion = { type: 'autocomplete', @@ -117,7 +131,7 @@ const importServiceWalkthrough = async ( footer: importMessages.AutoCompleteFooter, }; - const { tableName } = await enquirer.prompt(tableNameQuestion as any); // any case needed because async validation TS definition is not up to date + const { tableName } = await enquirer.prompt(tableNameQuestion as $TSAny); // any case needed because async validation TS definition is not up to date answers.tableName = tableName!; answers.resourceName = answers.tableName!.replace(/[\W_]+/g, ''); @@ -204,7 +218,7 @@ const createMetaOutput = (answers: DynamoDBImportAnswers, questionParameters: Dy if (attribute) { output.PartitionKeyName = hashKey.AttributeName; - output.PartitionKeyType = attribute.AttributeType; + output.PartitionKeyType = attrReverseMap[attribute.AttributeType]; } } @@ -213,7 +227,7 @@ const createMetaOutput = (answers: DynamoDBImportAnswers, questionParameters: Dy if (attribute) { output.SortKeyName = sortKeys[0].AttributeName; - output.SortKeyType = attribute.AttributeType; + output.SortKeyType = attrReverseMap[attribute.AttributeType]; } } @@ -239,7 +253,7 @@ const createEnvSpecificResourceParameters = ( if (attribute) { envSpecificResourceParameters.partitionKeyName = hashKey.AttributeName; - envSpecificResourceParameters.partitionKeyType = attribute.AttributeType; + envSpecificResourceParameters.partitionKeyType = attrReverseMap[attribute.AttributeType]; } } @@ -248,7 +262,7 @@ const createEnvSpecificResourceParameters = ( if (attribute) { envSpecificResourceParameters.sortKeyName = sortKeys[0].AttributeName; - envSpecificResourceParameters.sortKeyType = attribute.AttributeType; + envSpecificResourceParameters.sortKeyType = attrReverseMap[attribute.AttributeType]; } } @@ -312,8 +326,8 @@ export const importedDynamoDBEnvInit = async ( message: importMessages.ImportPreviousTable(resourceName, sourceEnvParams.tableName, context.exeInfo.sourceEnvName), footer: importMessages.ImportPreviousResourceFooter, initial: true, - format: (e: any) => (e ? 'Yes' : 'No'), - } as any); + format: (e: $TSAny) => (e ? 'Yes' : 'No'), + } as $TSAny); if (!importExisting) { return { @@ -335,7 +349,7 @@ export const importedDynamoDBEnvInit = async ( // If there are no current parameters a service walkthrough is required, it can happen when pulling to an empty directory. if (!(currentEnvSpecificParameters.tableName && currentEnvSpecificParameters.region)) { - context.print.info(importMessages.ImportNewResourceRequired(resourceName)); + printer.info(importMessages.ImportNewResourceRequired(resourceName)); return { doServiceWalkthrough: true, @@ -357,7 +371,7 @@ export const importedDynamoDBEnvInit = async ( const tableExists = await dynamoDB.tableExists(currentEnvSpecificParameters.tableName); if (!tableExists) { - context.print.error(importMessages.TableNotFound(currentEnvSpecificParameters.tableName)); + printer.error(importMessages.TableNotFound(currentEnvSpecificParameters.tableName)); return { succeeded: false, diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDB-input-state.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDB-input-state.ts index f8b111415fc..193ee6d6b7e 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDB-input-state.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDB-input-state.ts @@ -1,7 +1,15 @@ -import { DynamoDBCLIInputs, DynamoDBCLIInputsGSIType } from '../service-walkthrough-types/dynamoDB-user-input-types'; -import { AmplifyCategories, AmplifySupportedService, CLIInputSchemaValidator, JSONUtilities, pathManager } from 'amplify-cli-core'; +import { + $TSAny, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + CLIInputSchemaValidator, + JSONUtilities, + pathManager, +} from 'amplify-cli-core'; import * as fs from 'fs-extra'; import * as path from 'path'; +import { DynamoDBCLIInputs, DynamoDBCLIInputsGSIType } from '../service-walkthrough-types/dynamoDB-user-input-types'; /* Need to move this logic to a base class */ @@ -27,7 +35,7 @@ export class DynamoDBInputState { // Read cliInputs file if exists try { - cliInputs = JSONUtilities.readJson(this._cliInputsFilePath) as DynamoDBCLIInputs; + cliInputs = JSONUtilities.readJson(this._cliInputsFilePath)!; } catch (e) { throw new Error('cli-inputs.json file missing from the resource directory'); } @@ -51,7 +59,7 @@ export class DynamoDBInputState { public saveCliInputPayload(cliInputs: DynamoDBCLIInputs): void { this.isCLIInputsValid(cliInputs); - fs.ensureDirSync(path.join(pathManager.getBackendDirPath(), this._category, this._resourceName)); + fs.ensureDirSync(pathManager.getResourceDirectoryPath(undefined, this._category, this._resourceName)); try { JSONUtilities.writeJson(this._cliInputsFilePath, cliInputs); } catch (e) { @@ -61,7 +69,7 @@ export class DynamoDBInputState { public migrate() { let cliInputs: DynamoDBCLIInputs; - const attrReverseMap: any = { + const attrReverseMap: $TSObject = { S: 'string', N: 'number', B: 'binary', @@ -81,9 +89,9 @@ export class DynamoDBInputState { const oldCFNFilepath = path.join(backendDir, 'storage', this._resourceName, `${this._resourceName}-cloudformation-template.json`); const oldStorageParamsFilepath = path.join(backendDir, 'storage', this._resourceName, `storage-params.json`); - const oldParameters: any = JSONUtilities.readJson(oldParametersFilepath, { throwIfNotExist: true }); - const oldCFN: any = JSONUtilities.readJson(oldCFNFilepath, { throwIfNotExist: true }); - const oldStorageParams: any = JSONUtilities.readJson(oldStorageParamsFilepath, { throwIfNotExist: false }) || {}; + const oldParameters = JSONUtilities.readJson<$TSAny>(oldParametersFilepath, { throwIfNotExist: true }); + const oldCFN = JSONUtilities.readJson<$TSAny>(oldCFNFilepath, { throwIfNotExist: true }); + const oldStorageParams = JSONUtilities.readJson<$TSAny>(oldStorageParamsFilepath, { throwIfNotExist: false }) || {}; const partitionKey = { fieldName: oldParameters.partitionKeyName, @@ -105,10 +113,10 @@ export class DynamoDBInputState { triggerFunctions = oldStorageParams.triggerFunctions; } - const getType = (attrList: any, attrName: string) => { + const getType = (attrList: $TSAny, attrName: string) => { let attrType; - attrList.forEach((attr: any) => { + attrList.forEach((attr: $TSAny) => { if (attr.AttributeName === attrName) { attrType = attrReverseMap[attr.AttributeType]; } @@ -120,10 +128,10 @@ export class DynamoDBInputState { let gsi: DynamoDBCLIInputsGSIType[] = []; if (oldCFN?.Resources?.DynamoDBTable?.Properties?.GlobalSecondaryIndexes) { - oldCFN.Resources.DynamoDBTable.Properties.GlobalSecondaryIndexes.forEach((cfnGSIValue: any) => { - let gsiValue: any = {}; + oldCFN.Resources.DynamoDBTable.Properties.GlobalSecondaryIndexes.forEach((cfnGSIValue: $TSAny) => { + let gsiValue: $TSAny = {}; (gsiValue.name = cfnGSIValue.IndexName), - cfnGSIValue.KeySchema.forEach((keySchema: any) => { + cfnGSIValue.KeySchema.forEach((keySchema: $TSObject) => { if (keySchema.KeyType === 'HASH') { gsiValue.partitionKey = { fieldName: keySchema.AttributeName, diff --git a/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDb-walkthrough.ts b/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDb-walkthrough.ts index 37a77cba694..d1616db82d5 100644 --- a/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDb-walkthrough.ts +++ b/packages/amplify-category-storage/src/provider-utils/awscloudformation/service-walkthroughs/dynamoDb-walkthrough.ts @@ -1,17 +1,26 @@ -import * as path from 'path'; +import { + $TSAny, + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + exitOnNextTick, + pathManager, + ResourceDoesNotExistError, + stateManager, +} from 'amplify-cli-core'; +import { alphanumeric, printer, prompter, Validator } from 'amplify-prompts'; import * as fs from 'fs-extra'; +import * as path from 'path'; import { v4 as uuid } from 'uuid'; -import { alphanumeric, printer, prompter, Validator } from 'amplify-prompts'; -import { $TSContext, AmplifyCategories, ResourceDoesNotExistError, exitOnNextTick, stateManager } from 'amplify-cli-core'; -import { DynamoDBInputState } from './dynamoDB-input-state'; +import { DDBStackTransform } from '../cdk-stack-builder/ddb-stack-transform'; import { DynamoDBAttributeDefType, DynamoDBCLIInputs, DynamoDBCLIInputsGSIType, DynamoDBCLIInputsKeyType, } from '../service-walkthrough-types/dynamoDB-user-input-types'; -import { DDBStackTransform } from '../cdk-stack-builder/ddb-stack-transform'; -import { ConfigSnapshotDeliveryProperties } from 'cloudform-types/types/config/deliveryChannel'; +import { DynamoDBInputState } from './dynamoDB-input-state'; // keep in sync with ServiceName in amplify-AmplifyCategories.STORAGE-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -58,7 +67,7 @@ export async function addWalkthrough(context: $TSContext, defaultValuesFilename: export async function updateWalkthrough(context: $TSContext) { const amplifyMeta = stateManager.getMeta(); - const dynamoDbResources: any = {}; + const dynamoDbResources: $TSObject = {}; Object.keys(amplifyMeta[AmplifyCategories.STORAGE]).forEach(resourceName => { if ( @@ -519,7 +528,7 @@ async function addTrigger(context: $TSContext, resourceName: string, triggerList // Update amplify-meta and backend-config const backendConfigs = { - service: FunctionServiceNameLambdaFunction, + service: AmplifySupportedService.LAMBDA, providerPlugin: 'awscloudformation', build: true, }; @@ -599,7 +608,7 @@ async function addTrigger(context: $TSContext, resourceName: string, triggerList // Update dependsOn - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); + const amplifyMetaFilePath = pathManager.getAmplifyMetaFilePath(); const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); const resourceDependsOn = amplifyMeta.function[functionName].dependsOn || []; @@ -641,13 +650,13 @@ async function addTrigger(context: $TSContext, resourceName: string, triggerList async function getLambdaFunctions(context: $TSContext) { const { allResources } = await context.amplify.getResourceStatus(); const lambdaResources = allResources - .filter((resource: any) => resource.service === FunctionServiceNameLambdaFunction) + .filter((resource: any) => resource.service === AmplifySupportedService.LAMBDA) .map((resource: any) => resource.resourceName); return lambdaResources; } -function migrateCategory(context: $TSContext, projectPath: any, resourceName: any) { +export function migrate(context: $TSContext, projectPath: any, resourceName: any) { const resourceDirPath = path.join(projectPath, 'amplify', 'backend', AmplifyCategories.STORAGE, resourceName); const cfnFilePath = path.join(resourceDirPath, `${resourceName}-cloudformation-template.json`); @@ -722,11 +731,11 @@ function migrateCategory(context: $TSContext, projectPath: any, resourceName: an fs.writeFileSync(cfnFilePath, jsonString, 'utf8'); } -function getIAMPolicies(resourceName: any, crudOptions: any) { +export function getIAMPolicies(resourceName: string, crudOptions: $TSAny) { let policy = {}; - const actions: any = []; + const actions: string[] = []; - crudOptions.forEach((crudOption: any) => { + crudOptions.forEach((crudOption: $TSAny) => { switch (crudOption) { case 'create': actions.push('dynamodb:Put*', 'dynamodb:Create*', 'dynamodb:BatchWriteItem'); @@ -770,10 +779,3 @@ function getIAMPolicies(resourceName: any, crudOptions: any) { return { policy, attributes }; } - -module.exports = { - addWalkthrough, - updateWalkthrough, - migrate: migrateCategory, - getIAMPolicies, -}; diff --git a/packages/amplify-e2e-tests/src/__tests__/import_dynamodb_2.test.ts b/packages/amplify-e2e-tests/src/__tests__/import_dynamodb_2.test.ts index 2688bc080b2..b21a1807038 100644 --- a/packages/amplify-e2e-tests/src/__tests__/import_dynamodb_2.test.ts +++ b/packages/amplify-e2e-tests/src/__tests__/import_dynamodb_2.test.ts @@ -143,7 +143,7 @@ describe('dynamodb import', () => { teamInfo = getTeamProviderInfo(projectRoot); - // No prod in team proovider info + // No prod in team provider info expect(teamInfo.prod).toBeUndefined(); });