diff --git a/.changeset/fix-gitlab-topic-filter.md b/.changeset/fix-gitlab-topic-filter.md new file mode 100644 index 0000000000..5d56dcd232 --- /dev/null +++ b/.changeset/fix-gitlab-topic-filter.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-backend-module-gitlab': patch +--- + +Fixed GitLab project topic filtering by using correct API parameter 'topic' instead of 'topics' diff --git a/plugins/catalog-backend-module-gitlab/src/lib/client.ts b/plugins/catalog-backend-module-gitlab/src/lib/client.ts index df211e4bd0..95b0b4afa7 100644 --- a/plugins/catalog-backend-module-gitlab/src/lib/client.ts +++ b/plugins/catalog-backend-module-gitlab/src/lib/client.ts @@ -41,7 +41,7 @@ interface ListProjectOptions extends CommonListOptions { archived?: boolean; group?: string; membership?: boolean; - topics?: string; + topic?: string; last_activity_after?: string; } diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts index 3dc979e776..90ee56d5b8 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.test.ts @@ -827,3 +827,67 @@ describe('GitlabDiscoveryEntityProvider - simple parameter', () => { }); }); }); + +describe('GitlabDiscoveryEntityProvider - topic parameter', () => { + it('should pass topic (singular) when topics (plural) is configured', async () => { + const config = new ConfigReader({ + integrations: { + gitlab: [ + { + host: 'example.com', + apiBaseUrl: 'https://example.com/api/v4', + token: 'test-token', + }, + ], + }, + catalog: { + providers: { + gitlab: { + 'test-id': { + host: 'example.com', + group: 'test-group', + topics: ['topic1', 'topic2'], + }, + }, + }, + }, + }); + + const schedule = new PersistingTaskRunner(); + const entityProviderConnection: EntityProviderConnection = { + applyMutation: jest.fn(), + refresh: jest.fn(), + }; + + const provider = GitlabDiscoveryEntityProvider.fromConfig(config, { + logger, + schedule, + })[0]; + + // Mock the GitLabClient listProjects method to verify parameters + const mockListProjects = jest.fn().mockResolvedValue({ + items: [], + nextPage: undefined, + }); + + (provider as any).gitLabClient.listProjects = mockListProjects; + + await provider.connect(entityProviderConnection); + await provider.refresh(logger); + + expect(mockListProjects).toHaveBeenCalledWith({ + group: 'test-group', + page: undefined, + per_page: 50, + archived: false, + topic: 'topic1,topic2', // Correct singular 'topic' parameter + simple: true, + }); + // Verify the old incorrect 'topics' key is NOT present + expect(mockListProjects).not.toHaveBeenCalledWith( + expect.objectContaining({ + topics: expect.anything(), + }), + ); + }); +}); diff --git a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts index 40936a4d77..92f4ac797a 100644 --- a/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts +++ b/plugins/catalog-backend-module-gitlab/src/providers/GitlabDiscoveryEntityProvider.ts @@ -383,7 +383,7 @@ export class GitlabDiscoveryEntityProvider implements EntityProvider { per_page: 50, ...(!this.config.includeArchivedRepos && { archived: false }), ...(this.config.membership && { membership: true }), - ...(this.config.topics && { topics: this.config.topics }), + ...(this.config.topics && { topic: this.config.topics }), // Only use simple=true when we don't need to skip forked repos. // The simple=true parameter reduces response size by returning fewer fields, // but it excludes the 'forked_from_project' field which is required for fork detection.