Skip to content

Commit

Permalink
feat(nuget): adds package source mapping and generate cached NuGet.co…
Browse files Browse the repository at this point in the history
…nfig without CLI commands (#25052)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
  • Loading branch information
wterpstra and viceice committed Oct 17, 2023
1 parent cfa2277 commit 65a69d5
Show file tree
Hide file tree
Showing 7 changed files with 471 additions and 161 deletions.
114 changes: 1 addition & 113 deletions lib/modules/manager/nuget/artifacts.spec.ts
Expand Up @@ -5,9 +5,7 @@ import { env, fs, git, mocked, scm } from '../../../../test/util';
import { GlobalConfig } from '../../../config/global';
import type { RepoGlobalConfig } from '../../../config/types';
import * as docker from '../../../util/exec/docker';
import * as _hostRules from '../../../util/host-rules';
import type { UpdateArtifactsConfig } from '../types';
import type { Registry } from './types';
import * as util from './util';
import * as nuget from '.';

Expand All @@ -17,8 +15,7 @@ jest.mock('../../../util/host-rules', () => mockDeep());
jest.mock('../../../util/git');
jest.mock('./util');

const { getConfiguredRegistries, getDefaultRegistries } = mocked(util);
const hostRules = mocked(_hostRules);
const { getDefaultRegistries } = mocked(util);

process.env.CONTAINERBASE = 'true';

Expand Down Expand Up @@ -404,113 +401,4 @@ describe('modules/manager/nuget/artifacts', () => {
]);
expect(execSnapshots).toBeEmptyArray();
});

it('authenticates at registries', async () => {
const execSnapshots = mockExecAll();
fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
git.getFiles.mockResolvedValueOnce({
'packages.lock.json': 'Current packages.lock.json',
});
fs.getLocalFiles.mockResolvedValueOnce({
'packages.lock.json': 'New packages.lock.json',
});
getConfiguredRegistries.mockResolvedValueOnce([
{
name: 'myRegistry',
url: 'https://my-registry.example.org',
},
{
name: 'myRegistry2',
url: 'https://my-registry2.example.org',
},
] satisfies Registry[]);
hostRules.find.mockImplementation((search) => {
if (search.hostType === 'nuget') {
if (search.url === 'https://my-registry.example.org') {
return {
username: 'some-username',
password: 'some-password',
};
} else {
return {
password: 'some-password',
};
}
}
return {};
});
expect(
await nuget.updateArtifacts({
packageFileName: 'project.csproj',
updatedDeps: [{ depName: 'dep' }],
newPackageFileContent: '{}',
config,
})
).toEqual([
{
file: {
contents: 'New packages.lock.json',
path: 'packages.lock.json',
type: 'addition',
},
},
]);
expect(execSnapshots).toMatchObject([
{
cmd:
'dotnet nuget add source https://my-registry.example.org/ --configfile /tmp/renovate/cache/__renovate-private-cache/nuget/nuget.config ' +
'--name myRegistry --username some-username --password some-password --store-password-in-clear-text',
},
{
cmd:
'dotnet nuget add source https://my-registry2.example.org/ --configfile /tmp/renovate/cache/__renovate-private-cache/nuget/nuget.config ' +
'--name myRegistry2 --password some-password --store-password-in-clear-text',
},
{
cmd: 'dotnet restore project.csproj --force-evaluate --configfile /tmp/renovate/cache/__renovate-private-cache/nuget/nuget.config',
},
]);
});

