Skip to content

Commit 23fb135

Browse files
committed
Incorporate CR feedback
1 parent 3d1fc75 commit 23fb135

File tree

2 files changed

+7
-143
lines changed

2 files changed

+7
-143
lines changed

packages/aws-cdk-lib/aws-ecs/lib/deployment-lifecycle-hook-target.ts

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,6 @@ import * as iam from '../../aws-iam';
33
import * as lambda from '../../aws-lambda';
44
import { Fn, ValidationError } from '../../core';
55

6-
/**
7-
* Validates that input is a valid JSON object and returns it as a stringified JSON using Fn::ToJsonString
8-
* @param hookDetails The input to validate (must be a JSON object)
9-
* @returns The stringified JSON using CloudFormation's Fn::ToJsonString intrinsic function
10-
* @throws HookDetailsValidationError if the input is not a valid JSON object
11-
*/
12-
export function stringifyHookDetails(scope: IConstruct, hookDetails: any): string {
13-
// Reject arrays
14-
if (Array.isArray(hookDetails)) {
15-
throw new ValidationError('hookDetails must be a JSON object, got: array', scope);
16-
}
17-
18-
// Check if it's a plain object
19-
if (typeof hookDetails === 'object' && hookDetails.constructor === Object) {
20-
return Fn.toJsonString(hookDetails);
21-
}
22-
23-
// Everything else is invalid (primitives, functions, dates, etc.)
24-
throw new ValidationError(`hookDetails must be a JSON object, got: ${typeof hookDetails}`, scope);
25-
}
26-
276
/**
287
* Deployment lifecycle stages where hooks can be executed
298
*/
@@ -123,7 +102,7 @@ export interface DeploymentLifecycleLambdaTargetProps {
123102
*
124103
* @default - No custom parameters will be passed
125104
*/
126-
readonly hookDetails?: any;
105+
readonly hookDetails?: { [key: string]: any };
127106
}
128107

129108
/**
@@ -158,12 +137,17 @@ export class DeploymentLifecycleLambdaTarget implements IDeploymentLifecycleHook
158137
this.handler.grantInvoke(this._role);
159138
}
160139

140+
// Reject arrays
141+
if (Array.isArray(this.props.hookDetails)) {
142+
throw new ValidationError('hookDetails must be a JSON object, got: array', scope);
143+
}
144+
161145
return {
162146
targetArn: this.handler.functionArn,
163147
role: this._role,
164148
lifecycleStages: this.props.lifecycleStages,
165149
hookDetails: (this.props.hookDetails === undefined || this.props.hookDetails === null)?
166-
this.props.hookDetails : stringifyHookDetails(scope, this.props.hookDetails),
150+
this.props.hookDetails: Fn.toJsonString(this.props.hookDetails),
167151
};
168152
}
169153
}

packages/aws-cdk-lib/aws-ecs/test/deployment-lifecycle-hook-target.test.ts

Lines changed: 0 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import * as lambda from '../../aws-lambda';
55
import * as cdk from '../../core';
66
import { App, Stack } from '../../core';
77
import * as ecs from '../lib';
8-
import { stringifyHookDetails } from '../lib/deployment-lifecycle-hook-target';
98

109
describe('DeploymentLifecycleHookTarget', () => {
1110
let stack: cdk.Stack;
@@ -337,124 +336,5 @@ describe('DeploymentLifecycleHookTarget', () => {
337336
Template.fromStack(stack);
338337
}).toThrow(/hookDetails must be a JSON object, got: array/);
339338
});
340-
341-
test('throws error for primitive string hookDetails', () => {
342-
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
343-
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
344-
hookDetails: 'just a string',
345-
});
346-
347-
const service = new ecs.FargateService(stack, 'FargateService', {
348-
cluster,
349-
taskDefinition,
350-
});
351-
352-
service.addLifecycleHook(hookTarget);
353-
354-
// GIVEN & WHEN & THEN
355-
expect(() => {
356-
Template.fromStack(stack);
357-
}).toThrow(/hookDetails must be a JSON object, got: string/);
358-
});
359-
360-
test('throws error for primitive number hookDetails', () => {
361-
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
362-
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
363-
hookDetails: 42,
364-
});
365-
366-
const service = new ecs.FargateService(stack, 'FargateService', {
367-
cluster,
368-
taskDefinition,
369-
});
370-
371-
service.addLifecycleHook(hookTarget);
372-
373-
// GIVEN & WHEN & THEN
374-
expect(() => {
375-
Template.fromStack(stack);
376-
}).toThrow(/hookDetails must be a JSON object, got: number/);
377-
});
378-
379-
test('throws error for null hookDetails', () => {
380-
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
381-
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
382-
hookDetails: null,
383-
});
384-
385-
const service = new ecs.FargateService(stack, 'FargateService', {
386-
cluster,
387-
taskDefinition,
388-
});
389-
390-
service.addLifecycleHook(hookTarget);
391-
392-
// GIVEN & WHEN & THEN
393-
Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
394-
DeploymentConfiguration: {
395-
LifecycleHooks: [
396-
{
397-
LifecycleStages: ['PRE_SCALE_UP'],
398-
HookTargetArn: {
399-
'Fn::GetAtt': [
400-
Match.stringLikeRegexp('TestFunction'),
401-
'Arn',
402-
],
403-
},
404-
},
405-
],
406-
},
407-
});
408-
});
409-
410-
test('throws error for undefined hookDetails', () => {
411-
const hookTarget = new ecs.DeploymentLifecycleLambdaTarget(lambdaFunction, 'PreScaleUpHook', {
412-
lifecycleStages: [ecs.DeploymentLifecycleStage.PRE_SCALE_UP],
413-
});
414-
415-
const service = new ecs.FargateService(stack, 'FargateService', {
416-
cluster,
417-
taskDefinition,
418-
});
419-
420-
service.addLifecycleHook(hookTarget);
421-
422-
// GIVEN & WHEN & THEN
423-
Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
424-
DeploymentConfiguration: {
425-
LifecycleHooks: [
426-
{
427-
LifecycleStages: ['PRE_SCALE_UP'],
428-
HookTargetArn: {
429-
'Fn::GetAtt': [
430-
Match.stringLikeRegexp('TestFunction'),
431-
'Arn',
432-
],
433-
},
434-
},
435-
],
436-
},
437-
});
438-
});
439-
});
440-
441-
describe('stringifyHookDetails function', () => {
442-
test('validates and stringifies object directly', () => {
443-
const objectInput = { environment: 'production', timeout: 300 };
444-
expect(() => stringifyHookDetails(stack, objectInput)).not.toThrow();
445-
expect(stringifyHookDetails(stack, objectInput)).toBe('{"environment":"production","timeout":300}');
446-
});
447-
448-
test('rejects primitive string value', () => {
449-
expect(() => stringifyHookDetails(stack, 'just a string')).toThrow(/hookDetails must be a JSON object, got: string/);
450-
});
451-
452-
test('rejects primitive number value', () => {
453-
expect(() => stringifyHookDetails(stack, 42)).toThrow(/hookDetails must be a JSON object, got: number/);
454-
});
455-
456-
test('rejects primitive boolean value', () => {
457-
expect(() => stringifyHookDetails(stack, true)).toThrow(/hookDetails must be a JSON object, got: boolean/);
458-
});
459339
});
460340
});

0 commit comments

Comments
 (0)