Skip to content
This repository was archived by the owner on Apr 5, 2025. It is now read-only.

feat: add support for Python 3.12 and Node 20 #76

Merged
merged 3 commits into from
Nov 15, 2023
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
2 changes: 1 addition & 1 deletion .projen/deps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .projenrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
'typescript',
'nodejs',
],
cdkVersion: '2.88.0',
cdkVersion: '2.108.1',
defaultReleaseBranch: 'main',
minNodeVersion: '16.19.1',
majorVersion: 3,
Expand Down
4 changes: 2 additions & 2 deletions package.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 33 additions & 11 deletions src/lambda-powertools-layer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,12 @@ export class LambdaPowertoolsLayer extends lambda.LayerVersion {
const runtimeFamily = props?.runtimeFamily ?? lambda.RuntimeFamily.PYTHON;
const languageName = getLanguageNameFromRuntimeFamily(runtimeFamily);
const dockerFilePath = path.join(__dirname, `../layer/${languageName}`);
const compatibleArchitectures = props?.compatibleArchitectures ?? [lambda.Architecture.X86_64];
const compatibleArchitecturesDescription = compatibleArchitectures.map((arch) => arch.name).join(', ');
const compatibleArchitectures = props?.compatibleArchitectures ?? [
lambda.Architecture.X86_64,
];
const compatibleArchitecturesDescription = compatibleArchitectures
.map((arch) => arch.name)
.join(', ');

console.log(`path ${dockerFilePath}`);
super(scope, id, {
Expand All @@ -94,23 +98,35 @@ export class LambdaPowertoolsLayer extends lambda.LayerVersion {
),
},
// supports cross-platform docker build
platform: getDockerPlatformNameFromArchitectures(compatibleArchitectures),
platform: getDockerPlatformNameFromArchitectures(
compatibleArchitectures,
),
}),
layerVersionName: props?.layerVersionName ? props?.layerVersionName : undefined,
layerVersionName: props?.layerVersionName
? props?.layerVersionName
: undefined,
license: 'MIT-0',
compatibleRuntimes: getRuntimesFromRuntimeFamily(runtimeFamily),
description: `Powertools for AWS Lambda (${languageName}) [${compatibleArchitecturesDescription}]${
props?.includeExtras ? ' with extra dependencies' : ''
} ${props?.version ? `version ${props?.version}` : 'latest version'}`.trim(),
description:
`Powertools for AWS Lambda (${languageName}) [${compatibleArchitecturesDescription}]${
props?.includeExtras ? ' with extra dependencies' : ''
} ${
props?.version ? `version ${props?.version}` : 'latest version'
}`.trim(),
// Dear reader: I'm happy that you've stumbled upon this line too! You might wonder, why are we doing this and passing `undefined` when the list is empty?
// Answer: on regions that don't support ARM64 Lambdas, we can't use the `compatibleArchitectures` parameter. Otherwise CloudFormation will bail with an error.
// So if this construct is called with en empty list of architectures, just pass undefined down to the CDK construct.
compatibleArchitectures: compatibleArchitectures.length == 0 ? undefined : compatibleArchitectures,
compatibleArchitectures:
compatibleArchitectures.length == 0
? undefined
: compatibleArchitectures,
});
}
}

function getRuntimesFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily): lambda.Runtime[] | undefined {
function getRuntimesFromRuntimeFamily(
runtimeFamily: lambda.RuntimeFamily,
): lambda.Runtime[] | undefined {
switch (runtimeFamily) {
case lambda.RuntimeFamily.PYTHON:
return [
Expand All @@ -119,20 +135,24 @@ function getRuntimesFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily): lamb
lambda.Runtime.PYTHON_3_9,
lambda.Runtime.PYTHON_3_10,
lambda.Runtime.PYTHON_3_11,
lambda.Runtime.PYTHON_3_12,
];
case lambda.RuntimeFamily.NODEJS:
return [
lambda.Runtime.NODEJS_12_X,
lambda.Runtime.NODEJS_14_X,
lambda.Runtime.NODEJS_16_X,
lambda.Runtime.NODEJS_18_X,
lambda.Runtime.NODEJS_20_X,
];
default:
return [];
}
}

function getLanguageNameFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily): string {
function getLanguageNameFromRuntimeFamily(
runtimeFamily: lambda.RuntimeFamily,
): string {
switch (runtimeFamily) {
case lambda.RuntimeFamily.PYTHON:
return 'Python';
Expand All @@ -145,7 +165,9 @@ function getLanguageNameFromRuntimeFamily(runtimeFamily: lambda.RuntimeFamily):

// Docker expects a single string for the --platform option.
// getDockerPlatformNameFromArchitectures converts the Architecture enum to a string.
function getDockerPlatformNameFromArchitectures(architectures: lambda.Architecture[]): string {
function getDockerPlatformNameFromArchitectures(
architectures: lambda.Architecture[],
): string {
if (architectures.length == 1) {
return architectures[0].dockerPlatform;
} else {
Expand Down
95 changes: 68 additions & 27 deletions test/lambda-powertools-python-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Template } from 'aws-cdk-lib/assertions';
import { Architecture, RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
import { LambdaPowertoolsLayer } from '../src';


describe('with no configuration the construct', () => {
const stack = new Stack();
new LambdaPowertoolsLayer(stack, 'PowertoolsLayer');
Expand All @@ -28,6 +27,7 @@ describe('with no configuration the construct', () => {
'python3.9',
'python3.10',
'python3.11',
'python3.12',
],
});
});
Expand Down Expand Up @@ -55,9 +55,12 @@ describe('for layerVersionName configuraiton the construct', () => {
layerVersionName: 'mySpecialName',
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
LayerName: 'mySpecialName',
});
Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
LayerName: 'mySpecialName',
},
);
});
});

