diff --git a/.changeset/fifty-clubs-play.md b/.changeset/fifty-clubs-play.md index 561e24a130..33d4378e69 100644 --- a/.changeset/fifty-clubs-play.md +++ b/.changeset/fifty-clubs-play.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': minor --- -Updated the `list-scaffolder-tasks` action to support the new "status" filter paramter, allowing the action to return tasks matching a specific status. +Updated the `list-scaffolder-tasks` action to support the new "status" filter parameter, allowing the action to return tasks matching a specific status. diff --git a/plugins/scaffolder-backend/src/actions/listScaffolderTasksAction.ts b/plugins/scaffolder-backend/src/actions/listScaffolderTasksAction.ts index 3f3a0eed04..b3374a0946 100644 --- a/plugins/scaffolder-backend/src/actions/listScaffolderTasksAction.ts +++ b/plugins/scaffolder-backend/src/actions/listScaffolderTasksAction.ts @@ -65,29 +65,20 @@ Filtering by one or multiple statuses is supported. Pagination is supported via .min(0) .describe('The offset to start from for pagination') .optional(), - status: z - .union([ - z.enum([ - 'open', - 'processing', - 'completed', - 'failed', - 'cancelled', - 'skipped', - ]), - z.array( - z.enum([ - 'open', - 'processing', - 'completed', - 'failed', - 'cancelled', - 'skipped', - ]), - ), - ]) - .optional() - .describe('Filter tasks by status, or an array of statuses'), + status: (() => { + const statusEnum = z.enum([ + 'open', + 'processing', + 'completed', + 'failed', + 'cancelled', + 'skipped', + ]); + return z + .union([statusEnum, z.array(statusEnum).nonempty()]) + .optional() + .describe('Filter tasks by status, or an array of statuses'); + })(), }), output: z => z diff --git a/plugins/scaffolder-node/src/scaffolderService.test.ts b/plugins/scaffolder-node/src/scaffolderService.test.ts index de0870751f..f9b0d85f32 100644 --- a/plugins/scaffolder-node/src/scaffolderService.test.ts +++ b/plugins/scaffolder-node/src/scaffolderService.test.ts @@ -202,4 +202,61 @@ describe('scaffolderServiceRef', () => { expect(result).toEqual({ items: [], totalItems: 0 }); }); + + it('should serialize a single status as a repeated query param for listTasks', async () => { + expect.assertions(1); + + server.use( + rest.get('*/api/scaffolder/v2/tasks', (req, res, ctx) => { + expect(req.url.searchParams.getAll('status')).toEqual(['completed']); + return res(ctx.json({ tasks: [], totalTasks: 0 })); + }), + ); + + const tester = ServiceFactoryTester.from( + createServiceFactory({ + service: createServiceRef({ id: 'unused-dummy' }), + deps: {}, + factory() {}, + }), + { dependencies: [mockServices.discovery.factory()] }, + ); + + const scaffolder = await tester.getService(scaffolderServiceRef); + + await scaffolder.listTasks( + { status: 'completed' }, + { credentials: mockCredentials.user() }, + ); + }); + + it('should serialize multiple statuses as repeated query params for listTasks', async () => { + expect.assertions(1); + + server.use( + rest.get('*/api/scaffolder/v2/tasks', (req, res, ctx) => { + expect(req.url.searchParams.getAll('status')).toEqual([ + 'completed', + 'failed', + ]); + return res(ctx.json({ tasks: [], totalTasks: 0 })); + }), + ); + + const tester = ServiceFactoryTester.from( + createServiceFactory({ + service: createServiceRef({ id: 'unused-dummy' }), + deps: {}, + factory() {}, + }), + { dependencies: [mockServices.discovery.factory()] }, + ); + + const scaffolder = await tester.getService(scaffolderServiceRef); + + await scaffolder.listTasks( + { status: ['completed', 'failed'] }, + { credentials: mockCredentials.user() }, + ); + }); });