From 9af9fc1a85340bed776459f2988d8de1005c2b61 Mon Sep 17 00:00:00 2001 From: Lokesh Kaki Date: Tue, 17 Mar 2026 20:00:48 -0500 Subject: [PATCH] fix(catalog-backend-module-gitlab): fix push event rename heuristic and add API docs Signed-off-by: Lokesh Kaki --- .../events/analyzeGitLabWebhookEvent.test.ts | 14 ++- .../src/events/analyzeGitLabWebhookEvent.ts | 92 +++++++------------ 2 files changed, 45 insertions(+), 61 deletions(-) diff --git a/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.test.ts b/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.test.ts index 8e792f1822..73c702c790 100644 --- a/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.test.ts @@ -85,7 +85,7 @@ describe('analyzeGitLabWebhookEvent', () => { `); }); - it('handles file rename as location move', async () => { + it('handles file add and delete in the same commit as separate events', async () => { const payload = { object_kind: 'push', ref: 'refs/heads/main', @@ -116,9 +116,15 @@ describe('analyzeGitLabWebhookEvent', () => { "context": { "commitUrl": "https://gitlab.example.com/group-a/repo-a/-/commit/c3", }, - "fromUrl": "https://gitlab.example.com/group-a/repo-a/-/blob/main/old/catalog-info.yaml", - "toUrl": "https://gitlab.example.com/group-a/repo-a/-/blob/main/new/catalog-info.yaml", - "type": "location.moved", + "type": "location.created", + "url": "https://gitlab.example.com/group-a/repo-a/-/blob/main/new/catalog-info.yaml", + }, + { + "context": { + "commitUrl": "https://gitlab.example.com/group-a/repo-a/-/commit/c3", + }, + "type": "location.deleted", + "url": "https://gitlab.example.com/group-a/repo-a/-/blob/main/old/catalog-info.yaml", }, ], "result": "ok", diff --git a/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.ts b/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.ts index 2ca7a14a6a..f733d3b07d 100644 --- a/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.ts +++ b/plugins/catalog-backend-module-gitlab/src/events/analyzeGitLabWebhookEvent.ts @@ -21,13 +21,31 @@ import { WebhookPushEventSchema } from '@gitbeaker/rest'; type StringRecord = Record; -/** @alpha */ +/** + * Options for {@link analyzeGitLabWebhookEvent}. + * @alpha + */ export interface AnalyzeWebhookEventOptions { + /** Optional logger for debug output when events are ignored or unsupported. */ logger?: LoggerService; + /** + * Predicate that returns true for file paths that are relevant to the + * catalog (e.g. paths ending in `.yaml` or `.yml`). + */ isRelevantPath: (path: string) => boolean; } -/** @alpha */ +/** + * The result of analyzing a GitLab webhook event. + * + * - `ok` — one or more catalog SCM events were produced. + * - `ignored` — the event was valid but not relevant (e.g. push to a + * non-default branch, or no catalog files affected). + * - `aborted` — the event could not be fully processed due to missing data. + * - `unsupported-event` — the event type is not handled by this analyzer. + * + * @alpha + */ export type AnalyzeWebhookEventResult = | { result: 'unsupported-event'; @@ -55,11 +73,6 @@ type PathState = type: 'removed'; commitUrl?: string; } - | { - type: 'renamed'; - fromPath: string; - commitUrl?: string; - } | { type: 'changed'; commitUrl?: string; @@ -172,13 +185,6 @@ function pathStateToCatalogScmEvent( url: toBlobUrl(path), context, }; - case 'renamed': - return { - type: 'location.moved', - fromUrl: toBlobUrl(event.fromPath), - toUrl: toBlobUrl(path), - context, - }; case 'changed': return { type: 'location.updated', @@ -226,13 +232,6 @@ function applyRemovedPath( pathState.set(path, { type: 'removed', commitUrl }); return; } - if (previous.type === 'renamed') { - if (!pathState.has(previous.fromPath)) { - pathState.set(previous.fromPath, { type: 'removed', commitUrl }); - } - pathState.delete(path); - return; - } pathState.set(path, previous); } @@ -253,34 +252,6 @@ function applyModifiedPath( pathState.set(path, previous); } -function applyRenamedPath( - pathState: Map, - fromPath: string, - toPath: string, - commitUrl: string | undefined, -) { - const previous = pathState.get(fromPath); - pathState.delete(fromPath); - - if (!previous) { - pathState.set(toPath, { type: 'renamed', fromPath, commitUrl }); - return; - } - if (previous.type === 'added') { - pathState.set(toPath, { type: 'added', commitUrl }); - return; - } - if (previous.type === 'renamed') { - pathState.set(toPath, { - type: 'renamed', - fromPath: previous.fromPath, - commitUrl, - }); - return; - } - pathState.set(toPath, { type: 'renamed', fromPath, commitUrl }); -} - async function onPushEvent( event: WebhookPushEventSchema, options: AnalyzeWebhookEventOptions, @@ -328,16 +299,11 @@ async function onPushEvent( applyModifiedPath(pathState, path, commitUrl); } - const renamePairs = Math.min(added.length, removed.length); - for (let i = 0; i < renamePairs; i++) { - applyRenamedPath(pathState, removed[i], added[i], commitUrl); - } - - for (const path of added.slice(renamePairs)) { + for (const path of added) { applyAddedPath(pathState, path, commitUrl); } - for (const path of removed.slice(renamePairs)) { + for (const path of removed) { applyRemovedPath(pathState, path, commitUrl); } } @@ -506,7 +472,19 @@ async function onRepositoryUpdateEvent( }; } -/** @alpha */ +/** + * Analyzes a GitLab webhook event and translates it into zero or more catalog + * SCM events that entity providers can act on. + * + * Supported event types: + * - `push` — translates file-level adds, modifications, and deletions on the + * default branch into `location.created`, `location.updated`, and + * `location.deleted` events for paths matching `isRelevantPath`. + * - `repository_update` — translates repository renames, transfers, and + * deletions into `repository.moved` and `repository.deleted` events. + * + * @alpha + */ export async function analyzeGitLabWebhookEvent( eventType: string, eventPayload: unknown,