From 39005855a9f08ae62eb6a6958237be9c88cea1a9 Mon Sep 17 00:00:00 2001
From: Michael Kriese <michael.kriese@visualon.de>
Date: Wed, 25 Oct 2023 09:26:32 +0200
Subject: [PATCH] fix(manager/nuget): add source mappings for default registry
 (#25400)

---
 lib/modules/datasource/nuget/index.ts  |  4 +-
 lib/modules/manager/nuget/types.ts     |  2 +-
 lib/modules/manager/nuget/util.spec.ts | 64 ++++++++++++++++++++++----
 lib/modules/manager/nuget/util.ts      | 23 ++++++---
 4 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/lib/modules/datasource/nuget/index.ts b/lib/modules/datasource/nuget/index.ts
index 53b7c78d7a..a34bcb0088 100644
--- a/lib/modules/datasource/nuget/index.ts
+++ b/lib/modules/datasource/nuget/index.ts
@@ -7,12 +7,12 @@ import * as v2 from './v2';
 import * as v3 from './v3';
 
 // https://api.nuget.org/v3/index.json is a default official nuget feed
-export const defaultRegistryUrls = ['https://api.nuget.org/v3/index.json'];
+export const nugetOrg = 'https://api.nuget.org/v3/index.json';
 
 export class NugetDatasource extends Datasource {
   static readonly id = 'nuget';
 
-  override readonly defaultRegistryUrls = defaultRegistryUrls;
+  override readonly defaultRegistryUrls = [nugetOrg];
 
   override readonly defaultVersioning = nugetVersioning.id;
 
diff --git a/lib/modules/manager/nuget/types.ts b/lib/modules/manager/nuget/types.ts
index be6c2f33a6..30b5d63547 100644
--- a/lib/modules/manager/nuget/types.ts
+++ b/lib/modules/manager/nuget/types.ts
@@ -13,7 +13,7 @@ export interface DotnetTool {
 export interface Registry {
   readonly url: string;
   readonly name?: string;
-  readonly sourceMappedPackagePatterns?: string[];
+  sourceMappedPackagePatterns?: string[];
 }
 
 export interface MsbuildGlobalManifest {
diff --git a/lib/modules/manager/nuget/util.spec.ts b/lib/modules/manager/nuget/util.spec.ts
index 2d2efbdc2c..1a898ccdbd 100644
--- a/lib/modules/manager/nuget/util.spec.ts
+++ b/lib/modules/manager/nuget/util.spec.ts
@@ -1,3 +1,4 @@
+import { codeBlock } from 'common-tags';
 import { XmlDocument } from 'xmldoc';
 import { fs } from '../../../../test/util';
 import { bumpPackageVersion } from './update';
@@ -35,14 +36,61 @@ describe('modules/manager/nuget/util', () => {
       fs.findUpLocal.mockReturnValue(
         Promise.resolve<string | null>('NuGet.config')
       );
-      fs.readLocalFile.mockImplementation((file): Promise<any> => {
-        const content: string | null =
-          '<configuration><packageSources><clear /><add key="nuget.org" value="https://api.nuget.org/v3/index.json" /><add key="contoso.com" value="https://contoso.com/packages/" /></packageSources><packageSourceMapping><packageSource key="nuget.org"><package pattern="*" /></packageSource><packageSource key="contoso.com"><package pattern="Contoso.*" /><package pattern="NuGet.Common" /></packageSource></packageSourceMapping></configuration>';
-        if (file !== 'NuGet.config') {
-          return Promise.reject(new Error(`Unexpected file: ${file}`));
-        }
-        return Promise.resolve(content);
-      });
+      fs.readLocalFile.mockResolvedValueOnce(
+        codeBlock`
+          <configuration>
+            <packageSources>
+              <clear/>
+              <add key="nuget.org" value="https://api.nuget.org/v3/index.json"/>
+              <add key="contoso.com" value="https://contoso.com/packages/"/>
+            </packageSources>
+            <packageSourceMapping>
+              <packageSource key="nuget.org">
+                <package pattern="*"/>
+              </packageSource>
+              <packageSource key="contoso.com">
+                <package pattern="Contoso.*"/>
+                <package pattern="NuGet.Common"/>
+              </packageSource>
+            </packageSourceMapping>
+          </configuration>`
+      );
+
+      const registries = await getConfiguredRegistries('NuGet.config');
+      expect(registries?.length).toBe(2);
+      expect(registries![0].name).toBe('nuget.org');
+      expect(registries![0].url).toBe('https://api.nuget.org/v3/index.json');
+      expect(registries![0].sourceMappedPackagePatterns).toEqual(['*']);
+
+      expect(registries![1].name).toBe('contoso.com');
+      expect(registries![1].url).toBe('https://contoso.com/packages/');
+      expect(registries![1].sourceMappedPackagePatterns).toEqual([
+        'Contoso.*',
+        'NuGet.Common',
+      ]);
+    });
+
+    it('reads nuget config file with default registry', async () => {
+      fs.findUpLocal.mockReturnValue(
+        Promise.resolve<string | null>('NuGet.config')
+      );
+      fs.readLocalFile.mockResolvedValueOnce(
+        codeBlock`
+        <configuration>
+          <packageSources>
+            <add key="contoso.com" value="https://contoso.com/packages/"/>
+          </packageSources>
+          <packageSourceMapping>
+            <packageSource key="nuget.org">
+              <package pattern="*"/>
+            </packageSource>
+            <packageSource key="contoso.com">
+              <package pattern="Contoso.*"/>
+              <package pattern="NuGet.Common"/>
+            </packageSource>
+          </packageSourceMapping>
+        </configuration>`
+      );
 
       const registries = await getConfiguredRegistries('NuGet.config');
       expect(registries?.length).toBe(2);
diff --git a/lib/modules/manager/nuget/util.ts b/lib/modules/manager/nuget/util.ts
index 10fa4bc805..17036469c6 100644
--- a/lib/modules/manager/nuget/util.ts
+++ b/lib/modules/manager/nuget/util.ts
@@ -3,7 +3,7 @@ import { XmlDocument, XmlElement } from 'xmldoc';
 import { logger } from '../../../logger';
 import { findUpLocal, readLocalFile } from '../../../util/fs';
 import { regEx } from '../../../util/regex';
-import { defaultRegistryUrls } from '../../datasource/nuget';
+import { nugetOrg } from '../../datasource/nuget';
 import type { Registry } from './types';
 
 export async function readFileAsXmlDocument(
@@ -20,12 +20,12 @@ export async function readFileAsXmlDocument(
   }
 }
 
-const defaultRegistries = defaultRegistryUrls.map(
-  (registryUrl) => ({ url: registryUrl } as Registry)
-);
-
+/**
+ * The default `nuget.org` named registry.
+ * @returns the default registry for NuGet
+ */
 export function getDefaultRegistries(): Registry[] {
-  return [...defaultRegistries];
+  return [{ url: nugetOrg, name: 'nuget.org' }];
 }
 
 export async function getConfiguredRegistries(
@@ -57,6 +57,17 @@ export async function getConfiguredRegistries(
   const packageSourceMapping = nuGetConfig.childNamed('packageSourceMapping');
 
   const registries = getDefaultRegistries();
+
+  // Map optional source mapped package patterns to default registries
+  for (const registry of registries) {
+    const sourceMappedPackagePatterns = packageSourceMapping
+      ?.childWithAttribute('key', registry.name)
+      ?.childrenNamed('package')
+      .map((packagePattern) => packagePattern.attr['pattern']);
+
+    registry.sourceMappedPackagePatterns = sourceMappedPackagePatterns;
+  }
+
   for (const child of packageSources.children) {
     if (child.type === 'element') {
       if (child.name === 'clear') {
-- 
GitLab