Expand All @@ -68,17 +71,23 @@ describe('with version configuration the construct', () => {
version: '1.21.0',
});


Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: 'Powertools for AWS Lambda (Python) [x86_64] version 1.21.0',
});
Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
Description:
'Powertools for AWS Lambda (Python) [x86_64] version 1.21.0',
},
);
});

test('fails with invalid version', () => {
const stack = new Stack();
expect(() => new LambdaPowertoolsLayer(stack, 'PowertoolsLayerBadVersion', {
version: '0.0.0',
})).toThrow(/docker exited with status 1/);
expect(
() =>
new LambdaPowertoolsLayer(stack, 'PowertoolsLayerBadVersion', {
version: '0.0.0',
}),
).toThrow(/docker exited with status 1/);
});

test('synthesizes with pynadtic and specific version', () => {
Expand All @@ -88,10 +97,13 @@ describe('with version configuration the construct', () => {
version: '1.22.0',
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: 'Powertools for AWS Lambda (Python) [x86_64] with extra dependencies version 1.22.0',
});

Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
Description:
'Powertools for AWS Lambda (Python) [x86_64] with extra dependencies version 1.22.0',
},
);
});

test('synthesizes with extras and latest version', () => {
Expand All @@ -100,49 +112,78 @@ describe('with version configuration the construct', () => {
includeExtras: true,
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: 'Powertools for AWS Lambda (Python) [x86_64] with extra dependencies latest version',
});
Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
Description:
'Powertools for AWS Lambda (Python) [x86_64] with extra dependencies latest version',
},
);
});
});

describe('construct build args for Dockerfile', () => {
test('returns extras and version', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, true, '1.21.0');
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
true,
'1.21.0',
);

expect(args).toEqual('[all]==1.21.0');
});

test('returns only extras when no version provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, true, undefined);
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
true,
undefined,
);

expect(args).toEqual('[all]');
});

test('returns a git url with extras when a git url is provided', () => {
const version = 'git+https://github.com/awslabs/aws-lambda-powertools-python@v2';
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, true, version);
const version =
'git+https://github.com/awslabs/aws-lambda-powertools-python@v2';
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
true,
version,
);

expect(args).toEqual(`[all] @ ${version}`);
});

test('returns only version when no extras flag provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, undefined, '1.11.0');
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
undefined,
'1.11.0',
);

expect(args).toEqual('==1.11.0');
});

test('returns empty when no version and extras provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, undefined, undefined);
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
undefined,
undefined,
);

expect(args).toEqual('');
});

test('returns a git url when a git url is provided and extras provided', () => {
const version = 'git+https://github.com/awslabs/aws-lambda-powertools-python@v2';
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.PYTHON, false, version);
const version =
'git+https://github.com/awslabs/aws-lambda-powertools-python@v2';
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.PYTHON,
false,
version,
);

expect(args).toEqual(` @ ${version}`);
});

});
49 changes: 32 additions & 17 deletions test/lambda-powertools-typescript-layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Template } from 'aws-cdk-lib/assertions';
import { RuntimeFamily } from 'aws-cdk-lib/aws-lambda';
import { LambdaPowertoolsLayer } from '../src';


describe('with minimal configuration the construct', () => {
const stack = new Stack();
new LambdaPowertoolsLayer(stack, 'PowertoolsLayer', {
Expand All @@ -12,7 +11,8 @@ describe('with minimal configuration the construct', () => {
const template = Template.fromStack(stack);
test('synthesizes successfully', () => {
template.hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: 'Powertools for AWS Lambda (TypeScript) [x86_64] latest version',
Description:
'Powertools for AWS Lambda (TypeScript) [x86_64] latest version',
});
});

Expand All @@ -29,6 +29,7 @@ describe('with minimal configuration the construct', () => {
'nodejs14.x',
'nodejs16.x',
'nodejs18.x',
'nodejs20.x',
],
});
});
Expand All @@ -41,9 +42,12 @@ describe('for layerVersionName configuration the construct', () => {
layerVersionName: 'mySpecialName',
});

Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
LayerName: 'mySpecialName',
});
Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
LayerName: 'mySpecialName',
},
);
});
});

Expand All @@ -56,31 +60,42 @@ describe('with version configuration the construct', () => {
version: version,
});


Template.fromStack(stack).hasResourceProperties('AWS::Lambda::LayerVersion', {
Description: `Powertools for AWS Lambda (TypeScript) [x86_64] version ${version}`,
});
Template.fromStack(stack).hasResourceProperties(
'AWS::Lambda::LayerVersion',
{
Description: `Powertools for AWS Lambda (TypeScript) [x86_64] version ${version}`,
},
);
});

test('fails with invalid version', () => {
const stack = new Stack();
expect(() => new LambdaPowertoolsLayer(stack, 'PowertoolsLayerBadVersion', {
runtimeFamily: RuntimeFamily.NODEJS,
version: '12.222.21123',
})).toThrow();
expect(
() =>
new LambdaPowertoolsLayer(stack, 'PowertoolsLayerBadVersion', {
runtimeFamily: RuntimeFamily.NODEJS,
version: '12.222.21123',
}),
).toThrow();
});


test('returns version with @ when provided provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.NODEJS, undefined, '0.9.0');
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.NODEJS,
undefined,
'0.9.0',
);

expect(args).toEqual('@0.9.0');
});

test('returns empty when no version provided', () => {
const args = LambdaPowertoolsLayer.constructBuildArgs(RuntimeFamily.NODEJS, undefined, undefined);
const args = LambdaPowertoolsLayer.constructBuildArgs(
RuntimeFamily.NODEJS,
undefined,
undefined,
);

expect(args).toEqual('');
});

});
Loading