From 20a803dc9dd0ec3883642e7ea2f7cd229059d676 Mon Sep 17 00:00:00 2001 From: James Agger Date: Sun, 12 Jul 2026 13:21:50 -0400 Subject: [PATCH] fix(backend): match GitLab project topics case-insensitively GitLab connection topic filters lowercased the configured topics but compared them against project topics in their original case, so a project topic like 'Backend' would not match a config topic such as 'backend'. Lowercase the project topics as well so include/exclude topic matching is case-insensitive and symmetric. Fixes #1388 --- CHANGELOG.md | 3 +++ packages/backend/src/gitlab.test.ts | 19 ++++++++++++++++--- packages/backend/src/gitlab.ts | 4 ++-- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 429b650f3..d96758219 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed +- Fixed GitLab connection topic filters (`topics` / `exclude.topics`) being case-sensitive on the project side, so mixed-case GitLab project topics (e.g. `Backend`) now match lowercase config topics. [#1388](https://github.com/sourcebot-dev/sourcebot/issues/1388) + ## [5.1.0] - 2026-07-10 ### Changed diff --git a/packages/backend/src/gitlab.test.ts b/packages/backend/src/gitlab.test.ts index a502488df..956374a87 100644 --- a/packages/backend/src/gitlab.test.ts +++ b/packages/backend/src/gitlab.test.ts @@ -141,16 +141,29 @@ test('shouldExcludeProject returns false when exclude.topics does not match any })).toBe(false); }); -test('shouldExcludeProject include.topics matching is case-sensitive on the project side.', () => { +test('shouldExcludeProject include.topics matching is case-insensitive on the project side.', () => { const project = { path_with_namespace: 'test/project', topics: ['Backend'], } as unknown as ProjectSchema; - // The function lowercases config topics but not project topics, - // so 'Backend' does not match the lowercased pattern 'backend'. + // Both config and project topics are lowercased before matching, + // so the mixed-case project topic 'Backend' matches the pattern 'backend'. expect(shouldExcludeProject({ project, include: { topics: ['backend'] }, + })).toBe(false); +}); + +test('shouldExcludeProject exclude.topics matching is case-insensitive on the project side.', () => { + const project = { + path_with_namespace: 'test/project', + topics: ['Deprecated'], + } as unknown as ProjectSchema; + + // The mixed-case project topic 'Deprecated' matches the exclude pattern 'deprecated'. + expect(shouldExcludeProject({ + project, + exclude: { topics: ['deprecated'] }, })).toBe(true); }); diff --git a/packages/backend/src/gitlab.ts b/packages/backend/src/gitlab.ts index 94a6e0710..6cdadb43a 100644 --- a/packages/backend/src/gitlab.ts +++ b/packages/backend/src/gitlab.ts @@ -249,7 +249,7 @@ export const shouldExcludeProject = ({ if (include?.topics) { const configTopics = include.topics.map(topic => topic.toLowerCase()); - const projectTopics = project.topics ?? []; + const projectTopics = (project.topics ?? []).map(topic => topic.toLowerCase()); const matchingTopics = projectTopics.filter((topic) => micromatch.isMatch(topic, configTopics)); if (matchingTopics.length === 0) { @@ -260,7 +260,7 @@ export const shouldExcludeProject = ({ if (exclude?.topics) { const configTopics = exclude.topics.map(topic => topic.toLowerCase()); - const projectTopics = project.topics ?? []; + const projectTopics = (project.topics ?? []).map(topic => topic.toLowerCase()); const matchingTopics = projectTopics.filter((topic) => micromatch.isMatch(topic, configTopics)); if (matchingTopics.length > 0) {