diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts index ada52d192ce..efb5f999e09 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts @@ -4,6 +4,7 @@ import { $TSAny, $TSContext } from 'amplify-cli-core'; jest.mock('fs-extra'); jest.mock('amplify-cli-core', () => ({ + AmplifyCategories: { API: 'api' }, isResourceNameUnique: jest.fn().mockReturnValue(true), JSONUtilities: { readJson: jest.fn(), diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts index cf6e04f21fc..2945ad4def2 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts @@ -4,6 +4,7 @@ import { category } from '../../../category-constants'; jest.mock('fs-extra'); jest.mock('amplify-cli-core', () => ({ + AmplifyCategories: { API: 'api' }, JSONUtilities: { readJson: jest.fn(), writeJson: jest.fn(), diff --git a/packages/amplify-category-api/src/category-constants.ts b/packages/amplify-category-api/src/category-constants.ts index 5851dbb6a02..1b460621d7a 100644 --- a/packages/amplify-category-api/src/category-constants.ts +++ b/packages/amplify-category-api/src/category-constants.ts @@ -1,2 +1,5 @@ -export const category = 'api'; +import { AmplifyCategories } from 'amplify-cli-core'; + +export const ADMIN_QUERIES_NAME = 'AdminQueries'; export const NETWORK_STACK_LOGICAL_ID = 'NetworkStack'; +export const category = AmplifyCategories.API; diff --git a/packages/amplify-category-api/src/commands/api/migrate.ts b/packages/amplify-category-api/src/commands/api/migrate.ts index 63859fafa80..3389023cad8 100644 --- a/packages/amplify-category-api/src/commands/api/migrate.ts +++ b/packages/amplify-category-api/src/commands/api/migrate.ts @@ -1,8 +1,7 @@ -import { $TSAny, $TSContext, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, AmplifyCategories, pathManager, stateManager } from 'amplify-cli-core'; import { printer } from 'amplify-prompts'; import { attemptV2TransformerMigration, revertV2Migration } from '@aws-amplify/graphql-transformer-migrator'; import * as path from 'path'; -import { category } from '../../category-constants'; import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; const subcommand = 'migrate'; @@ -27,7 +26,7 @@ export const run = async (context: $TSContext) => { return; } const apiName = apiNames[0]; - const apiResourceDir = path.join(pathManager.getBackendDirPath(), category, apiName); + const apiResourceDir = path.join(pathManager.getBackendDirPath(), AmplifyCategories.API, apiName); if (await checkAppsyncApiResourceMigration(context, apiName, true)) { await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [context, { forceCompile: true }]); diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts index 4dcbd14957b..3dbbe3830fb 100644 --- a/packages/amplify-category-api/src/commands/api/override.ts +++ b/packages/amplify-category-api/src/commands/api/override.ts @@ -1,17 +1,18 @@ import { $TSContext, + $TSObject, AmplifyCategories, AmplifySupportedService, generateOverrideSkeleton, - getMigrateResourceMessageForOverride, pathManager, stateManager, } from 'amplify-cli-core'; import { printer, prompter } from 'amplify-prompts'; import * as path from 'path'; -import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; -import { ApigwInputState } from '../../provider-utils/awscloudformation/apigw-input-state'; +import { ADMIN_QUERIES_NAME } from '../../category-constants'; +import { AdminQueriesProps, ApigwInputState } from '../../provider-utils/awscloudformation/apigw-input-state'; import { ApigwStackTransform } from '../../provider-utils/awscloudformation/cdk-stack-builder'; +import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; export const name = 'override'; @@ -71,12 +72,26 @@ export const run = async (context: $TSContext) => { // Migration logic goes in here const apigwInputState = new ApigwInputState(context, selectedResourceName); if (!apigwInputState.cliInputsFileExists()) { - if (await prompter.yesOrNo(getMigrateResourceMessageForOverride(AmplifyCategories.API, selectedResourceName, false), true)) { + if (selectedResourceName === ADMIN_QUERIES_NAME) { + const { dependsOn }: { dependsOn: $TSObject[] } = amplifyMeta[AmplifyCategories.API][selectedResourceName]; + if (!Array.isArray(dependsOn) || dependsOn.length === 0) { + throw new Error(`Invalid dependsOn entry found in amplify-meta.json for "${ADMIN_QUERIES_NAME}"`); + } + + const getResourceNameFromDependsOn = (categoryName: string, dependsOn: $TSObject[]) => + dependsOn.filter(entry => entry.category === categoryName)[0].resourceName; + + const props: AdminQueriesProps = { + apiName: selectedResourceName, + authResourceName: getResourceNameFromDependsOn(AmplifyCategories.AUTH, dependsOn), + functionName: getResourceNameFromDependsOn(AmplifyCategories.FUNCTION, dependsOn), + dependsOn: dependsOn, + }; + await apigwInputState.migrateAdminQueries(props); + } else { await apigwInputState.migrateApigwResource(selectedResourceName); const stackGenerator = new ApigwStackTransform(context, selectedResourceName); stackGenerator.transform(); - } else { - return; } } await generateOverrideSkeleton(context, srcPath, destPath); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts index fc053a69287..3a20074f6ba 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts @@ -239,7 +239,7 @@ export class ApigwInputState { } } -type AdminQueriesProps = { +export type AdminQueriesProps = { apiName: string; functionName: string; authResourceName: string; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts index d0863d3a6f2..338f77bac4f 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts @@ -4,6 +4,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { $TSObject, JSONUtilities } from 'amplify-cli-core'; import _ from 'lodash'; +import { ADMIN_QUERIES_NAME } from '../../../category-constants'; import { AmplifyApigwResourceTemplate, ApigwInputs, ApigwPathPolicy, Path, PermissionSetting } from './types'; const CFN_TEMPLATE_FORMAT_VERSION = '2010-09-09'; @@ -250,9 +251,9 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw const addedFunctionPermissions = new Set(); for (const [pathName, path] of Object.entries(this._props.paths)) { let lambdaPermissionLogicalId: string; - if (resourceName === 'AdminQueries') { + if (resourceName === ADMIN_QUERIES_NAME) { this.paths[`/{proxy+}`] = getAdminQueriesPathObject(path.lambdaFunction); - lambdaPermissionLogicalId = 'AdminQueriesAPIGWPolicyForLambda'; + lambdaPermissionLogicalId = `${ADMIN_QUERIES_NAME}APIGWPolicyForLambda`; } else { this.paths[pathName] = createPathObject(path); this.paths[`${pathName}/{proxy+}`] = createPathObject(path); @@ -284,8 +285,9 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw private _setDeploymentResource = (resourceName: string) => { this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}`, { - restApiId: cdk.Fn.ref(resourceName), + description: 'The Development stage deployment of your API.', stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), + restApiId: cdk.Fn.ref(resourceName), }); }; } diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts index 244bad5cbc2..c2401160362 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts @@ -18,8 +18,8 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import * as vm from 'vm2'; import { AmplifyApigwResourceStack, ApigwInputs, CrudOperation, Path } from '.'; -import { category } from '../../../category-constants'; import { ApigwInputState } from '../apigw-input-state'; +import { ADMIN_QUERIES_NAME } from '../../../category-constants'; export class ApigwStackTransform { _app: cdk.App; cliInputs: ApigwInputs; @@ -44,7 +44,7 @@ export class ApigwStackTransform { const pathsWithUserPoolGroups = Object.entries(this.cliInputs.paths).filter(([_, path]) => !!path?.permissions?.groups); - if (this.resourceName === 'AdminQueries' || pathsWithUserPoolGroups.length > 0) { + if (this.resourceName === ADMIN_QUERIES_NAME || pathsWithUserPoolGroups.length > 0) { [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter(resourceName => resourceName !== 'userPoolGroups'); } @@ -172,7 +172,7 @@ export class ApigwStackTransform { ); // Add resources - this.resourceName === 'AdminQueries' + this.resourceName === ADMIN_QUERIES_NAME ? this.resourceTemplateObj.generateAdminQueriesStack(this.resourceName, authResourceName) : this.resourceTemplateObj.generateStackResources(this.resourceName); } @@ -228,7 +228,7 @@ export class ApigwStackTransform { this.cfn = JSONUtilities.parse(this.resourceTemplateObj.renderCloudFormationTemplate()); } - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, this.resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); fs.ensureDirSync(resourceDirPath); const buildDirPath = path.join(resourceDirPath, PathConstants.BuildDirName); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts index d737b33baf3..cfb5eea0313 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts @@ -15,6 +15,7 @@ import { byValues, printer, prompter } from 'amplify-prompts'; import inquirer from 'inquirer'; import os from 'os'; import { v4 as uuid } from 'uuid'; +import { ADMIN_QUERIES_NAME } from '../../../category-constants'; import { ApigwInputState } from '../apigw-input-state'; import { CrudOperation, PermissionSetting } from '../cdk-stack-builder'; import { getAllDefaults } from '../default-values/apigw-defaults'; @@ -66,7 +67,7 @@ export async function updateWalkthrough(context: $TSContext) { updateApiOperation = 'add'; } - if (selectedApiName === 'AdminQueries') { + if (selectedApiName === ADMIN_QUERIES_NAME) { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; printer.warn(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -276,8 +277,8 @@ async function askPermissions( }); //if single user pool group is selected, convert to array - if ( selectedUserPoolGroupList && !Array.isArray(selectedUserPoolGroupList)){ - selectedUserPoolGroupList = [ selectedUserPoolGroupList ]; + if (selectedUserPoolGroupList && !Array.isArray(selectedUserPoolGroupList)) { + selectedUserPoolGroupList = [selectedUserPoolGroupList]; } for (const selectedUserPoolGroup of selectedUserPoolGroupList) { diff --git a/packages/amplify-provider-awscloudformation/src/download-api-models.ts b/packages/amplify-provider-awscloudformation/src/download-api-models.ts index 5d8aff6def5..45f4682483d 100644 --- a/packages/amplify-provider-awscloudformation/src/download-api-models.ts +++ b/packages/amplify-provider-awscloudformation/src/download-api-models.ts @@ -1,10 +1,11 @@ -import fs from 'fs-extra'; +import { $TSContext, $TSObject, pathManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import extract from 'extract-zip'; +import * as fs from 'fs-extra'; import sequential from 'promise-sequential'; -import { $TSContext, pathManager } from 'amplify-cli-core'; import { APIGateway } from './aws-utils/aws-apigw'; -export async function downloadAPIModels(context: $TSContext, allResources) { +export async function downloadAPIModels(context: $TSContext, allResources: $TSObject[]) { const { amplify } = context; const projectConfig = amplify.getProjectConfig(); @@ -18,21 +19,21 @@ export async function downloadAPIModels(context: $TSContext, allResources) { const promises = []; if (resources.length > 0) { - context.print.info('\nCreating API models...'); + printer.info('\nCreating API models...'); } - for (let i = 0; i < resources.length; i += 1) { - if (resources[i].output.ApiName) { - promises.push(() => extractAPIModel(context, resources[i], framework)); + for (const resource of resources) { + if (resource.output.ApiName) { + promises.push(() => extractAPIModel(context, resource, framework)); } } return sequential(promises); } -async function extractAPIModel(context: $TSContext, resource, framework) { +async function extractAPIModel(context: $TSContext, resource: $TSObject, framework: string) { const apigw = await APIGateway.getInstance(context); - const apigwParams = getAPIGWRequestParams(context, resource, framework); + const apigwParams = getAPIGWRequestParams(resource, framework); const apiName = resource.output.ApiName; @@ -53,8 +54,8 @@ async function extractAPIModel(context: $TSContext, resource, framework) { fs.removeSync(tempDir); } -function copyFilesToSrc(context, apiName, framework) { - const backendDir = context.amplify.pathManager.getBackendDirPath(); +function copyFilesToSrc(context: $TSContext, apiName: string, framework: string) { + const backendDir = pathManager.getBackendDirPath(); const tempDir = `${backendDir}/.temp`; switch (framework) { @@ -85,7 +86,7 @@ function copyFilesToSrc(context, apiName, framework) { } } -function getAPIGWRequestParams(_: $TSContext, resource, framework) { +function getAPIGWRequestParams(resource: $TSObject, framework: string) { const apiUrl = resource.output.RootUrl; const apiName = resource.output.ApiName; const firstSplit = apiUrl.split('/'); diff --git a/packages/amplify-provider-awscloudformation/tsconfig.json b/packages/amplify-provider-awscloudformation/tsconfig.json index 07cccf37287..665cb53f448 100644 --- a/packages/amplify-provider-awscloudformation/tsconfig.json +++ b/packages/amplify-provider-awscloudformation/tsconfig.json @@ -15,18 +15,19 @@ "resources/overrides-resource/override.ts" ], "references": [ - {"path": "../amplify-cli-core"}, - {"path": "../amplify-util-import"}, - {"path": "../graphql-auth-transformer"}, - {"path": "../graphql-connection-transformer"}, - {"path": "../graphql-dynamodb-transformer"}, - {"path": "../graphql-elasticsearch-transformer"}, - {"path": "../graphql-function-transformer"}, - {"path": "../graphql-http-transformer"}, - {"path": "../graphql-key-transformer"}, - {"path": "../graphql-predictions-transformer"}, - {"path": "../graphql-transformer-core"}, - {"path": "../graphql-versioned-transformer"}, + { "path": "../amplify-cli-core" }, + { "path": "../amplify-prompts" }, + { "path": "../amplify-util-import" }, + { "path": "../graphql-auth-transformer" }, + { "path": "../graphql-connection-transformer" }, + { "path": "../graphql-dynamodb-transformer" }, + { "path": "../graphql-elasticsearch-transformer" }, + { "path": "../graphql-function-transformer" }, + { "path": "../graphql-http-transformer" }, + { "path": "../graphql-key-transformer" }, + { "path": "../graphql-predictions-transformer" }, + { "path": "../graphql-transformer-core" }, + { "path": "../graphql-versioned-transformer" }, { "path": "../amplify-graphql-transformer-core" }, { "path": "../amplify-graphql-transformer-interfaces" }, ]