Skip to content

Commit 07899bb

Browse files
authored
Merge pull request #14123 from bzsurbhi/migrations
chore: copy schema in data/resource.ts, add error message if env variable is not set
2 parents caac9f4 + a6a3606 commit 07899bb

15 files changed

Lines changed: 402 additions & 1360 deletions

File tree

packages/amplify-gen2-codegen/API.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export type CustomAttributes = Partial<Record<`custom:${string}`, CustomAttribut
8282
// @public (undocumented)
8383
export type DataDefinition = {
8484
tableMappings: Record<string, DataTableMapping | undefined>;
85+
schema: string;
8586
};
8687

8788
// @public (undocumented)

packages/amplify-gen2-codegen/src/backend/synthesizer.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,4 +523,19 @@ describe('BackendRenderer', () => {
523523
expect(output).toContain(`generateSecret: false\n});`);
524524
});
525525
});
526+
describe('environment variables', () => {
527+
it('renders dynamic environment variables', () => {
528+
const renderer = new BackendSynthesizer();
529+
const rendered = renderer.render({
530+
auth: {
531+
importFrom: './auth/resource.ts',
532+
},
533+
});
534+
const output = printNodeArray(rendered);
535+
assert(output.includes('process.env.AMPLIFY_GEN_1_ENV_NAME'));
536+
assert(output.includes('ci.isCI && !AMPLIFY_GEN_1_ENV_NAME'));
537+
assert(output.includes('throw new Error("AMPLIFY_GEN_1_ENV_NAME is required in CI environment")'));
538+
assert(output.includes('AMPLIFY_GEN_1_ENV_NAME = "sandbox"'));
539+
});
540+
});
526541
});

packages/amplify-gen2-codegen/src/backend/synthesizer.ts

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -464,14 +464,74 @@ export class BackendSynthesizer {
464464
);
465465
}
466466

467+
private createAmplifyEnvNameLogic() {
468+
// Create: let AMPLIFY_GEN_1_ENV_NAME = process.env.AMPLIFY_GEN_1_ENV_NAME;
469+
const variableDeclaration = factory.createVariableStatement(
470+
undefined,
471+
factory.createVariableDeclarationList(
472+
[
473+
factory.createVariableDeclaration(
474+
factory.createIdentifier('AMPLIFY_GEN_1_ENV_NAME'),
475+
undefined,
476+
undefined,
477+
factory.createPropertyAccessExpression(
478+
factory.createPropertyAccessExpression(factory.createIdentifier('process'), factory.createIdentifier('env')),
479+
factory.createIdentifier('AMPLIFY_GEN_1_ENV_NAME'),
480+
),
481+
),
482+
],
483+
ts.NodeFlags.Let,
484+
),
485+
);
486+
487+
// Create: if (ci.isCI && !AMPLIFY_GEN_1_ENV_NAME) { ... } else if (!ci.isCI) { ... }
488+
const ifStatement = factory.createIfStatement(
489+
// Condition: ci.isCI && !AMPLIFY_GEN_1_ENV_NAME
490+
factory.createLogicalAnd(
491+
factory.createPropertyAccessExpression(factory.createIdentifier('ci'), factory.createIdentifier('isCI')),
492+
factory.createLogicalNot(factory.createIdentifier('AMPLIFY_GEN_1_ENV_NAME')),
493+
),
494+
// Then block: throw new Error('...')
495+
factory.createBlock(
496+
[
497+
factory.createThrowStatement(
498+
factory.createNewExpression(factory.createIdentifier('Error'), undefined, [
499+
factory.createStringLiteral('AMPLIFY_GEN_1_ENV_NAME is required in CI environment'),
500+
]),
501+
),
502+
],
503+
true,
504+
),
505+
// Else block: if (!ci.isCI) { ... }
506+
factory.createIfStatement(
507+
factory.createLogicalNot(factory.createPropertyAccessExpression(factory.createIdentifier('ci'), factory.createIdentifier('isCI'))),
508+
// Then block: AMPLIFY_GEN_1_ENV_NAME = 'sandbox';
509+
factory.createBlock(
510+
[
511+
factory.createExpressionStatement(
512+
factory.createBinaryExpression(
513+
factory.createIdentifier('AMPLIFY_GEN_1_ENV_NAME'),
514+
factory.createToken(ts.SyntaxKind.EqualsToken),
515+
factory.createStringLiteral('sandbox'),
516+
),
517+
),
518+
],
519+
true,
520+
),
521+
),
522+
);
523+
524+
return [variableDeclaration, ifStatement];
525+
}
526+
467527
render(renderArgs: BackendRenderParameters): NodeArray<Node> {
468528
const authFunctionIdentifier = factory.createIdentifier('auth');
469529
const storageFunctionIdentifier = factory.createIdentifier('storage');
470530
const dataFunctionIdentifier = factory.createIdentifier('data');
471531
const backendFunctionIdentifier = factory.createIdentifier('defineBackend');
472532

473533
const imports = [];
474-
const errors: ts.CallExpression[] = [];
534+
const errors = [];
475535
const defineBackendProperties = [];
476536
const nodes = [];
477537

@@ -554,23 +614,23 @@ export class BackendSynthesizer {
554614
}
555615
}
556616

