From 8365a1c869a0025c4192988e5e271169a722e3b6 Mon Sep 17 00:00:00 2001 From: Tankatronic Date: Wed, 15 Apr 2026 12:13:49 -0700 Subject: [PATCH] Implement Azure DevOps URL parsing for repositories Added support for Azure DevOps URL parsing, including both modern and legacy formats, to extract relevant repository information. --- .../modules/custom-module-manager.js | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tools/installer/modules/custom-module-manager.js b/tools/installer/modules/custom-module-manager.js index 482c4dc43..9d95b9101 100644 --- a/tools/installer/modules/custom-module-manager.js +++ b/tools/installer/modules/custom-module-manager.js @@ -73,6 +73,56 @@ class CustomModuleManager { }; } + // Azure DevOps URL: https://dev.azure.com/{org}/{project}/_git/{repo} + // Also supports legacy: https://{org}.visualstudio.com/{project}/_git/{repo} + const adoModernMatch = trimmed.match( + /^https?:\/\/(dev\.azure\.com)\/([^/]+)\/([^/]+)\/_git\/([^/.]+?)(?:\.git)?(\/.*)?$/, + ); + const adoLegacyMatch = + !adoModernMatch && + trimmed.match( + /^https?:\/\/([^/]+\.visualstudio\.com)\/([^/]+)\/_git\/([^/.]+?)(?:\.git)?(\/.*)?$/, + ); + const adoMatch = adoModernMatch || adoLegacyMatch; + if (adoMatch) { + let host, org, project, repo, remainder; + if (adoModernMatch) { + [, host, org, project, repo, remainder] = adoModernMatch; + } else { + // Legacy: org is in the hostname, path is /{project}/_git/{repo} + [, host, project, repo, remainder] = adoLegacyMatch; + org = null; + } + + const cloneUrl = adoModernMatch + ? `https://${host}/${org}/${project}/_git/${repo}` + : `https://${host}/${project}/_git/${repo}`; + let subdir = null; + + if (remainder) { + // Azure DevOps uses ?path=/subdir or /path/subdir patterns + const subdirMatch = remainder.match(/^\/(.+)$/); + if (subdirMatch) { + subdir = subdirMatch[1].replace(/\/$/, ''); + } + } + + const cacheKey = adoModernMatch + ? `${host}/${org}/${project}/${repo}` + : `${host}/${project}/${repo}`; + + return { + type: 'url', + cloneUrl, + subdir, + localPath: null, + cacheKey, + displayName: `${project}/${repo}`, + isValid: true, + error: null, + }; + } + // HTTPS URL: https://host/owner/repo[/tree/branch/subdir][.git] const httpsMatch = trimmed.match(/^https?:\/\/([^/]+)\/([^/]+)\/([^/.]+?)(?:\.git)?(\/.*)?$/); if (httpsMatch) {