Skip to content

Commit

Permalink
feat: add resource parameter map to backend-config.json (#11417)
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardfoyle committed Dec 1, 2022
1 parent 284c264 commit 6500436
Show file tree
Hide file tree
Showing 33 changed files with 555 additions and 134 deletions.
2 changes: 2 additions & 0 deletions .circleci/config.base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ jobs:
executor: l_large
steps:
- checkout
- run: yarn config set script-shell $(which bash)
- run: yarn run production-build
- run:
name: Build tests
Expand Down Expand Up @@ -130,6 +131,7 @@ jobs:
equal: [*windows-e2e-executor-xlarge, << parameters.os >>]
steps:
- checkout
- run: yarn config set script-shell $(which bash)
- run: yarn run production-build
- run:
name: Build tests
Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-appsync-simulator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"access": "public"
},
"scripts": {
"copy-assets": "yarn rimraf ./public && yarn copyfiles -u 3 \"../amplify-graphiql-explorer/build/**/*\" ./public",
"copy-assets": "rimraf ./public && copyfiles -u 3 \"../amplify-graphiql-explorer/build/**/*\" ./public",
"build": "yarn copy-assets && tsc",
"build-tests": "tsc --build tsconfig.tests.json",
"clean": "rimraf ./lib tsconfig.tsbuildinfo tsconfig.tests.tsbuildinfo node_modules",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,16 @@ const writeNotificationsTeamProviderInfo = async (pinpointMeta: $TSAny): Promise
if (!pinpointMeta) {
return;
}
getEnvParamManager().getResourceParamManager(AmplifyCategories.NOTIFICATIONS, AmplifySupportedService.PINPOINT).setAllParams({
const envParamManager = getEnvParamManager();
const params = {
Name: pinpointMeta.Name,
Id: pinpointMeta.Id,
Region: pinpointMeta.Region,
});
};
// set params in the notifications and analytics resource param manager
[AmplifyCategories.NOTIFICATIONS, AmplifyCategories.ANALYTICS]
.map(category => envParamManager.getResourceParamManager(category, AmplifySupportedService.PINPOINT))
.forEach(resourceParamManager => { resourceParamManager.setAllParams(params); });
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ jest.mock('amplify-cli-core', () => ({
}),
getLocalEnvInfo: jest.fn().mockReturnValue({ envName: 'testEnv' }),
getTeamProviderInfo: jest.fn(),
getBackendConfig: jest.fn(),
},
}));

Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-category-custom/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type AmplifyResourceProps = {
export const executeAmplifyCommand: (context: $TSContext) => Promise<void>;

// @public (undocumented)
export const generateDependentResourcesType: (context: $TSContext) => Promise<void>;
export const generateDependentResourcesType: () => Promise<void>;

// @public (undocumented)
export const handleAmplifyEvent: (__context: $TSContext, args: $TSAny) => Promise<void>;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ jest.mock('fs-extra', () => ({
readFileSync: jest.fn().mockReturnValue('mockCode'),
existsSync: jest.fn().mockReturnValue(true),
ensureDirSync: jest.fn().mockReturnValue(true),
ensureDir: jest.fn(),
writeFileSync: jest.fn().mockReturnValue(true),
writeFile: jest.fn(),
}));

jest.mock('ora', () => {
return () => ({
start: jest.fn(),
fail: jest.fn(),
succeed: jest.fn(),
stop: jest.fn(),
});
});
jest.mock('ora', () => () => ({
start: jest.fn(),
fail: jest.fn(),
succeed: jest.fn(),
stop: jest.fn(),
}));

jest.mock('../../utils/dependency-management-utils', () => ({
getAllResources: jest.fn().mockResolvedValue({ mockedvalue: 'mockedkey' }),
Expand All @@ -41,6 +41,7 @@ jest.mock('amplify-cli-core', () => ({
JSONUtilities: {
writeJson: jest.fn(),
readJson: jest.fn(),
stringify: jest.fn(),
},
}));

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
$TSAny,
$TSContext, AmplifyError, getPackageManager, pathManager, ResourceTuple,
$TSContext, AmplifyError, getPackageManager, JSONUtilities, pathManager, ResourceTuple,
} from 'amplify-cli-core';
import { printer } from 'amplify-prompts';
import execa from 'execa';
Expand All @@ -11,9 +11,6 @@ import { categoryName, TYPES_DIR_NAME, AMPLIFY_RESOURCES_TYPE_DEF_FILENAME } fro
import { getAllResources } from './dependency-management-utils';
import { generateCloudFormationFromCDK } from './generate-cfn-from-cdk';

const resourcesDirRoot = path.normalize(path.join(__dirname, '../../resources'));
const amplifyDependentResourcesFilename = 'amplify-dependent-resources-ref.ejs';

type ResourceMeta = ResourceTuple & {
service: string;
build: boolean;
Expand All @@ -30,7 +27,7 @@ export const buildCustomResources = async (context: $TSContext, resourceName?: s

const resourcesToBuild = (await getSelectedResources(context, resourceName)).filter(resource => resource.service === 'customCDK');
for await (const resource of resourcesToBuild) {
await buildResource(context, resource);
await buildResource(resource);
}
} catch (err: $TSAny) {
throw new AmplifyError('InvalidCustomResourceError', {
Expand All @@ -48,33 +45,21 @@ const getSelectedResources = async (context: $TSContext, resourceName?: string)

/**
* generates dependent resource type
* @param context object
*/
export const generateDependentResourcesType = async (context: $TSContext): Promise<void> => {
export const generateDependentResourcesType = async (): Promise<void> => {
const resourceDirPath = path.join(pathManager.getBackendDirPath(), TYPES_DIR_NAME);
const target = path.join(resourceDirPath, AMPLIFY_RESOURCES_TYPE_DEF_FILENAME);
const dependentResourceAttributesFileContent = `export type AmplifyDependentResourcesAttributes = ${JSONUtilities.stringify(getAllResources(), { orderedKeys: true })}`;

const copyJobs = [
{
dir: resourcesDirRoot,
template: amplifyDependentResourcesFilename,
target: path.join(resourceDirPath, AMPLIFY_RESOURCES_TYPE_DEF_FILENAME),
},
];

const allResources = getAllResources();

const params = {
dependentResourcesType: allResources,
};

await context.amplify.copyBatch(context, copyJobs, params, true);
await fs.ensureDir(path.dirname(target));
await fs.writeFile(target, dependentResourceAttributesFileContent);
};

const buildResource = async (context: $TSContext, resource: ResourceMeta): Promise<void> => {
const buildResource = async (resource: ResourceMeta): Promise<void> => {
const targetDir = path.resolve(path.join(pathManager.getBackendDirPath(), categoryName, resource.resourceName));

// generate dynamic types for Amplify resources
await generateDependentResourcesType(context);
await generateDependentResourcesType();

const packageManager = getPackageManager(targetDir);

Expand Down
2 changes: 1 addition & 1 deletion packages/amplify-category-interactions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"build": "tsc && yarn copy-templates",
"clean": "rimraf lib tsconfig.tsbuildinfo node_modules",
"watch": "tsc --watch",
"copy-templates": "copyfiles -u 4 src/provider-utils/awscloudformation/cloudformation-templates/* lib/provider-utils/awscloudformation/cloudformation-templates/ && yarn copyfiles -u 4 src/provider-utils/awscloudformation/function-template-dir/*.ejs lib/provider-utils/awscloudformation/function-template-dir/",
"copy-templates": "copyfiles -u 4 src/provider-utils/awscloudformation/cloudformation-templates/* lib/provider-utils/awscloudformation/cloudformation-templates/ && copyfiles -u 4 src/provider-utils/awscloudformation/function-template-dir/*.ejs lib/provider-utils/awscloudformation/function-template-dir/",
"extract-api": "ts-node ../../scripts/extract-api.ts"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ const writeTeamProviderInfo = (pinpointMeta: $TSAny): void => {
if (!pinpointMeta) {
return;
}
getEnvParamManager().getResourceParamManager(AmplifyCategories.ANALYTICS, AmplifySupportedService.PINPOINT).setAllParams({
const envParamManager = getEnvParamManager();
const params = {
Name: pinpointMeta.Name,
Id: pinpointMeta.Id,
Region: pinpointMeta.Region,
});
};
[AmplifyCategories.NOTIFICATIONS, AmplifyCategories.ANALYTICS]
.map(category => envParamManager.getResourceParamManager(category, AmplifySupportedService.PINPOINT))
.forEach(resourceParamManager => { resourceParamManager.setAllParams(params); });
};

const updateBackendConfig = (pinpointMeta: $TSAny, backendConfig: $TSAny): $TSAny => {
Expand Down Expand Up @@ -67,16 +71,17 @@ export const writeData = async (context: $TSContext, channelAPIResponse: IChanne
// This normalization will be removed once all notifications are deployed through CFN
let pinpointMeta;
if (notificationsServiceMeta) {
const applicationId = (notificationsServiceMeta.Id) || analyticsMeta[notificationsServiceMeta.ResourceName]?.output?.Id;
const lastPushTimeStamp = (notificationsServiceMeta.lastPushTimeStamp)
|| (analyticsMeta[notificationsServiceMeta.ResourceName]?.lastPushTimeStamp);
const applicationId = notificationsServiceMeta.Id || analyticsMeta[notificationsServiceMeta.ResourceName]?.output?.Id;
const lastPushTimeStamp = notificationsServiceMeta.lastPushTimeStamp
|| analyticsMeta[notificationsServiceMeta.ResourceName]?.lastPushTimeStamp;
const region = notificationsServiceMeta.Region || analyticsMeta[notificationsServiceMeta.ResourceName]?.output?.Region;
pinpointMeta = {
serviceName: notificationsServiceMeta.ResourceName,
service: notificationsServiceMeta.service,
channels: enabledChannels,
Name: notificationsServiceMeta.output.Name,
Id: applicationId,
Region: notificationsServiceMeta.Region,
Region: region,
lastPushTimeStamp,
};
}
Expand Down
12 changes: 6 additions & 6 deletions packages/amplify-cli-core/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class AmplifyError extends AmplifyException {
}

// @public (undocumented)
export type AmplifyErrorType = 'AmplifyStudioError' | 'AmplifyStudioLoginError' | 'AmplifyStudioNotEnabledError' | 'ApiCategorySchemaNotFoundError' | 'AuthImportError' | 'BucketAlreadyExistsError' | 'BucketNotFoundError' | 'CategoryNotEnabledError' | 'CloudFormationTemplateError' | 'CommandNotSupportedError' | 'ConfigurationError' | 'DeploymentError' | 'DeploymentInProgressError' | 'DirectoryError' | 'DirectoryAlreadyExistsError' | 'DuplicateLogicalIdError' | 'EnvironmentConfigurationError' | 'EnvironmentNameError' | 'EnvironmentNotInitializedError' | 'FeatureFlagsValidationError' | 'FrameworkNotSupportedError' | 'FunctionTooLargeError' | 'InputValidationError' | 'InvalidAmplifyAppIdError' | 'InvalidCustomResourceError' | 'InvalidOverrideError' | 'InvalidStackError' | 'IterativeRollbackError' | 'LambdaLayerDeleteError' | 'MigrationError' | 'MissingAmplifyMetaFileError' | 'MissingOverridesInstallationRequirementsError' | 'ModelgenError' | 'NestedProjectInitError' | 'NoUpdateBackendError' | 'NotImplementedError' | 'OpenSslCertificateError' | 'ParameterNotFoundError' | 'PermissionsError' | 'PluginMethodNotFoundError' | 'PluginNotFoundError' | 'PluginPolicyAddError' | 'ProfileConfigurationError' | 'ProjectAppIdResolveError' | 'ProjectInitError' | 'ProjectNotFoundError' | 'ProjectNotInitializedError' | 'PushResourcesError' | 'RegionNotAvailableError' | 'RemoveNotificationAppError' | 'ResourceAlreadyExistsError' | 'ResourceInUseError' | 'ResourceNotReadyError' | 'StackNotFoundError' | 'StackStateError' | 'UserInputError' | 'MockProcessError' | 'SearchableMockUnsupportedPlatformError' | 'SearchableMockUnavailablePortError' | 'SearchableMockProcessError';
export type AmplifyErrorType = 'AmplifyStudioError' | 'AmplifyStudioLoginError' | 'AmplifyStudioNotEnabledError' | 'ApiCategorySchemaNotFoundError' | 'AuthImportError' | 'BackendConfigValidationError' | 'BucketAlreadyExistsError' | 'BucketNotFoundError' | 'CategoryNotEnabledError' | 'CloudFormationTemplateError' | 'CommandNotSupportedError' | 'ConfigurationError' | 'DeploymentError' | 'DeploymentInProgressError' | 'DirectoryError' | 'DirectoryAlreadyExistsError' | 'DuplicateLogicalIdError' | 'EnvironmentConfigurationError' | 'EnvironmentNameError' | 'EnvironmentNotInitializedError' | 'FeatureFlagsValidationError' | 'FrameworkNotSupportedError' | 'FunctionTooLargeError' | 'InputValidationError' | 'InvalidAmplifyAppIdError' | 'InvalidCustomResourceError' | 'InvalidOverrideError' | 'InvalidStackError' | 'IterativeRollbackError' | 'LambdaLayerDeleteError' | 'MigrationError' | 'MissingAmplifyMetaFileError' | 'MissingOverridesInstallationRequirementsError' | 'ModelgenError' | 'NestedProjectInitError' | 'NoUpdateBackendError' | 'NotImplementedError' | 'OpenSslCertificateError' | 'ParameterNotFoundError' | 'PermissionsError' | 'PluginMethodNotFoundError' | 'PluginNotFoundError' | 'PluginPolicyAddError' | 'ProfileConfigurationError' | 'ProjectAppIdResolveError' | 'ProjectInitError' | 'ProjectNotFoundError' | 'ProjectNotInitializedError' | 'PushResourcesError' | 'RegionNotAvailableError' | 'RemoveNotificationAppError' | 'ResourceAlreadyExistsError' | 'ResourceInUseError' | 'ResourceNotReadyError' | 'StackNotFoundError' | 'StackStateError' | 'UserInputError' | 'MockProcessError' | 'SearchableMockUnsupportedPlatformError' | 'SearchableMockUnavailablePortError' | 'SearchableMockProcessError';

// @public (undocumented)
export abstract class AmplifyException extends Error {
Expand Down Expand Up @@ -966,16 +966,16 @@ export class JSONUtilities {
preserveComments?: boolean | undefined;
} | undefined) => T | undefined;
// (undocumented)
static stringify: (data: any, options?: {
static stringify: (data: unknown, options?: {
minify?: boolean | undefined;
keepComments?: boolean | undefined;
orderedKeys?: boolean | undefined;
} | undefined) => string | undefined;
// (undocumented)
static writeJson: (fileName: string, data: any, options?: {
keepComments?: boolean | undefined;
static writeJson: (fileName: string, data: unknown, options?: {
mode?: number | undefined;
minify?: boolean | undefined;
secureFile?: boolean | undefined;
orderedKeys?: boolean | undefined;
} | undefined) => void;
}

Expand Down Expand Up @@ -1317,7 +1317,7 @@ export class StateManager {
// (undocumented)
getAppID: () => string;
// (undocumented)
getBackendConfig: (projectPath?: string | undefined, options?: GetOptions<any> | undefined) => $TSAny;
getBackendConfig: (projectPath?: string | undefined, options?: GetOptions<any> | undefined, includeParameters?: boolean) => $TSAny;
// (undocumented)
getCLIJSON: (projectPath: string, env?: string | undefined, options?: GetOptions<any> | undefined) => $TSAny;
// (undocumented)
Expand Down
34 changes: 17 additions & 17 deletions packages/amplify-cli-core/src/__tests__/jsonUtilities.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { JSONUtilities } from '../jsonUtilities';
import * as fs from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import * as rimraf from 'rimraf';
import { v4 as uuid } from 'uuid';
import { JSONUtilities } from '../jsonUtilities';

describe('JSONUtilities tests', () => {
const jsonString = `{
Expand Down Expand Up @@ -41,13 +41,13 @@ describe('JSONUtilities tests', () => {

test('readJson throws error when fileName is not specified', () => {
expect(() => {
const _ = JSONUtilities.readJson((undefined as unknown) as string);
JSONUtilities.readJson((undefined as unknown) as string);
}).toThrowError(`'fileName' argument missing`);
});

test('readJson throws error for non-existing file', () => {
expect(() => {
const _ = JSONUtilities.readJson('/test.json');
JSONUtilities.readJson('/test.json');
}).toThrowError(`File at path: '/test.json' does not exist`);
});

Expand All @@ -60,6 +60,7 @@ describe('JSONUtilities tests', () => {
});

test('writeJson successfully writes file and creating nested directories', () => {
// eslint-disable-next-line spellcheck/spell-checker
const osTempDir = fs.realpathSync(os.tmpdir());
const topTempDir = path.join(osTempDir, `amp-${uuid()}`);
const nestedTempDir = path.join(topTempDir, 'f1', 'f2');
Expand All @@ -84,13 +85,13 @@ describe('JSONUtilities tests', () => {

test('writeJson throws error when fileName is not specified', () => {
expect(() => {
const _ = JSONUtilities.writeJson((undefined as unknown) as string, (undefined as unknown) as string);
JSONUtilities.writeJson((undefined as unknown) as string, (undefined as unknown) as string);
}).toThrowError(`'fileName' argument missing`);
});

test('writeJson throws error when data is not specified', () => {
expect(() => {
const _ = JSONUtilities.writeJson('test.json', (undefined as unknown) as string);
JSONUtilities.writeJson('test.json', (undefined as unknown) as string);
}).toThrowError(`'data' argument missing`);
});

Expand All @@ -104,7 +105,8 @@ describe('JSONUtilities tests', () => {
});

test('JSON parse with BOM', () => {
const withBom = '\ufeff' + jsonString;
// eslint-disable-next-line spellcheck/spell-checker
const withBom = `\ufeff${jsonString}`;
const data = JSONUtilities.parse(withBom);

expect(data).toMatchObject({
Expand All @@ -115,11 +117,9 @@ describe('JSONUtilities tests', () => {

test.skip('JSON roundtrip preserve comments', () => {
const data = JSONUtilities.parse(jsonString, { preserveComments: true });
const roundtrippedString = JSONUtilities.stringify(data, {
keepComments: true,
});
const roundTripString = JSONUtilities.stringify(data);

expect(jsonString).toEqual(roundtrippedString);
expect(jsonString).toEqual(roundTripString);
});

test('JSON parse returns successfully for non-string parameters', () => {
Expand All @@ -144,18 +144,18 @@ describe('JSONUtilities tests', () => {

test('stringify compatible with builtin JSON.stringify', () => {
const data = JSONUtilities.parse(jsonString);
const hjsonString = JSONUtilities.stringify(data);
const utilsString = JSONUtilities.stringify(data);
const builtinJsonString = JSON.stringify(data, null, 2);

expect(hjsonString).toEqual(builtinJsonString);
expect(utilsString).toEqual(builtinJsonString);
});

test('minified stringify using builtin JSON.stringify', () => {
const data = JSONUtilities.parse(jsonString);
const hjsonString = JSONUtilities.stringify(data, { minify: true });
const utilsString = JSONUtilities.stringify(data, { minify: true });
const builtinJsonString = JSON.stringify(data);

expect(hjsonString).toEqual(builtinJsonString);
expect(utilsString).toEqual(builtinJsonString);
});

test('JSON parse throws error when jsonString is undefined', () => {
Expand All @@ -166,13 +166,13 @@ describe('JSONUtilities tests', () => {

test('JSON parse throws error when jsonString is empty string', () => {
expect(() => {
const _ = JSONUtilities.parse('');
JSONUtilities.parse('');
}).toThrowError(`'jsonString' argument missing or empty`);
});

test('JSON stringify throws error when data is undefined', () => {
expect(() => {
const _ = JSONUtilities.stringify((undefined as unknown) as any);
JSONUtilities.stringify((undefined as unknown) as any);
}).toThrowError(`'data' argument missing`);
});

Expand All @@ -184,7 +184,7 @@ describe('JSONUtilities tests', () => {
"bar": 1 // Line comments
`;

const _ = JSONUtilities.parse(malformedJsonString);
JSONUtilities.parse(malformedJsonString);
}).toThrowError(`Expected ':' instead of '"' at line 3,9 >>> "foo" "bar",`);
});
});
1 change: 1 addition & 0 deletions packages/amplify-cli-core/src/errors/amplify-exception.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export type AmplifyErrorType =
| 'AmplifyStudioNotEnabledError'
| 'ApiCategorySchemaNotFoundError'
| 'AuthImportError'
| 'BackendConfigValidationError'
| 'BucketAlreadyExistsError'
| 'BucketNotFoundError'
| 'CategoryNotEnabledError'
Expand Down

0 comments on commit 6500436

Please sign in to comment.