Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,28 @@ describe('CFNOutputResolver', () => {
TopicName: 'snsTopic',
},
},
CustomS3AutoDeleteObjectsCustomResourceProviderHandler: {
Type: 'AWS::Lambda::Function',
Properties: {
FunctionName: 'CustomS3AutoDeleteObjectsCustomResourceProviderHandler',
Handler: 'index.handler',
Code: {
ZipFile: 'exports.handler = function() {}',
},
Runtime: 'nodejs14.x',
},
},
CustomS3AutoDeleteObjects: {
Type: 'Custom::S3AutoDeleteObjects',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['CustomS3AutoDeleteObjectsCustomResourceProviderHandler', 'Arn'],
},
BucketName: {
Ref: 'MyS3Bucket',
},
},
},
},
};
const expectedTemplate: CFNTemplate = {
Expand Down Expand Up @@ -372,8 +394,27 @@ describe('CFNOutputResolver', () => {
TopicName: 'snsTopic',
},
},
CustomS3AutoDeleteObjectsCustomResourceProviderHandler: {
Type: 'AWS::Lambda::Function',
Properties: {
FunctionName: 'CustomS3AutoDeleteObjectsCustomResourceProviderHandler',
Handler: 'index.handler',
Code: {
ZipFile: 'exports.handler = function() {}',
},
Runtime: 'nodejs14.x',
},
},
CustomS3AutoDeleteObjects: {
Type: 'Custom::S3AutoDeleteObjects',
Properties: {
ServiceToken: 'arn:aws:lambda:us-east-1:12345:function:mycustomS3AutoDeleteObjectsLambdaFunction',
BucketName: 'test-bucket',
},
},
},
};

it('should resolve output references', () => {
expect(
new CfnOutputResolver(template, 'us-east-1', '12345').resolve(
Expand Down Expand Up @@ -431,6 +472,15 @@ describe('CFNOutputResolver', () => {
Timestamp: new Date('2025-04-02T22:27:41.603000+00:00'),
ResourceStatus: 'CREATE_COMPLETE',
},
{
StackName: 'amplify-amplifycodegen-dev',
StackId: 'arn:aws:cloudformation:us-west-2:123456789:stack/amplify-amplifycodegen-dev',
LogicalResourceId: 'CustomS3AutoDeleteObjectsCustomResourceProviderHandler',
PhysicalResourceId: 'mycustomS3AutoDeleteObjectsLambdaFunction',
ResourceType: 'AWS::Lambda::Function',
Timestamp: new Date('2025-04-02T22:27:41.603000+00:00'),
ResourceStatus: 'CREATE_COMPLETE',
},
],
),
).toEqual(expectedTemplate);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ class CfnOutputResolver {
return {
Arn: `arn:aws:sqs:${this.region}:${this.accountId}:${resourceIdentifier}`,
};
case 'AWS::Lambda::Function':
return {
Arn: `arn:aws:lambda:${this.region}:${this.accountId}:function:${resourceIdentifier}`,
};
default:
return undefined;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ describe('TemplateGenerator', () => {
CFN_AUTH_TYPE.IdentityPoolRoleAttachment,
CFN_AUTH_TYPE.UserPoolDomain,
],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
2,
Expand All @@ -848,7 +848,7 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_AUTH_TYPE.UserPoolGroup],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
3,
Expand All @@ -862,7 +862,7 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_S3_TYPE.Bucket],
expect.any(Function),
undefined,
);
}

Expand Down Expand Up @@ -892,7 +892,7 @@ describe('TemplateGenerator', () => {
CFN_AUTH_TYPE.IdentityPoolRoleAttachment,
CFN_AUTH_TYPE.UserPoolDomain,
],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
2,
Expand All @@ -906,7 +906,7 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_AUTH_TYPE.UserPoolGroup],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
3,
Expand All @@ -920,7 +920,7 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_S3_TYPE.Bucket],
expect.any(Function),
undefined,
);
}