617+
const ciInfoImportStatement = factory.createImportDeclaration(
618+
undefined,
619+
factory.createImportClause(false, factory.createIdentifier('ci'), undefined),
620+
factory.createStringLiteral('ci-info'),
621+
);
622+
623+
imports.push(ciInfoImportStatement);
624+
const envNameStatements = this.createAmplifyEnvNameLogic();
625+
errors.push(...envNameStatements);
626+
557627
const callBackendFn = this.defineBackendCall(backendFunctionIdentifier, defineBackendProperties);
558628
const backendVariable = factory.createVariableDeclaration('backend', undefined, undefined, callBackendFn);
559629
const backendStatement = factory.createVariableStatement(
560630
[],
561631
factory.createVariableDeclarationList([backendVariable], ts.NodeFlags.Const),
562632
);
563633

564-
const amplifyGen1EnvStatement = this.createVariableStatement(
565-
factory.createVariableDeclaration(
566-
'AMPLIFY_GEN_1_ENV_NAME',
567-
undefined,
568-
undefined,
569-
factory.createIdentifier('process.env.AMPLIFY_GEN_1_ENV_NAME ?? "sandbox"'),
570-
),
571-
);
572-
nodes.push(amplifyGen1EnvStatement);
573-
574634
if (renderArgs.auth?.userPoolOverrides && !renderArgs?.auth?.referenceAuth) {
575635
const cfnUserPoolVariableStatement = this.createVariableStatement(
576636
this.createVariableDeclaration('cfnUserPool', 'auth.resources.cfnResources.cfnUserPool'),

packages/amplify-gen2-codegen/src/data/source_builder.test.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
import assert from 'node:assert';
22
import { printNodeArray } from '../test_utils/ts_node_printer';
3-
import { generateDataSource, schemaPlaceholderComment } from './source_builder';
3+
import { generateDataSource } from './source_builder';
44
describe('Data Category code generation', () => {
5-
it('generates the schema placeholder comment', () => {
6-
const source = printNodeArray(generateDataSource());
7-
assert.match(source, new RegExp(`schema: "${schemaPlaceholderComment}"`));
8-
});
9-
it('generates the TODO error for the schema', () => {
10-
const source = printNodeArray(generateDataSource());
11-
assert.match(source, /throw new Error\("TODO: Add Gen 1 GraphQL schema"\)/);
12-
});
135
it('generates the correct import', () => {
146
const source = printNodeArray(generateDataSource());
157
assert.match(source, /import\s?\{\s?defineData\s?\}\s?from\s?"\@aws-amplify\/backend"/);
168
});
179
describe('import map', () => {
1810
it('is rendered', () => {
1911
const tableMappings = { dev: { Todo: 'my-todo-mapping' } };
20-
const source = printNodeArray(generateDataSource({ tableMappings }));
12+
const source = printNodeArray(generateDataSource({ tableMappings, schema: 'schema' }));
2113
assert.match(
2214
source,
2315
/migratedAmplifyGen1DynamoDbTableMap: \[\{\n\s+\/\/ Replace the environment name \(dev\) with the corresponding branch name. Use ['"]sandbox['"] for your sandbox environment.\n\s+branchName: ['"]dev['"],\n\s+modelTableNameMap: { Todo: ['"]my-todo-mapping['"] }\n\s+}]/,
@@ -28,7 +20,7 @@ describe('Data Category code generation', () => {
2820
dev: { Todo: 'my-todo-mapping' },
2921
prod: { Todo: 'my-todo-mapping-prod' },
3022
};
31-
const source = printNodeArray(generateDataSource({ tableMappings }));
23+
const source = printNodeArray(generateDataSource({ tableMappings, schema: 'schema' }));
3224
assert.match(
3325
source,
3426
/migratedAmplifyGen1DynamoDbTableMap: \[\{\n\s+\/\/ Replace the environment name \(dev\) with the corresponding branch name. Use ['"]sandbox['"] for your sandbox environment.\n\s+branchName: ['"]dev['"],\n\s+modelTableNameMap: { Todo: ['"]my-todo-mapping['"] }\n\s+}, {\n\s+\/\/ Replace the environment name \(prod\) with the corresponding branch name. Use ['"]sandbox['"] for your sandbox environment.\n\s+branchName: ['"]prod['"],\n\s+modelTableNameMap: { Todo: ['"]my-todo-mapping-prod['"] }\n\s+}]/,
@@ -38,18 +30,18 @@ describe('Data Category code generation', () => {
3830
const tableMappings = {
3931
dev: undefined,
4032
};
41-
const source = printNodeArray(generateDataSource({ tableMappings }));
33+
const source = printNodeArray(generateDataSource({ tableMappings, schema: 'schema' }));
4234
assert.match(
4335
source,
4436
/\/\*\*\n\s+\* Unable to find the table mapping for this environment.\n\s+\* This could be due the enableGen2Migration feature flag not being set to true for this environment.\n\s+\* Please enable the feature flag and push the backend resources.\n\s+\* If you are not planning to migrate this environment, you can remove this key.\n\s+\*\/\n\s+modelTableNameMap: {}/,
4537
);
4638
});
4739
it('has each each key in defineData', () => {
4840
const tableMappings = { dev: { Todo: 'my-todo-mapping' } };
49-
const source = printNodeArray(generateDataSource({ tableMappings }));
41+
const source = printNodeArray(generateDataSource({ tableMappings, schema: 'schema' }));
5042
assert.match(
5143
source,
52-
/defineData\({\n\s+migratedAmplifyGen1DynamoDbTableMap: \[\{\n\s+\/\/ Replace the environment name \(dev\) with the corresponding branch name. Use ['"]sandbox['"] for your sandbox environment.\n\s+branchName: ['"]dev['"],\n\s+modelTableNameMap: { Todo: ['"]my-todo-mapping['"] }\n\s+}],\n\s+schema: "TODO: Add your existing graphql schema here"\n}\)/,
44+
/const schema \= \`schema\`\;\nexport const data \= defineData\({\n\s+migratedAmplifyGen1DynamoDbTableMap: \[\{\n\s+\/\/ Replace the environment name \(dev\) with the corresponding branch name. Use ['"]sandbox['"] for your sandbox environment.\n\s+branchName: ['"]dev['"],\n\s+modelTableNameMap: { Todo: ['"]my-todo-mapping['"] }\n\s+}],\n\s+schema\n}\)/,
5345
);
5446
});
5547
});

packages/amplify-gen2-codegen/src/data/source_builder.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
import ts, { ObjectLiteralElementLike, ObjectLiteralExpression } from 'typescript';
22
import { renderResourceTsFile } from '../resource/resource';
3-
import { createTodoError } from '../todo_error';
43
const factory = ts.factory;
54

65
export type DataTableMapping = Record<string, string>;
76
export type DataDefinition = {
87
tableMappings: Record<string, DataTableMapping | undefined>;
8+
schema: string;
99
};
1010

1111
const migratedAmplifyGen1DynamoDbTableMapKeyName = 'migratedAmplifyGen1DynamoDbTableMap';
1212

13-
export const schemaPlaceholderComment = 'TODO: Add your existing graphql schema here';
14-
1513
export const generateDataSource = (dataDefinition?: DataDefinition): ts.NodeArray<ts.Node> => {
1614
const dataRenderProperties: ObjectLiteralElementLike[] = [];
1715
const namedImports: Record<string, Set<string>> = { '@aws-amplify/backend': new Set() };
1816
namedImports['@aws-amplify/backend'].add('defineData');
1917

18+
const schemaStatements: ts.Node[] = [];
19+
20+
if (dataDefinition && dataDefinition.schema) {
21+
const schemaVariableDeclaration = factory.createVariableDeclaration(
22+
'schema',
23+
undefined,
24+
undefined,
25+
factory.createNoSubstitutionTemplateLiteral(dataDefinition.schema),
26+
);
27+
const schemaStatementAssignment = factory.createVariableStatement(
28+
[],
29+
factory.createVariableDeclarationList([schemaVariableDeclaration], ts.NodeFlags.Const),
30+
);
31+
schemaStatements.push(schemaStatementAssignment);
32+
}
33+
2034
if (dataDefinition?.tableMappings) {
2135
const tableMappingEnvironments: ObjectLiteralExpression[] = [];
2236
for (const [environmentName, tableMapping] of Object.entries(dataDefinition.tableMappings)) {
@@ -61,14 +75,12 @@ export const generateDataSource = (dataDefinition?: DataDefinition): ts.NodeArra
6175
),
6276
);
6377
}
64-
dataRenderProperties.push(
65-
factory.createPropertyAssignment(factory.createIdentifier('schema'), factory.createStringLiteral(schemaPlaceholderComment)),
66-
);
78+
dataRenderProperties.push(factory.createShorthandPropertyAssignment(factory.createIdentifier('schema')));
6779
return renderResourceTsFile({
6880
exportedVariableName: factory.createIdentifier('data'),
6981
functionCallParameter: factory.createObjectLiteralExpression(dataRenderProperties, true),
70-
postExportStatements: [createTodoError('Add Gen 1 GraphQL schema')],
7182
backendFunctionConstruct: 'defineData',
83+
postImportStatements: schemaStatements,
7284
additionalImportedBackendIdentifiers: namedImports,
7385
});
7486
};

packages/amplify-gen2-codegen/src/function/source_builder.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ts, { ObjectLiteralElementLike } from 'typescript';
1+
import ts, { ObjectLiteralElementLike, VariableDeclaration, VariableStatement } from 'typescript';
22
import { EnvironmentResponse, Runtime } from '@aws-sdk/client-lambda';
33
import { renderResourceTsFile } from '../resource/resource';
44

@@ -15,36 +15,60 @@ export interface FunctionDefinition {
1515

1616
const factory = ts.factory;
1717

18-
const createParameter = (name: string, value: ts.LiteralExpression | ts.ObjectLiteralExpression): ts.PropertyAssignment =>
19-
factory.createPropertyAssignment(factory.createIdentifier(name), value);
18+
const amplifyGen1EnvName = 'AMPLIFY_GEN_1_ENV_NAME';
19+
20+
const createParameter = (
21+
name: string,
22+
value: ts.LiteralExpression | ts.ObjectLiteralExpression | ts.TemplateExpression,
23+
): ts.PropertyAssignment => factory.createPropertyAssignment(factory.createIdentifier(name), value);
24+
25+
const createVariableStatement = (variableDeclaration: VariableDeclaration): VariableStatement => {
26+
return factory.createVariableStatement([], factory.createVariableDeclarationList([variableDeclaration], ts.NodeFlags.Const));
27+
};
28+
29+
const createTemplateLiteral = (templateHead: string, templateSpan: string, templateTail: string) => {
30+
return factory.createTemplateExpression(factory.createTemplateHead(templateHead), [
31+
factory.createTemplateSpan(factory.createIdentifier(templateSpan), factory.createTemplateTail(templateTail)),
32+
]);
33+
};
2034

2135
export function renderFunctions(definition: FunctionDefinition, appId?: string, backendEnvironmentName?: string | undefined) {
22-
const groupsComment: (ts.CallExpression | ts.JSDoc)[] = [];
36+
const postImportStatements = [];
2337
const namedImports: Record<string, Set<string>> = { '@aws-amplify/backend': new Set() };
2438
namedImports['@aws-amplify/backend'].add('defineFunction');
2539

26-
groupsComment.push(
40+
postImportStatements.push(
2741
factory.createCallExpression(factory.createIdentifier('throw new Error'), undefined, [
2842
factory.createStringLiteral(
2943
`Source code for this function can be found in your Amplify Gen 1 Directory. See .amplify/migration/amplify/backend/function/${definition.resourceName}/src`,
3044
),
3145
]),
3246
);
3347

34-
const defineFunctionProperty = createFunctionDefinition(definition, groupsComment, namedImports, appId, backendEnvironmentName);
48+
const defineFunctionProperty = createFunctionDefinition(definition, postImportStatements, namedImports, appId, backendEnvironmentName);
49+
50+
const amplifyGen1EnvStatement = createVariableStatement(
51+
factory.createVariableDeclaration(
52+
amplifyGen1EnvName,
53+
undefined,
54+
undefined,
55+
factory.createIdentifier('process.env.AMPLIFY_GEN_1_ENV_NAME ?? "sandbox"'),
56+
),
57+
);
58+
postImportStatements.push(amplifyGen1EnvStatement);
3559

3660
return renderResourceTsFile({
3761
exportedVariableName: factory.createIdentifier(definition?.resourceName || 'sayHello'),
3862
functionCallParameter: factory.createObjectLiteralExpression(defineFunctionProperty, true),
3963
backendFunctionConstruct: 'defineFunction',
4064
additionalImportedBackendIdentifiers: namedImports,
41-
postImportStatements: groupsComment,
65+
postImportStatements,
4266
});
4367
}
4468

4569
export function createFunctionDefinition(
4670
definition?: FunctionDefinition,
47-
groupsComment?: (ts.CallExpression | ts.JSDoc)[],
71+
postImportStatements?: (ts.CallExpression | ts.JSDoc)[],
4872
namedImports?: Record<string, Set<string>>,
4973
appId?: string,
5074
backendEnvironmentName?: string,
@@ -55,7 +79,12 @@ export function createFunctionDefinition(
5579
defineFunctionProperties.push(createParameter('entry', factory.createStringLiteral('./handler.ts')));
5680
}
5781
if (definition?.name) {
58-
defineFunctionProperties.push(createParameter('name', factory.createStringLiteral(definition.name)));
82+
const splitFuncName = definition.name.split('-');
83+
const funcNameWithoutBackendEnvName = splitFuncName.slice(0, -1).join('-');
84+
85+
const funcNameAssignment = createTemplateLiteral(`${funcNameWithoutBackendEnvName}-`, amplifyGen1EnvName, '');
86+
87+
defineFunctionProperties.push(createParameter('name', funcNameAssignment));
5988
}
6089
if (definition?.timeoutSeconds) {
6190
defineFunctionProperties.push(createParameter('timeoutSeconds', factory.createNumericLiteral(definition.timeoutSeconds)));
@@ -71,7 +100,7 @@ export function createFunctionDefinition(
71100
factory.createObjectLiteralExpression(
72101
Object.entries(definition.environment.Variables).map(([key, value]) => {
73102
if (key == 'API_KEY' && value.startsWith(`/amplify/${appId}/${backendEnvironmentName}`)) {
74-
groupsComment?.push(
103+
postImportStatements?.push(
75104
factory.createCallExpression(factory.createIdentifier('throw new Error'), undefined, [
76105
// eslint-disable-next-line spellcheck/spell-checker
77106
factory.createStringLiteral('Secrets need to be reset, use `npx ampx sandbox secret set API_KEY` to set the value'),
@@ -87,6 +116,9 @@ export function createFunctionDefinition(
87116
key,
88117
factory.createCallExpression(factory.createIdentifier('secret'), undefined, [factory.createStringLiteral('API_KEY')]),
89118
);
119+
} else if (key == 'ENV') {
120+
const envNameAssignment = createTemplateLiteral('', amplifyGen1EnvName, '');
121+
return createParameter(key, envNameAssignment);
90122
}
91123

92124
return createParameter(key, factory.createStringLiteral(value));

packages/amplify-gen2-codegen/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export const createGen2Renderer = ({
9494
return patchNpmPackageJson(packageJson, {
9595
'aws-cdk': '^2',
9696
'aws-cdk-lib': '^2',
97+
'ci-info': '^3.8.0',
9798
constructs: '^10.0.0',
9899
typescript: '^5.0.0',
99100
});

packages/amplify-gen2-codegen/src/npm_package/renderer.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const installedDependencies: Record<keyof AmplifyPackageVersions, IsDevDependenc
2323
'aws-cdk-lib': true,
2424
'@aws-amplify/backend': true,
2525
'@aws-amplify/backend-cli': true,
26+
'ci-info': true,
2627
};
2728

2829
describe('package.json renderer', () => {

packages/amplify-gen2-codegen/src/npm_package/renderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ export type AmplifyDevDependencies = {
33
'@aws-amplify/backend-cli': string;
44
'aws-cdk': string;
55
'aws-cdk-lib': string;
6+
'ci-info': string;
67
constructs: string;
78
esbuild: string;
89
tsx: string;
@@ -34,6 +35,7 @@ export const patchNpmPackageJson = (packageJson: PackageJson, packageVersions: P
3435
'@aws-amplify/backend-cli': withDefault(packageVersions['@aws-amplify/backend-cli']),
3536
'aws-cdk': withDefault(packageVersions['aws-cdk']),
3637
'aws-cdk-lib': withDefault(packageVersions['aws-cdk-lib']),
38+
'ci-info': withDefault(packageVersions['ci-info']),
3739
constructs: withDefault(packageVersions.constructs),
3840
esbuild: withDefault(packageVersions.esbuild),
3941
tsx: withDefault(packageVersions.tsx),

0 commit comments

Comments
 (0)