Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

defineFunction initial implementation #742

Merged
merged 29 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
954a506
build working
edwardfoyle Nov 14, 2023
67c2e23
Merge remote-tracking branch 'origin/main' into func-reimpl
edwardfoyle Nov 27, 2023
96a785a
update package lock
edwardfoyle Nov 27, 2023
84bb93c
updating test cases
edwardfoyle Nov 27, 2023
c5d9462
update snapshots
edwardfoyle Nov 27, 2023
22a3f0f
update api extract
edwardfoyle Nov 27, 2023
e3985a7
add changeset
edwardfoyle Nov 27, 2023
052e87e
fix api
edwardfoyle Nov 27, 2023
21f3187
fix auto-rename mishap
edwardfoyle Nov 28, 2023
886089d
update e2e test case
edwardfoyle Nov 28, 2023
1a5a5dd
add additional check to e2e suite
edwardfoyle Nov 28, 2023
83c8b56
lint fixes
edwardfoyle Nov 28, 2023
c28959f
update snapshots
edwardfoyle Nov 28, 2023
10b8893
trying this
edwardfoyle Nov 28, 2023
78167ce
updating assertion
edwardfoyle Nov 28, 2023
3fae3e8
Merge remote-tracking branch 'origin/main' into func-reimpl
edwardfoyle Nov 28, 2023
0c9cd67
update snapshots
edwardfoyle Nov 28, 2023
7144d16
addressing PR comments
edwardfoyle Nov 29, 2023
ddea87f
update snapshots
edwardfoyle Nov 29, 2023
1ad585d
update api extract
edwardfoyle Nov 29, 2023
40f75ad
update changeset
edwardfoyle Nov 29, 2023
edb5ee3
fix lint
edwardfoyle Nov 29, 2023
006f6c3
Im dumb
edwardfoyle Nov 29, 2023
6dabee6
still dumb
edwardfoyle Nov 29, 2023
159d3a1
remove unused code
edwardfoyle Nov 29, 2023
9dfb69f
hopefully last fix
edwardfoyle Nov 29, 2023
257ce66
update snapshots
edwardfoyle Nov 29, 2023
8453633
json parse lambda output
edwardfoyle Nov 29, 2023
3cdb1a3
Merge remote-tracking branch 'origin/main' into func-reimpl
edwardfoyle Nov 29, 2023
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
5 changes: 5 additions & 0 deletions .changeset/few-carpets-search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/backend-function': minor
---

Initial implementation of new 'defineFunction' entry point
7 changes: 7 additions & 0 deletions .changeset/mighty-rockets-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'create-amplify': patch
'@aws-amplify/plugin-types': patch
'@aws-amplify/backend': patch
---

Expose new `defineFunction` interface
506 changes: 497 additions & 9 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 7 additions & 24 deletions packages/backend-function/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,20 @@