Expand Down Expand Up @@ -950,7 +950,7 @@ describe('TemplateGenerator', () => {
CFN_AUTH_TYPE.IdentityPoolRoleAttachment,
CFN_AUTH_TYPE.UserPoolDomain,
],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
2,
Expand All @@ -964,7 +964,7 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_AUTH_TYPE.UserPoolGroup],
expect.any(Function),
undefined,
);
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
3,
Expand All @@ -978,8 +978,9 @@ describe('TemplateGenerator', () => {
APP_ID,
ENV_NAME,
[CFN_S3_TYPE.Bucket],
expect.any(Function),
undefined,
);
// custom resource category
expect(CategoryTemplateGenerator).toHaveBeenNthCalledWith(
4,
GEN1_ROOT_STACK_NAME,
Expand Down
31 changes: 16 additions & 15 deletions packages/amplify-migration-template-gen/src/template-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,13 +260,12 @@ class TemplateGenerator {
let updatingGen1CategoryStack;
try {
const { newTemplate, parameters: gen1StackParameters } = await categoryTemplateGenerator.generateGen1PreProcessTemplate();

assert(gen1StackParameters);
updatingGen1CategoryStack = ora(`Updating Gen 1 ${this.getStackCategoryName(category)} stack...`).start();

const gen1StackUpdateStatus = await tryUpdateStack(this.cfnClient, sourceCategoryStackId, gen1StackParameters, newTemplate);

assert(gen1StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE);
assert(gen1StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE, `Gen 1 stack is in an invalid state: ${gen1StackUpdateStatus}`);
updatingGen1CategoryStack.succeed(`Updated Gen 1 ${this.getStackCategoryName(category)} stack successfully`);

return newTemplate;
Expand Down Expand Up @@ -297,7 +296,7 @@ class TemplateGenerator {

const gen2StackUpdateStatus = await tryUpdateStack(this.cfnClient, destinationCategoryStackId, parameters ?? [], newTemplate);

assert(gen2StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE);
assert(gen2StackUpdateStatus === CFNStackStatus.UPDATE_COMPLETE, `Gen 2 stack is in an invalid state: ${gen2StackUpdateStatus}`);
updatingGen2CategoryStack.succeed(`Updated Gen 2 ${this.getStackCategoryName(category)} stack successfully`);

return { newTemplate, oldTemplate, parameters };
Expand Down Expand Up @@ -325,7 +324,7 @@ class TemplateGenerator {
destinationStackId,
this.createCategoryTemplateGenerator(sourceStackId, destinationStackId, config.resourcesToRefactor),
]);
} else if (customResourceMap && !Object.values(NON_CUSTOM_RESOURCE_CATEGORY).includes(category as NON_CUSTOM_RESOURCE_CATEGORY)) {
} else if (customResourceMap && this.isCustomResource(category)) {
this.categoryTemplateGenerators.push([
category,
sourceStackId,
Expand Down Expand Up @@ -354,17 +353,19 @@ class TemplateGenerator {
this.appId,
this.environmentName,
resourcesToRefactor,
(_resourcesToMove: CFN_CATEGORY_TYPE[], cfnResource: [string, CFNResource]) => {
const [logicalId] = cfnResource;

// Check if customResourceMap contains the logical ID
return (
customResourceMap?.some(
(resourceMapping) =>
resourceMapping.Source.LogicalResourceId === logicalId || resourceMapping.Destination.LogicalResourceId === logicalId,
) ?? false
);
},
customResourceMap
? (_resourcesToMove: CFN_CATEGORY_TYPE[], cfnResource: [string, CFNResource]) => {
const [logicalId] = cfnResource;

// Check if customResourceMap contains the logical ID
return (
customResourceMap?.some(
(resourceMapping) =>
resourceMapping.Source.LogicalResourceId === logicalId || resourceMapping.Destination.LogicalResourceId === logicalId,
) ?? false
);
}
: undefined,
);
}

Expand Down
6 changes: 5 additions & 1 deletion packages/amplify-migration-template-gen/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,11 @@ export enum CFN_SQS_TYPE {
Queue = 'AWS::SQS::Queue',
}

export type CFN_RESOURCE_TYPES = CFN_AUTH_TYPE | CFN_S3_TYPE | CFN_IAM_TYPE | CFN_SQS_TYPE;
export enum CFN_LAMBDA_TYPE {
Function = 'AWS::Lambda::Function',
}

export type CFN_RESOURCE_TYPES = CFN_AUTH_TYPE | CFN_S3_TYPE | CFN_IAM_TYPE | CFN_SQS_TYPE | CFN_LAMBDA_TYPE;

export type AWS_RESOURCE_ATTRIBUTES = 'Arn';

Expand Down
Loading