Skip to content

Commit 9c7c418

Browse files
rongyamazonkddejong
authored andcommitted
Updated to pass in nextToken and maxItem for ListStackResources
1 parent bcc357d commit 9c7c418

File tree

7 files changed

+41
-105
lines changed

7 files changed

+41
-105
lines changed

src/handlers/StackHandler.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { analyzeCapabilities } from '../stacks/actions/CapabilityAnalyzer';
99
import {
1010
parseCreateDeploymentParams,
1111
parseDeleteChangeSetParams,
12+
parseListStackResourcesParams,
1213
parseStackActionParams,
1314
parseTemplateUriParams,
1415
} from '../stacks/actions/StackActionParser';
@@ -335,9 +336,14 @@ export function listChangeSetsHandler(
335336
export function listStackResourcesHandler(
336337
components: ServerComponents,
337338
): RequestHandler<ListStackResourcesParams, ListStackResourcesResult, void> {
338-
return async (params: ListStackResourcesParams): Promise<ListStackResourcesResult> => {
339+
return async (rawParams): Promise<ListStackResourcesResult> => {
339340
try {
340-
const response = await components.cfnService.listStackResources({ StackName: params.stackName });
341+
const params = parseWithPrettyError(parseListStackResourcesParams, rawParams);
342+
const response = await components.cfnService.listStackResources({
343+
StackName: params.stackName,
344+
NextToken: params.nextToken,
345+
MaxItems: params.maxItems,
346+
});
341347
return { resources: response.StackResourceSummaries ?? [] };
342348
} catch (error) {
343349
log.error({ error: extractErrorMessage(error) }, 'Error listing stack resources');

src/server/CfnServer.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,8 @@ import {
2828
} from '../handlers/ResourceHandler';
2929
import {
3030
listStacksHandler,
31-
<<<<<<< HEAD
3231
listChangeSetsHandler,
33-
=======
3432
listStackResourcesHandler,
35-
>>>>>>> 29939f4 (Added new command for listStackResources)
3633
createValidationHandler,
3734
createDeploymentHandler,
3835
getValidationStatusHandler,

src/services/CfnService.ts

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import {
4242
TypeSummary,
4343
DescribeTypeOutput,
4444
StackSummary,
45-
StackResourceSummary,
4645
StackStatus,
4746
waitUntilChangeSetCreateComplete,
4847
waitUntilStackUpdateComplete,
@@ -197,33 +196,12 @@ export class CfnService {
197196
return await this.withClient((client) => client.send(new DescribeStackResourceCommand(params)));
198197
}
199198

200-
public async listStackResources(params: { StackName: string }): Promise<ListStackResourcesCommandOutput> {
201-
return await this.withClient(async (client) => {
202-
const allResources: StackResourceSummary[] = [];
203-
let nextToken: string | undefined;
204-
let lastResponse: ListStackResourcesCommandOutput;
205-
206-
do {
207-
lastResponse = await client.send(
208-
new ListStackResourcesCommand({
209-
StackName: params.StackName,
210-
NextToken: nextToken,
211-
}),
212-
);
213-
214-
if (lastResponse.StackResourceSummaries) {
215-
allResources.push(...lastResponse.StackResourceSummaries);
216-
}
217-
218-
nextToken = lastResponse.NextToken;
219-
} while (nextToken);
220-
221-
return {
222-
...lastResponse,
223-
StackResourceSummaries: allResources,
224-
NextToken: undefined,
225-
};
226-
});
199+
public async listStackResources(params: {
200+
StackName: string;
201+
NextToken?: string;
202+
MaxItems?: number;
203+
}): Promise<ListStackResourcesCommandOutput> {
204+
return await this.withClient((client) => client.send(new ListStackResourcesCommand(params)));
227205
}
228206

229207
public async describeStackResourceDrifts(params: {

src/stacks/StackRequestType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export const ListChangeSetRequest = new RequestType<ListChangeSetParams, ListCha
4949

5050
export type ListStackResourcesParams = {
5151
stackName: string;
52+
nextToken?: string;
53+
maxItems?: number;
5254
};
5355

5456
export type ListStackResourcesResult = {

src/stacks/actions/StackActionParser.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Capability } from '@aws-sdk/client-cloudformation';
22
import { z } from 'zod';
3+
import { ListStackResourcesParams } from '../StackRequestType';
34
import {
45
CreateDeploymentParams,
56
CreateValidationParams,
@@ -50,6 +51,12 @@ const DeleteChangeSetParamsSchema = z.object({
5051

5152
const TemplateUriSchema = z.string().min(1);
5253

54+
const ListStackResourcesParamsSchema = z.object({
55+
stackName: z.string().min(1),
56+
nextToken: z.string().optional(),
57+
maxItems: z.number().optional(),
58+
});
59+
5360
export function parseStackActionParams(input: unknown): CreateValidationParams {
5461
return StackActionParamsSchema.parse(input);
5562
}
@@ -65,3 +72,7 @@ export function parseDeleteChangeSetParams(input: unknown): DeleteChangeSetParam
6572
export function parseTemplateUriParams(input: unknown): TemplateUri {
6673
return TemplateUriSchema.parse(input);
6774
}
75+
76+
export function parseListStackResourcesParams(input: unknown): ListStackResourcesParams {
77+
return ListStackResourcesParamsSchema.parse(input);
78+
}

tst/unit/handlers/StackHandler.test.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,7 @@ import {
3232
StackActionPhase,
3333
StackActionState,
3434
} from '../../../src/stacks/actions/StackActionRequestType';
35-
import {
36-
ListStacksParams,
37-
ListStacksResult,
38-
ListStackResourcesParams,
39-
ListStackResourcesResult,
40-
} from '../../../src/stacks/StackRequestType';
35+
import { ListStacksParams, ListStacksResult, ListStackResourcesResult } from '../../../src/stacks/StackRequestType';
4136
import {
4237
createMockComponents,
4338
createMockSyntaxTreeManager,
@@ -59,6 +54,7 @@ vi.mock('../../../src/stacks/actions/StackActionParser', () => ({
5954
parseTemplateUriParams: vi.fn((input) => input),
6055
parseCreateDeploymentParams: vi.fn((input) => input),
6156
parseDeleteChangeSetParams: vi.fn((input) => input),
57+
parseListStackResourcesParams: vi.fn((input) => input),
6258
}));
6359

6460
vi.mock('../../../src/utils/ZodErrorWrapper', () => ({
@@ -475,18 +471,24 @@ describe('StackActionHandler', () => {
475471
});
476472

477473
const handler = listStackResourcesHandler(mockComponents);
478-
const params: ListStackResourcesParams = { stackName: 'test-stack' };
474+
const params = { stackName: 'test-stack', nextToken: 'token123', maxItems: 10 };
479475
const result = (await handler(params, {} as any)) as ListStackResourcesResult;
480476

481477
expect(result.resources).toEqual(mockResources);
482-
expect(mockComponents.cfnService.listStackResources.calledWith({ StackName: 'test-stack' })).toBe(true);
478+
expect(
479+
mockComponents.cfnService.listStackResources.calledWith({
480+
StackName: 'test-stack',
481+
NextToken: 'token123',
482+
MaxItems: 10,
483+
}),
484+
).toBe(true);
483485
});
484486

485487
it('should return empty array on error', async () => {
486488
mockComponents.cfnService.listStackResources.rejects(new Error('API Error'));
487489

488490
const handler = listStackResourcesHandler(mockComponents);
489-
const params: ListStackResourcesParams = { stackName: 'test-stack' };
491+
const params = { stackName: 'test-stack' };
490492
const result = (await handler(params, {} as any)) as ListStackResourcesResult;
491493

492494
expect(result.resources).toEqual([]);
@@ -496,7 +498,7 @@ describe('StackActionHandler', () => {
496498
mockComponents.cfnService.listStackResources.resolves({ StackResourceSummaries: undefined, $metadata: {} });
497499

498500
const handler = listStackResourcesHandler(mockComponents);
499-
const params: ListStackResourcesParams = { stackName: 'test-stack' };
501+
const params = { stackName: 'test-stack' };
500502
const result = (await handler(params, {} as any)) as ListStackResourcesResult;
501503

502504
expect(result.resources).toEqual([]);

tst/unit/services/CfnService.test.ts

Lines changed: 2 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -493,73 +493,13 @@ describe('CfnService', () => {
493493

494494
const result = await service.listStackResources({
495495
StackName: TEST_CONSTANTS.STACK_NAME,
496+
NextToken: 'token123',
497+
MaxItems: 10,
496498
});
497499

498500
expect(result).toEqual(MOCK_RESPONSES.LIST_STACK_RESOURCES);
499501
});
500502

501-
it('should handle pagination and collect all resources', async () => {
502-
const page1 = {
503-
...MOCK_RESPONSES.LIST_STACK_RESOURCES,
504-
StackResourceSummaries: [
505-
{
506-
LogicalResourceId: 'Resource1',
507-
ResourceType: 'AWS::S3::Bucket',
508-
LastUpdatedTimestamp: new Date(),
509-
ResourceStatus: 'CREATE_COMPLETE' as const,
510-
},
511-
{
512-
LogicalResourceId: 'Resource2',
513-
ResourceType: 'AWS::S3::Bucket',
514-
LastUpdatedTimestamp: new Date(),
515-
ResourceStatus: 'CREATE_COMPLETE' as const,
516-
},
517-
],
518-
NextToken: 'token1',
519-
};
520-
const page2 = {
521-
...MOCK_RESPONSES.LIST_STACK_RESOURCES,
522-
StackResourceSummaries: [
523-
{
524-
LogicalResourceId: 'Resource3',
525-
ResourceType: 'AWS::S3::Bucket',
526-
LastUpdatedTimestamp: new Date(),
527-
ResourceStatus: 'CREATE_COMPLETE' as const,
528-
},
529-
],
530-
NextToken: undefined,
531-
};
532-
533-
cloudFormationMock.on(ListStackResourcesCommand).resolvesOnce(page1).resolvesOnce(page2);
534-
535-
const result = await service.listStackResources({
536-
StackName: TEST_CONSTANTS.STACK_NAME,
537-
});
538-
539-
expect(result.StackResourceSummaries).toHaveLength(3);
540-
expect(result.StackResourceSummaries).toEqual([
541-
{
542-
LogicalResourceId: 'Resource1',
543-
ResourceType: 'AWS::S3::Bucket',
544-
LastUpdatedTimestamp: expect.any(Date),
545-
ResourceStatus: 'CREATE_COMPLETE' as const,
546-
},
547-
{
548-
LogicalResourceId: 'Resource2',
549-
ResourceType: 'AWS::S3::Bucket',
550-
LastUpdatedTimestamp: expect.any(Date),
551-
ResourceStatus: 'CREATE_COMPLETE' as const,
552-
},
553-
{
554-
LogicalResourceId: 'Resource3',
555-
ResourceType: 'AWS::S3::Bucket',
556-
LastUpdatedTimestamp: expect.any(Date),
557-
ResourceStatus: 'CREATE_COMPLETE' as const,
558-
},
559-
]);
560-
expect(result.NextToken).toBeUndefined();
561-
});
562-
563503
it('should throw StackNotFoundException when API call fails', async () => {
564504
const error = createStackNotFoundError();
565505
cloudFormationMock.on(ListStackResourcesCommand).rejects(error);

0 commit comments

Comments
 (0)