From 8cc08e0660250eaa9b02b5e51ee034d4de3f68e4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Hil=C3=A1rio=20Coelho?=
 <5185271+hilariocoelho@users.noreply.github.com>
Date: Sun, 11 Jun 2023 17:58:46 +0100
Subject: [PATCH] fix(azure): go-import meta header support for Azure DevOps 
 (#22664)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---
 lib/modules/datasource/go/base.spec.ts | 19 ++++++++++
 lib/modules/datasource/go/base.ts      | 49 +++++++++++++++-----------
 lib/util/common.spec.ts                | 16 +++++----
 lib/util/common.ts                     |  7 +++-
 4 files changed, 62 insertions(+), 29 deletions(-)

diff --git a/lib/modules/datasource/go/base.spec.ts b/lib/modules/datasource/go/base.spec.ts
index 0ad33fd4c5..68ad5bf917 100644
--- a/lib/modules/datasource/go/base.spec.ts
+++ b/lib/modules/datasource/go/base.spec.ts
@@ -346,6 +346,25 @@ describe('modules/datasource/go/base', () => {
         });
       });
 
+      it('handles go-import with azure devops source', async () => {
+        const meta =
+          '<meta name="go-import" content="dev.azure.com/my-organization/my-project/_git/my-repo.git git https://dev.azure.com/my-organization/my-project/_git/my-repo.git" />';
+        httpMock
+          .scope('https://dev.azure.com')
+          .get('/my-organization/my-project/_git/my-repo.git?go-get=1')
+          .reply(200, meta);
+
+        const res = await BaseGoDatasource.getDatasource(
+          'dev.azure.com/my-organization/my-project/_git/my-repo.git'
+        );
+
+        expect(res).toEqual({
+          datasource: GitTagsDatasource.id,
+          packageName:
+            'https://dev.azure.com/my-organization/my-project/_git/my-repo',
+        });
+      });
+
       it('handles uncommon imports', async () => {
         const meta =
           '<meta name="go-import" content="example.com/uncommon git ssh://git.example.com/uncommon">';
diff --git a/lib/modules/datasource/go/base.ts b/lib/modules/datasource/go/base.ts
index b212e2c671..b1cf3948c7 100644
--- a/lib/modules/datasource/go/base.ts
+++ b/lib/modules/datasource/go/base.ts
@@ -172,7 +172,7 @@ export class BaseGoDatasource {
     goModule: string
   ): DataSource | null {
     const importMatch = regEx(
-      `<meta\\s+name="?go-import"?\\s+content="([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)">`
+      `<meta\\s+name="?go-import"?\\s+content="([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)"\\s*\\/?>`
     ).exec(res);
 
     if (!importMatch) {
@@ -199,27 +199,34 @@ export class BaseGoDatasource {
     }
     // fall back to old behaviour if detection did not work
 
-    if (detectPlatform(goImportURL) === 'github') {
-      // split the go module from the URL: host/go/module -> go/module
-      // TODO: `parsedUrl.pathname` can be undefined
-      const packageName = trimTrailingSlash(`${parsedUrl.pathname}`)
-        .replace(regEx(/\.git$/), '')
-        .split('/')
-        .slice(-2)
-        .join('/');
+    switch (detectPlatform(goImportURL)) {
+      case 'github': {
+        // split the go module from the URL: host/go/module -> go/module
+        // TODO: `parsedUrl.pathname` can be undefined
+        const packageName = trimTrailingSlash(`${parsedUrl.pathname}`)
+          .replace(regEx(/\.git$/), '')
+          .split('/')
+          .slice(-2)
+          .join('/');
 
-      return {
-        datasource: GithubTagsDatasource.id,
-        registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`,
-        packageName,
-      };
+        return {
+          datasource: GithubTagsDatasource.id,
+          registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`,
+          packageName,
+        };
+      }
+      case 'azure': {
+        return {
+          datasource: GitTagsDatasource.id,
+          packageName: goImportURL.replace(regEx(/\.git$/), ''),
+        };
+      }
+      default: {
+        return {
+          datasource: GitTagsDatasource.id,
+          packageName: goImportURL,
+        };
+      }
     }
-
-    // Fall back to git tags
-
-    return {
-      datasource: GitTagsDatasource.id,
-      packageName: goImportURL,
-    };
   }
 }
diff --git a/lib/util/common.spec.ts b/lib/util/common.spec.ts
index e29e2a9ea6..b7c354a2bf 100644
--- a/lib/util/common.spec.ts
+++ b/lib/util/common.spec.ts
@@ -6,13 +6,15 @@ describe('util/common', () => {
 
   describe('detectPlatform', () => {
     it.each`
-      url                                                    | hostType
-      ${'some-invalid@url:::'}                               | ${null}
-      ${'https://enterprise.example.com/chalk/chalk'}        | ${null}
-      ${'https://github.com/semantic-release/gitlab'}        | ${'github'}
-      ${'https://github-enterprise.example.com/chalk/chalk'} | ${'github'}
-      ${'https://gitlab.com/chalk/chalk'}                    | ${'gitlab'}
-      ${'https://gitlab-enterprise.example.com/chalk/chalk'} | ${'gitlab'}
+      url                                                                    | hostType
+      ${'some-invalid@url:::'}                                               | ${null}
+      ${'https://enterprise.example.com/chalk/chalk'}                        | ${null}
+      ${'https://github.com/semantic-release/gitlab'}                        | ${'github'}
+      ${'https://github-enterprise.example.com/chalk/chalk'}                 | ${'github'}
+      ${'https://gitlab.com/chalk/chalk'}                                    | ${'gitlab'}
+      ${'https://gitlab-enterprise.example.com/chalk/chalk'}                 | ${'gitlab'}
+      ${'https://dev.azure.com/my-organization/my-project/_git/my-repo.git'} | ${'azure'}
+      ${'https://myorg.visualstudio.com/my-project/_git/my-repo.git'}        | ${'azure'}
     `('("$url") === $hostType', ({ url, hostType }) => {
       expect(detectPlatform(url)).toBe(hostType);
     });
diff --git a/lib/util/common.ts b/lib/util/common.ts
index 5133bfc2b1..4e7cd878e6 100644
--- a/lib/util/common.ts
+++ b/lib/util/common.ts
@@ -11,7 +11,9 @@ import { parseUrl } from './url';
  * @param url the url to detect `platform` from
  * @returns matched `platform` if found, otherwise `null`
  */
-export function detectPlatform(url: string): 'gitlab' | 'github' | null {
+export function detectPlatform(
+  url: string
+): 'gitlab' | 'github' | 'azure' | null {
   const { hostname } = parseUrl(url) ?? {};
   if (hostname === 'github.com' || hostname?.includes('github')) {
     return 'github';
@@ -19,6 +21,9 @@ export function detectPlatform(url: string): 'gitlab' | 'github' | null {
   if (hostname === 'gitlab.com' || hostname?.includes('gitlab')) {
     return 'gitlab';
   }
+  if (hostname === 'dev.azure.com' || hostname?.endsWith('.visualstudio.com')) {
+    return 'azure';
+  }
 
   const hostType = hostRules.hostType({ url });
 
-- 
GitLab