it('strips protocol version from feed url', async () => {
const execSnapshots = mockExecAll();
fs.getSiblingFileName.mockReturnValueOnce('packages.lock.json');
git.getFiles.mockResolvedValueOnce({
'packages.lock.json': 'Current packages.lock.json',
});
fs.getLocalFiles.mockResolvedValueOnce({
'packages.lock.json': 'New packages.lock.json',
});
getConfiguredRegistries.mockResolvedValueOnce([
{
name: 'myRegistry',
url: 'https://my-registry.example.org#protocolVersion=3',
},
] as never);
hostRules.find.mockImplementationOnce(() => ({}));
expect(
await nuget.updateArtifacts({
packageFileName: 'project.csproj',
updatedDeps: [{ depName: 'dep' }],
newPackageFileContent: '{}',
config,
})
).toEqual([
{
file: {
contents: 'New packages.lock.json',
path: 'packages.lock.json',
type: 'addition',
},
},
]);
expect(execSnapshots).toMatchObject([
{
cmd: 'dotnet nuget add source https://my-registry.example.org/ --configfile /tmp/renovate/cache/__renovate-private-cache/nuget/nuget.config --name myRegistry',
},
{
cmd: 'dotnet restore project.csproj --force-evaluate --configfile /tmp/renovate/cache/__renovate-private-cache/nuget/nuget.config',
},
]);
});
});
64 changes: 18 additions & 46 deletions lib/modules/manager/nuget/artifacts.ts
Expand Up @@ -13,57 +13,34 @@ import {
writeLocalFile,
} from '../../../util/fs';
import { getFiles } from '../../../util/git';
import * as hostRules from '../../../util/host-rules';
import { regEx } from '../../../util/regex';
import { NugetDatasource } from '../../datasource/nuget';
import { parseRegistryUrl } from '../../datasource/nuget/common';
import type {
UpdateArtifact,
UpdateArtifactsConfig,
UpdateArtifactsResult,
} from '../types';
import { createNuGetConfigXml } from './config-formatter';
import {
MSBUILD_CENTRAL_FILE,
NUGET_CENTRAL_FILE,
getDependentPackageFiles,
} from './package-tree';
import { getConfiguredRegistries, getDefaultRegistries } from './util';

async function addSourceCmds(
packageFileName: string,
_config: UpdateArtifactsConfig,
nugetConfigFile: string
): Promise<string[]> {
async function createCachedNuGetConfigFile(
nugetCacheDir: string,
packageFileName: string
): Promise<string> {
const registries =
(await getConfiguredRegistries(packageFileName)) ?? getDefaultRegistries();
const result: string[] = [];
for (const registry of registries) {
const { password, username } = hostRules.find({
hostType: NugetDatasource.id,
url: registry.url,
});
const registryInfo = parseRegistryUrl(registry.url);
let addSourceCmd = `dotnet nuget add source ${quote(
registryInfo.feedUrl
)} --configfile ${quote(nugetConfigFile)}`;
if (registry.name) {
// Add name for registry, if known.
addSourceCmd += ` --name ${quote(registry.name)}`;
}
// Add registry credentials from host rules, if configured.
if (username) {
// Add username from host rules, if configured.
addSourceCmd += ` --username ${quote(username)}`;
}
if (password) {
// Add password from host rules, if configured.
addSourceCmd += ` --password ${quote(
password
)} --store-password-in-clear-text`;
}
result.push(addSourceCmd);
}
return result;

const contents = createNuGetConfigXml(registries);

const cachedNugetConfigFile = join(nugetCacheDir, `nuget.config`);
await ensureDir(nugetCacheDir);
await outputCacheFile(cachedNugetConfigFile, contents);

return cachedNugetConfigFile;
}

async function runDotnetRestore(
Expand All @@ -73,6 +50,11 @@ async function runDotnetRestore(
): Promise<void> {
const nugetCacheDir = join(privateCacheDir(), 'nuget');

const nugetConfigFile = await createCachedNuGetConfigFile(
nugetCacheDir,
packageFileName
);

const execOptions: ExecOptions = {
docker: {},
extraEnv: {
Expand All @@ -84,17 +66,7 @@ async function runDotnetRestore(
],
};

const nugetConfigFile = join(nugetCacheDir, `nuget.config`);

await ensureDir(nugetCacheDir);

await outputCacheFile(
nugetConfigFile,
`<?xml version="1.0" encoding="utf-8"?>\n<configuration>\n</configuration>\n`
);

const cmds = [
...(await addSourceCmds(packageFileName, config, nugetConfigFile)),
...dependentPackageFileNames.map(
(fileName) =>
`dotnet restore ${quote(
Expand Down

0 comments on commit 65a69d5

Please sign in to comment.