diff --git a/docs/src/content/docs/targets/aws-lambda-layer.md b/docs/src/content/docs/targets/aws-lambda-layer.md index 835f1d37..ce3345ae 100644 --- a/docs/src/content/docs/targets/aws-lambda-layer.md +++ b/docs/src/content/docs/targets/aws-lambda-layer.md @@ -9,12 +9,27 @@ Creates a new public Lambda layer in each available AWS region and updates the S | Option | Description | |--------|-------------| -| `layerName` | Name of the Lambda layer | +| `layerName` | Name of the Lambda layer. Supports template variables (see below) | | `compatibleRuntimes` | List of runtime configurations | | `license` | Layer license | | `linkPrereleases` | Update for preview releases. Default: `false` | | `includeNames` | Must filter to exactly one artifact | +### Layer Name Templating + +The `layerName` option supports Mustache-style template variables for dynamic version interpolation: + +| Variable | Description | Example (for v10.2.3) | +|----------|-------------|----------------------| +| `{{{version}}}` | Full version string | `10.2.3` | +| `{{{major}}}` | Major version number | `10` | +| `{{{minor}}}` | Minor version number | `2` | +| `{{{patch}}}` | Patch version number | `3` | + +This is useful when you want the layer name to reflect the SDK major version, making it easier for users to identify which version the layer supports. + +Example: `SentryNodeServerlessSDKv{{{major}}}` becomes `SentryNodeServerlessSDKv10` when publishing version `10.2.3`. + ### Runtime Configuration ```yaml @@ -32,7 +47,9 @@ compatibleRuntimes: | `AWS_ACCESS_KEY` | AWS account access key | | `AWS_SECRET_ACCESS_KEY` | AWS account secret key | -## Example +## Examples + +### Basic Example ```yaml targets: @@ -46,3 +63,22 @@ targets: - nodejs12.x license: MIT ``` + +### With Version Templating + +Include the major version in the layer name so users can easily identify SDK compatibility: + +```yaml +targets: + - name: aws-lambda-layer + includeNames: /^sentry-node-serverless-\d+(\.\d+)*\.zip$/ + layerName: SentryNodeServerlessSDKv{{{major}}} + compatibleRuntimes: + - name: node + versions: + - nodejs18.x + - nodejs20.x + license: MIT +``` + +When publishing version `10.2.3`, the layer will be named `SentryNodeServerlessSDKv10`. diff --git a/src/targets/__tests__/awsLambda.test.ts b/src/targets/__tests__/awsLambda.test.ts index 01c856ea..0d5eea3b 100644 --- a/src/targets/__tests__/awsLambda.test.ts +++ b/src/targets/__tests__/awsLambda.test.ts @@ -119,6 +119,47 @@ describe('project config parameters', () => { }); }); +describe('layer name templating', () => { + beforeAll(() => { + setAwsEnvironmentVariables(); + }); + + test('layer name without template variables', () => { + const awsTarget = getAwsLambdaTarget(); + awsTarget.config.layerName = 'SentryNodeServerlessSDK'; + const resolved = awsTarget.resolveLayerName('10.2.3'); + expect(resolved).toBe('SentryNodeServerlessSDK'); + }); + + test('layer name with major version variable', () => { + const awsTarget = getAwsLambdaTarget(); + awsTarget.config.layerName = 'SentryNodeServerlessSDKv{{{major}}}'; + const resolved = awsTarget.resolveLayerName('10.2.3'); + expect(resolved).toBe('SentryNodeServerlessSDKv10'); + }); + + test('layer name with multiple version variables', () => { + const awsTarget = getAwsLambdaTarget(); + awsTarget.config.layerName = 'SentrySDKv{{{major}}}-{{{minor}}}-{{{patch}}}'; + const resolved = awsTarget.resolveLayerName('10.2.3'); + expect(resolved).toBe('SentrySDKv10-2-3'); + }); + + test('layer name with full version variable', () => { + const awsTarget = getAwsLambdaTarget(); + awsTarget.config.layerName = 'SentrySDK-{{{version}}}'; + const resolved = awsTarget.resolveLayerName('10.2.3'); + expect(resolved).toBe('SentrySDK-10.2.3'); + }); + + test('layer name with prerelease version', () => { + const awsTarget = getAwsLambdaTarget(); + awsTarget.config.layerName = 'SentrySDKv{{{major}}}'; + const resolved = awsTarget.resolveLayerName('10.2.3-alpha.1'); + expect(resolved).toBe('SentrySDKv10'); + }); +}); + describe('publish', () => { beforeAll(() => { setAwsEnvironmentVariables(); diff --git a/src/targets/awsLambdaLayer.ts b/src/targets/awsLambdaLayer.ts index 9b0463bc..ea0826de 100644 --- a/src/targets/awsLambdaLayer.ts +++ b/src/targets/awsLambdaLayer.ts @@ -22,7 +22,8 @@ import { import { createSymlinks } from '../utils/symlink'; import { withTempDir } from '../utils/files'; import { isDryRun } from '../utils/helpers'; -import { isPreviewRelease } from '../utils/version'; +import { renderTemplateSafe } from '../utils/strings'; +import { isPreviewRelease, parseVersion } from '../utils/version'; import { DEFAULT_REGISTRY_REMOTE } from '../utils/registry'; /** Config options for the "aws-lambda-layer" target. */ @@ -102,6 +103,34 @@ export class AwsLambdaLayerTarget extends BaseTarget { } } + /** + * Resolves the layer name by interpolating version variables. + * + * Supports Mustache-style templates with the following variables: + * - `{{{version}}}`: Full version string (e.g., "10.2.3") + * - `{{{major}}}`: Major version number (e.g., "10") + * - `{{{minor}}}`: Minor version number (e.g., "2") + * - `{{{patch}}}`: Patch version number (e.g., "3") + * + * Example: `SentryNodeServerlessSDKv{{{major}}}` becomes `SentryNodeServerlessSDKv10` + * + * @param version The version string to interpolate + * @returns The resolved layer name with variables substituted + */ + public resolveLayerName(version: string): string { + const layerNameTemplate = this.config.layerName as string; + const parsedVersion = parseVersion(version); + + const context = { + version, + major: parsedVersion?.major ?? '', + minor: parsedVersion?.minor ?? '', + patch: parsedVersion?.patch ?? '', + }; + + return renderTemplateSafe(layerNameTemplate, context); + } + /** * Publishes current lambda layer zip bundle to AWS Lambda. * @param version New version to be released. @@ -243,12 +272,15 @@ export class AwsLambdaLayerTarget extends BaseTarget { awsRegions: string[], artifactBuffer: Buffer ): Promise { + const resolvedLayerName = this.resolveLayerName(version); + this.logger.debug(`Resolved layer name: ${resolvedLayerName}`); + await Promise.all( this.config.compatibleRuntimes.map(async (runtime: CompatibleRuntime) => { this.logger.debug(`Publishing runtime ${runtime.name}...`); const layerManager = new AwsLambdaLayerManager( runtime, - this.config.layerName, + resolvedLayerName, this.config.license, artifactBuffer, awsRegions, @@ -302,7 +334,7 @@ export class AwsLambdaLayerTarget extends BaseTarget { canonical: layerManager.getCanonicalName(), sdk_version: version, account_number: getAccountFromArn(publishedLayers[0].arn), - layer_name: this.config.layerName, + layer_name: resolvedLayerName, regions: regionsVersions, };