From ffb5ff47e20dd6e7fdd3c6a8381597383625e380 Mon Sep 17 00:00:00 2001 From: Lokesh Kaki Date: Tue, 17 Mar 2026 22:16:07 -0500 Subject: [PATCH] fix(catalog-backend-module-azure): conditionally wire SCM events bridge, fix URL encoding and error messages Signed-off-by: Lokesh Kaki --- .../events/analyzeAzureDevOpsWebhookEvent.ts | 30 ++++++++++--------- .../catalogModuleAzureDevOpsEntityProvider.ts | 27 ++++++++++------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/plugins/catalog-backend-module-azure/src/events/analyzeAzureDevOpsWebhookEvent.ts b/plugins/catalog-backend-module-azure/src/events/analyzeAzureDevOpsWebhookEvent.ts index 0dfa1c0f99..9b7f246e12 100644 --- a/plugins/catalog-backend-module-azure/src/events/analyzeAzureDevOpsWebhookEvent.ts +++ b/plugins/catalog-backend-module-azure/src/events/analyzeAzureDevOpsWebhookEvent.ts @@ -172,12 +172,17 @@ function toLocationUrl(options: { return undefined; } - const url = new URL(options.remoteUrl); + // Match the URL format produced by AzureDevOpsEntityProvider.createObjectUrl + // which uses encodeURI on the full URL string with path and version as raw + // query parameter values. Using URL/searchParams would produce different + // encoding (e.g. %2F for slashes in branch names) and fail to match existing + // catalog location targets. const branch = branchNameFromRef(options.branchRef); - url.search = branch - ? `path=${options.path}&version=GB${branch}` - : `path=${options.path}`; - return encodeURI(url.toString()); + let fullUrl = `${options.remoteUrl}?path=${options.path}`; + if (branch) { + fullUrl += `&version=GB${branch}`; + } + return encodeURI(fullUrl); } function toCommitUrl( @@ -495,18 +500,15 @@ async function onRepositoryEvent( if (eventType === 'git.repo.renamed' && toUrl) { const oldName = asString(resource?.oldName); - if (!oldName) { - return { - result: 'ignored', - reason: 'Azure DevOps repository renamed event is missing oldName', - }; - } - const fromUrl = replaceRepoNameInRemoteUrl(toUrl, oldName); + const fromUrl = oldName + ? replaceRepoNameInRemoteUrl(toUrl, oldName) + : undefined; if (!fromUrl) { return { result: 'ignored', - reason: - 'Azure DevOps repository renamed event has an unexpected repository.remoteUrl format', + reason: oldName + ? 'Azure DevOps repository renamed event has an unexpected repository.remoteUrl format' + : 'Azure DevOps repository renamed event is missing oldName', }; } diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts index b7ad3cf6e6..c3475de239 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.ts @@ -75,17 +75,22 @@ export const catalogModuleAzureEntityProvider = createBackendModule({ ); } - const bridge = new AzureDevOpsScmEventsBridge({ - logger, - events, - catalogScmEvents, - }); - lifecycle.addStartupHook(async () => { - await bridge.start(); - }); - lifecycle.addShutdownHook(async () => { - await bridge.stop(); - }); + // Only wire up the SCM events bridge when Azure DevOps provider + // configuration is present — Azure Blob Storage users should not be + // required to handle Azure DevOps webhook events. + if (config.has('catalog.providers.azureDevOps')) { + const bridge = new AzureDevOpsScmEventsBridge({ + logger, + events, + catalogScmEvents, + }); + lifecycle.addStartupHook(async () => { + await bridge.start(); + }); + lifecycle.addShutdownHook(async () => { + await bridge.stop(); + }); + } }, }); },