```ts

import { AmplifyFunctionProps } from '@aws-amplify/function-construct-alpha';
import { AmplifyLambdaFunction } from '@aws-amplify/function-construct-alpha';
import { Construct } from 'constructs';
import { ConstructFactory } from '@aws-amplify/plugin-types';
import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types';
import { FunctionResources } from '@aws-amplify/plugin-types';
import { ResourceProvider } from '@aws-amplify/plugin-types';

// @public
export class AmplifyFunctionFactory implements ConstructFactory<AmplifyLambdaFunction> {
static build: (props: AmplifyFunctionFactoryBuildProps) => Promise<AmplifyFunctionFactory>;
static fromDir: (props: AmplifyFunctionFactoryFromDirProps) => AmplifyFunctionFactory;
getInstance: ({ constructContainer, }: ConstructFactoryGetInstanceProps) => AmplifyLambdaFunction;
}
export const defineFunction: (props?: FunctionFactoryProps) => ConstructFactory<Construct & ResourceProvider<FunctionResources>>;

// @public (undocumented)
export type AmplifyFunctionFactoryBaseProps = {
name: string;
export type FunctionFactoryProps = {
edwardfoyle marked this conversation as resolved.
Show resolved Hide resolved
name?: string;
entry?: string;
};

// @public (undocumented)
export type AmplifyFunctionFactoryBuildProps = AmplifyFunctionFactoryBaseProps & Omit<AmplifyFunctionProps, 'absoluteCodePath'> & {
buildCommand: string;
outDir: string;
};

// @public (undocumented)
export type AmplifyFunctionFactoryFromDirProps = AmplifyFunctionFactoryBaseProps & Omit<AmplifyFunctionProps, 'absoluteCodePath'> & {
codePath: string;
};

// @public
export const Func: typeof AmplifyFunctionFactory;

// (No @packageDocumentation comment for this package)

```
4 changes: 2 additions & 2 deletions packages/backend-function/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@
"license": "Apache-2.0",
"dependencies": {
"@aws-amplify/backend-output-storage": "0.2.6",
"@aws-amplify/function-construct-alpha": "^0.2.1",
"@aws-amplify/plugin-types": "^0.4.2",
"execa": "^7.1.1"
},
"devDependencies": {
"@aws-amplify/backend-platform-test-stubs": "^0.3.1",
"@aws-amplify/platform-core": "^0.3.1"
"@aws-amplify/platform-core": "^0.3.1",
"uuid": "^9.0.1"
},
"peerDependencies": {
"aws-cdk-lib": "^2.110.1",
Expand Down
95 changes: 66 additions & 29 deletions packages/backend-function/src/factory.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { beforeEach, describe, it, mock } from 'node:test';
import { Func } from './factory.js';
import { beforeEach, describe, it } from 'node:test';
import { App, Stack } from 'aws-cdk-lib';
import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types';
import assert from 'node:assert';
import { fileURLToPath } from 'url';
import * as path from 'path';
import { StackMetadataBackendOutputStorageStrategy } from '@aws-amplify/backend-output-storage';
import {
ConstructContainerStub,
StackResolverStub,
} from '@aws-amplify/backend-platform-test-stubs';
import { defaultLambda } from './test-assets/default-lambda/resource.js';
import { Template } from 'aws-cdk-lib/assertions';
import { defineFunction } from './factory.js';
import { lambdaWithDependencies } from './test-assets/lambda-with-dependencies/resource.js';

const createStackAndSetContext = (): Stack => {
const app = new App();
Expand Down Expand Up @@ -41,38 +42,74 @@ void describe('AmplifyFunctionFactory', () => {
});

void it('creates singleton function instance', () => {
const functionFactory = Func.fromDir({
name: 'testFunc',
codePath: path.join('..', 'test-assets', 'test-lambda'),
});
const functionFactory = defaultLambda;
const instance1 = functionFactory.getInstance(getInstanceProps);
const instance2 = functionFactory.getInstance(getInstanceProps);
assert.strictEqual(instance1, instance2);
});

void it('executes build command from directory where constructor is used', async () => {
const commandExecutorMock = mock.fn();
void it('resolves default name and entry when no args specified', () => {
const functionFactory = defaultLambda;
const lambda = functionFactory.getInstance(getInstanceProps);
const template = Template.fromStack(Stack.of(lambda));
template.resourceCountIs('AWS::Lambda::Function', 1);
template.hasResourceProperties('AWS::Lambda::Function', {
Handler: 'index.handler',
});
const lambdaLogicalId = Object.keys(
template.findResources('AWS::Lambda::Function')
)[0];
// eslint-disable-next-line spellcheck/spell-checker
assert.ok(lambdaLogicalId.includes('defaultlambda'));
});

// Casting to never is necessary because commandExecutor is a private method.
// TS yells that it's not a property on Func even though it is there
mock.method(Func, 'commandExecutor' as never, commandExecutorMock);
void it('resolves default name when entry specified', () => {
const functionFactory = defineFunction({
entry: './test-assets/default-lambda/handler.ts',
});
const lambda = functionFactory.getInstance(getInstanceProps);
const template = Template.fromStack(Stack.of(lambda));
template.resourceCountIs('AWS::Lambda::Function', 1);
template.hasResourceProperties('AWS::Lambda::Function', {
Handler: 'index.handler',
});
const lambdaLogicalId = Object.keys(
template.findResources('AWS::Lambda::Function')
)[0];
assert.ok(lambdaLogicalId.includes('handler'));
});

(
await Func.build({
name: 'testFunc',
outDir: path.join('..', 'test-assets', 'test-lambda'),
buildCommand: 'test command',
})
).getInstance(getInstanceProps);
void it('uses name and entry that is explicitly specified', () => {
const functionFactory = defineFunction({
entry: './test-assets/default-lambda/handler.ts',
name: 'myCoolLambda',
});
const lambda = functionFactory.getInstance(getInstanceProps);
const template = Template.fromStack(Stack.of(lambda));
template.resourceCountIs('AWS::Lambda::Function', 1);
template.hasResourceProperties('AWS::Lambda::Function', {
Handler: 'index.handler',
});
const lambdaLogicalId = Object.keys(
template.findResources('AWS::Lambda::Function')
)[0];
assert.ok(lambdaLogicalId.includes('myCoolLambda'));
});

assert.strictEqual(commandExecutorMock.mock.callCount(), 1);
assert.deepStrictEqual(commandExecutorMock.mock.calls[0].arguments, [
'test command',
{
cwd: fileURLToPath(new URL('../src', import.meta.url)),
stdio: 'inherit',
shell: 'bash',
},
]);
void it('builds lambda with local and 3p dependencies', () => {
const lambda = lambdaWithDependencies.getInstance(getInstanceProps);
const template = Template.fromStack(Stack.of(lambda));
// There isn't a way to check the contents of the bundled lambda using the CDK Template utility
// So we just check that the lambda was created properly in the CFN template.
// There is an e2e test that validates proper lambda bundling
template.resourceCountIs('AWS::Lambda::Function', 1);
template.hasResourceProperties('AWS::Lambda::Function', {
Handler: 'index.handler',
});
const lambdaLogicalId = Object.keys(
template.findResources('AWS::Lambda::Function')
)[0];
// eslint-disable-next-line spellcheck/spell-checker
assert.ok(lambdaLogicalId.includes('lambdawithdependencies'));
});
});
Loading
Loading