From 581cae1a86c5ab9dd0e6be9c878dee42f3aa3276 Mon Sep 17 00:00:00 2001 From: Alexandru Manea Date: Wed, 17 Dec 2025 16:43:18 +0200 Subject: [PATCH] fix: resolve azure devOps project names [IAC-3468] --- src/cli/commands/test/iac/meta.ts | 9 ++- .../unit/cli/commands/test/iac/meta.spec.ts | 78 ++++++++++--------- 2 files changed, 50 insertions(+), 37 deletions(-) diff --git a/src/cli/commands/test/iac/meta.ts b/src/cli/commands/test/iac/meta.ts index a86a45a389..05e0d32c17 100644 --- a/src/cli/commands/test/iac/meta.ts +++ b/src/cli/commands/test/iac/meta.ts @@ -79,6 +79,9 @@ export function getProjectNameFromGitUrl(url: string) { /^(git|https?|ftp):\/\/[^:/]+(:[^/]+)?\/(?.*).git\/?$/, /^[^@]+@[^:]+:(?.*).git$/, /^(https?):\/\/github.com\/(?.*)$/, + /^https?:\/\/dev\.azure\.com\/(?[^/]+\/[^/]+\/_git\/[^/]+)/, + /^https?:\/\/ssh\.dev\.azure\.com\/v3\/(?.*)$/, + /^git@ssh\.dev\.azure\.com:v3\/(?.*)$/, ]; const trimmed = url.trim(); @@ -86,7 +89,11 @@ export function getProjectNameFromGitUrl(url: string) { for (const regexp of regexps) { const match = trimmed.match(regexp); - if (match && match.groups) { + if (match?.groups?.name) { + // Only strip "/_git/" if we are dealing with an Azure url + if (url.includes('dev.azure.com')) { + return match.groups.name.replace('/_git/', '/'); + } return match.groups.name; } } diff --git a/test/jest/unit/cli/commands/test/iac/meta.spec.ts b/test/jest/unit/cli/commands/test/iac/meta.spec.ts index 6753208199..42204681bb 100644 --- a/test/jest/unit/cli/commands/test/iac/meta.spec.ts +++ b/test/jest/unit/cli/commands/test/iac/meta.spec.ts @@ -193,57 +193,63 @@ describe('buildMeta', () => { }); describe('getProjectNameFromGitUrl', () => { - const urls = [ + const testCases = [ // SSH URLs without ~username expansion, as documented by "git clone". - - 'ssh://user@host.xz:1234/user/repo.git/', - 'ssh://host.xz:1234/user/repo.git/', - 'ssh://user@host.xz/user/repo.git/', - 'ssh://host.xz/user/repo.git/', - 'ssh://user@host.xz:1234/user/repo.git', - 'ssh://host.xz:1234/user/repo.git', - 'ssh://user@host.xz/user/repo.git', - 'ssh://host.xz/user/repo.git', + ['ssh://user@host.xz:1234/user/repo.git/', 'user/repo'], + ['ssh://host.xz:1234/user/repo.git/', 'user/repo'], + ['ssh://user@host.xz/user/repo.git/', 'user/repo'], + ['ssh://host.xz/user/repo.git/', 'user/repo'], + ['ssh://user@host.xz:1234/user/repo.git', 'user/repo'], + ['ssh://host.xz:1234/user/repo.git', 'user/repo'], + ['ssh://user@host.xz/user/repo.git', 'user/repo'], + ['ssh://host.xz/user/repo.git', 'user/repo'], // Git URLs without ~username expansion, as documented by "git clone". - - 'git://host.xz:1234/user/repo.git/', - 'git://host.xz/user/repo.git/', - 'git://host.xz:1234/user/repo.git', - 'git://host.xz/user/repo.git', + ['git://host.xz:1234/user/repo.git/', 'user/repo'], + ['git://host.xz/user/repo.git/', 'user/repo'], + ['git://host.xz:1234/user/repo.git', 'user/repo'], + ['git://host.xz/user/repo.git', 'user/repo'], // HTTP URLs, as documented by "git clone". - - 'http://host.xz:1234/user/repo.git/', - 'http://host.xz/user/repo.git/', - 'http://host.xz:1234/user/repo.git', - 'http://host.xz/user/repo.git', + ['http://host.xz:1234/user/repo.git/', 'user/repo'], + ['http://host.xz/user/repo.git/', 'user/repo'], + ['http://host.xz:1234/user/repo.git', 'user/repo'], + ['http://host.xz/user/repo.git', 'user/repo'], // HTTPS URLs, as documented by "git clone". - - 'https://host.xz:1234/user/repo.git/', - 'https://host.xz/user/repo.git/', - 'https://host.xz:1234/user/repo.git', - 'https://host.xz/user/repo.git', + ['https://host.xz:1234/user/repo.git/', 'user/repo'], + ['https://host.xz/user/repo.git/', 'user/repo'], + ['https://host.xz:1234/user/repo.git', 'user/repo'], + ['https://host.xz/user/repo.git', 'user/repo'], // SSH URLs without protocol, as used by GitHub. - - 'git@github.com:user/repo.git', + ['git@github.com:user/repo.git', 'user/repo'], // Remote URLs set up by 'actions/checkout' in GitHub workflows. - - 'https://github.com/user/repo', - 'http://github.com/user/repo', + ['https://github.com/user/repo', 'user/repo'], + ['http://github.com/user/repo', 'user/repo'], + + // Azure DevOps SSH via Proxy - http://ssh.dev.azure.com/v3/Org/Project/Repo + [ + 'http://ssh.dev.azure.com/v3/org-user/project/repo', + 'org-user/project/repo', + ], + // Azure DevOps Standard HTTP - https://dev.azure.com/Org/Project/_git/Repo + [ + 'https://dev.azure.com/org-user/project/_git/repo', + 'org-user/project/repo', + ], + // Azure DevOps SSH - git@ssh.dev.azure.com:v3/Org/Project/Repo + ['git@ssh.dev.azure.com:v3/org-user/project/repo', 'org-user/project/repo'], // If everything else fails, the URL should be returned as-is, but trimmed. - - 'user/repo', - ' user/repo', - 'user/repo ', + ['user/repo', 'user/repo'], + [' user/repo', 'user/repo'], + ['user/repo ', 'user/repo'], ]; - it.each(urls)('should parse %s', (url) => { - expect(getProjectNameFromGitUrl(url)).toBe('user/repo'); + it.each(testCases)('parses "%s" -> "%s"', (url, expected) => { + expect(getProjectNameFromGitUrl(url)).toBe(expected); }); });