Skip to content

Commit

Permalink
refactor(datasource/nuget): Convert to class (#14140)
Browse files Browse the repository at this point in the history
* refactor(datasource/nuget): Convert to class

* Fix strict nulls and obsolete URL

* Fixes

* Fix mutability

Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
  • Loading branch information
3 people authored Feb 13, 2022
1 parent f72517d commit b0ce30b
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 110 deletions.
4 changes: 2 additions & 2 deletions lib/datasource/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { JenkinsPluginsDatasource } from './jenkins-plugins';
import * as maven from './maven';
import { NodeDatasource } from './node';
import * as npm from './npm';
import * as nuget from './nuget';
import { NugetDatasource } from './nuget';
import { OrbDatasource } from './orb';
import { PackagistDatasource } from './packagist';
import { PodDatasource } from './pod';
Expand Down Expand Up @@ -71,7 +71,7 @@ api.set(JenkinsPluginsDatasource.id, new JenkinsPluginsDatasource());
api.set('maven', maven);
api.set(NodeDatasource.id, new NodeDatasource());
api.set('npm', npm);
api.set('nuget', nuget);
api.set(NugetDatasource.id, new NugetDatasource());
api.set(OrbDatasource.id, new OrbDatasource());
api.set(PackagistDatasource.id, new PackagistDatasource());
api.set(PodDatasource.id, new PodDatasource());
Expand Down
32 changes: 30 additions & 2 deletions lib/datasource/nuget/common.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
import { logger } from '../../logger';
import { regEx } from '../../util/regex';

export const id = 'nuget';
import { parseUrl } from '../../util/url';
import type { ParsedRegistryUrl } from './types';

const buildMetaRe = regEx(/\+.+$/g);

export function removeBuildMeta(version: string): string {
return version?.replace(buildMetaRe, '');
}

const protocolVersionRegExp = regEx(/#protocolVersion=(?<protocol>2|3)/);

export function parseRegistryUrl(registryUrl: string): ParsedRegistryUrl {
const parsedUrl = parseUrl(registryUrl);
if (!parsedUrl) {
logger.debug(
{ urL: registryUrl },
`nuget registry failure: can't parse ${registryUrl}`
);
return { feedUrl: registryUrl, protocolVersion: null };
}
let protocolVersion = 2;
const protocolVersionMatch = protocolVersionRegExp.exec(
parsedUrl.hash
)?.groups;
if (protocolVersionMatch) {
const { protocol } = protocolVersionMatch;
parsedUrl.hash = '';
protocolVersion = Number.parseInt(protocol, 10);
} else if (parsedUrl.pathname.endsWith('.json')) {
protocolVersion = 3;
}

const feedUrl = parsedUrl.href;
return { feedUrl, protocolVersion };
}
11 changes: 6 additions & 5 deletions lib/datasource/nuget/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import * as httpMock from '../../../test/http-mock';
import { loadFixture } from '../../../test/util';
import * as _hostRules from '../../util/host-rules';
import { id as versioning } from '../../versioning/nuget';
import { id as datasource, parseRegistryUrl } from '.';
import { parseRegistryUrl } from './common';
import { NugetDatasource } from '.';

const datasource = NugetDatasource.id;

const hostRules: any = _hostRules;

Expand Down Expand Up @@ -118,11 +121,9 @@ describe('datasource/nuget/index', () => {
});

it('returns null for unparseable', () => {
const parsed = parseRegistryUrl(
'https://test:malfor%5Med@test.example.com'
);
const parsed = parseRegistryUrl('https://test.example.com:abc');

expect(parsed.feedUrl).toBe('https://test:malfor%5Med@test.example.com');
expect(parsed.feedUrl).toBe('https://test.example.com:abc');
expect(parsed.protocolVersion).toBeNull();
});
});
Expand Down
70 changes: 29 additions & 41 deletions lib/datasource/nuget/index.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,42 @@
import urlApi from 'url';
import { logger } from '../../logger';
import { regEx } from '../../util/regex';
import * as nugetVersioning from '../../versioning/nuget';
import { Datasource } from '../datasource';
import type { GetReleasesConfig, ReleaseResult } from '../types';
import { parseRegistryUrl } from './common';
import * as v2 from './v2';
import * as v3 from './v3';

export { id } from './common';
// 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 customRegistrySupport = true;
export const defaultRegistryUrls = [v3.getDefaultFeed()];
export const defaultVersioning = nugetVersioning.id;
export const registryStrategy = 'merge';
export class NugetDatasource extends Datasource {
static readonly id = 'nuget';

export function parseRegistryUrl(registryUrl: string): {
feedUrl: string;
protocolVersion: number;
} {
try {
const parsedUrl = urlApi.parse(registryUrl);
let protocolVersion = 2;
const protocolVersionRegExp = regEx(/#protocolVersion=(2|3)/);
const protocolVersionMatch = protocolVersionRegExp.exec(parsedUrl.hash);
if (protocolVersionMatch) {
parsedUrl.hash = '';
protocolVersion = Number.parseInt(protocolVersionMatch[1], 10);
} else if (parsedUrl.pathname.endsWith('.json')) {
protocolVersion = 3;
}
return { feedUrl: urlApi.format(parsedUrl), protocolVersion };
} catch (err) {
logger.debug({ err }, `nuget registry failure: can't parse ${registryUrl}`);
return { feedUrl: registryUrl, protocolVersion: null };
}
}
override readonly defaultRegistryUrls = defaultRegistryUrls;

override readonly defaultVersioning = nugetVersioning.id;

export async function getReleases({
lookupName,
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult> {
logger.trace(`nuget.getReleases(${lookupName})`);
const { feedUrl, protocolVersion } = parseRegistryUrl(registryUrl);
if (protocolVersion === 2) {
return v2.getReleases(feedUrl, lookupName);
override readonly registryStrategy = 'merge';

constructor() {
super(NugetDatasource.id);
}
if (protocolVersion === 3) {
const queryUrl = await v3.getResourceUrl(feedUrl);
if (queryUrl) {
return v3.getReleases(feedUrl, queryUrl, lookupName);

async getReleases({
lookupName,
registryUrl,
}: GetReleasesConfig): Promise<ReleaseResult> {
logger.trace(`nuget.getReleases(${lookupName})`);
const { feedUrl, protocolVersion } = parseRegistryUrl(registryUrl);
if (protocolVersion === 2) {
return v2.getReleases(this.http, feedUrl, lookupName);
}
if (protocolVersion === 3) {
const queryUrl = await v3.getResourceUrl(this.http, feedUrl);
if (queryUrl) {
return v3.getReleases(this.http, feedUrl, queryUrl, lookupName);
}
}
return null;
}
return null;
}
5 changes: 5 additions & 0 deletions lib/datasource/nuget/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,8 @@ export interface CatalogPage {
export interface PackageRegistration {
items: CatalogPage[];
}

export interface ParsedRegistryUrl {
feedUrl: string;
protocolVersion: number | null;
}
7 changes: 3 additions & 4 deletions lib/datasource/nuget/v2.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import { XmlDocument, XmlElement } from 'xmldoc';
import { logger } from '../../logger';
import { Http } from '../../util/http';
import type { Http } from '../../util/http';
import { regEx } from '../../util/regex';
import type { ReleaseResult } from '../types';
import { id, removeBuildMeta } from './common';

const http = new Http(id);
import { removeBuildMeta } from './common';

function getPkgProp(pkgInfo: XmlElement, propName: string): string {
return pkgInfo.childNamed('m:properties').childNamed(`d:${propName}`)?.val;
}

export async function getReleases(
http: Http,
feedUrl: string,
pkgName: string
): Promise<ReleaseResult | null> {
Expand Down
18 changes: 7 additions & 11 deletions lib/datasource/nuget/v3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,23 @@ import { XmlDocument } from 'xmldoc';
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/errors/external-host-error';
import * as packageCache from '../../util/cache/package';
import { Http } from '../../util/http';
import type { Http } from '../../util/http';
import { HttpError } from '../../util/http/types';
import { regEx } from '../../util/regex';
import { ensureTrailingSlash } from '../../util/url';
import type { Release, ReleaseResult } from '../types';
import { id, removeBuildMeta } from './common';
import { removeBuildMeta } from './common';
import type {
CatalogEntry,
CatalogPage,
PackageRegistration,
ServicesIndexRaw,
} from './types';

const http = new Http(id);

// https://api.nuget.org/v3/index.json is a default official nuget feed
const defaultNugetFeed = 'https://api.nuget.org/v3/index.json';
const cacheNamespace = 'datasource-nuget';

export function getDefaultFeed(): string {
return defaultNugetFeed;
}

export async function getResourceUrl(
http: Http,
url: string,
resourceType = 'RegistrationsBaseUrl'
): Promise<string | null> {
Expand Down Expand Up @@ -101,6 +94,7 @@ export async function getResourceUrl(
}

async function getCatalogEntry(
http: Http,
catalogPage: CatalogPage
): Promise<CatalogEntry[]> {
let items = catalogPage.items;
Expand All @@ -113,6 +107,7 @@ async function getCatalogEntry(
}

export async function getReleases(
http: Http,
registryUrl: string,
feedUrl: string,
pkgName: string
Expand All @@ -122,7 +117,7 @@ export async function getReleases(
const packageRegistration = await http.getJson<PackageRegistration>(url);
const catalogPages = packageRegistration.body.items || [];
const catalogPagesQueue = catalogPages.map(
(page) => (): Promise<CatalogEntry[]> => getCatalogEntry(page)
(page) => (): Promise<CatalogEntry[]> => getCatalogEntry(http, page)
);
const catalogEntries = (
await pAll(catalogPagesQueue, { concurrency: 5 })
Expand Down Expand Up @@ -164,6 +159,7 @@ export async function getReleases(

try {
const packageBaseAddress = await getResourceUrl(
http,
registryUrl,
'PackageBaseAddress'
);
Expand Down
10 changes: 7 additions & 3 deletions lib/manager/cake/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import moo from 'moo';
import { ProgrammingLanguage } from '../../constants';
import { id as datasource } from '../../datasource/nuget';
import { NugetDatasource } from '../../datasource/nuget';
import { regEx } from '../../util/regex';
import type { PackageDependency, PackageFile } from '../types';

Expand Down Expand Up @@ -36,7 +36,11 @@ function parseDependencyLine(line: string): PackageDependency | null {
const depName = searchParams.get('package');
const currentValue = searchParams.get('version');

const result: PackageDependency = { datasource, depName, currentValue };
const result: PackageDependency = {
datasource: NugetDatasource.id,
depName,
currentValue,
};

if (!isEmptyHost) {
if (protocol.startsWith('http')) {
Expand Down Expand Up @@ -69,4 +73,4 @@ export function extractPackageFile(content: string): PackageFile {
return { deps };
}

export const supportedDatasources = [datasource];
export const supportedDatasources = [NugetDatasource.id];
5 changes: 3 additions & 2 deletions lib/manager/nuget/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { join } from 'path';
import { quote } from 'shlex';
import { GlobalConfig } from '../../config/global';
import { TEMPORARY_ERROR } from '../../constants/error-messages';
import { id, parseRegistryUrl } from '../../datasource/nuget';
import { NugetDatasource } from '../../datasource/nuget';
import { parseRegistryUrl } from '../../datasource/nuget/common';
import { logger } from '../../logger';
import { exec } from '../../util/exec';
import type { ExecOptions } from '../../util/exec/types';
Expand Down Expand Up @@ -39,7 +40,7 @@ async function addSourceCmds(
const result = [];
for (const registry of registries) {
const { username, password } = hostRules.find({
hostType: id,
hostType: NugetDatasource.id,
url: registry.url,
});
const registryInfo = parseRegistryUrl(registry.url);
Expand Down
6 changes: 3 additions & 3 deletions lib/manager/nuget/extract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { XmlDocument, XmlElement, XmlNode } from 'xmldoc';
import { GlobalConfig } from '../../config/global';
import * as datasourceNuget from '../../datasource/nuget';
import { NugetDatasource } from '../../datasource/nuget';
import { logger } from '../../logger';
import { getSiblingFileName, localPathExists } from '../../util/fs';
import { hasKey } from '../../util/object';
Expand Down Expand Up @@ -54,7 +54,7 @@ function extractDepsFromXml(xmlNode: XmlDocument): PackageDependency[] {
?.groups?.currentValue?.trim();
if (depName && currentValue) {
results.push({
datasource: datasourceNuget.id,
datasource: NugetDatasource.id,
depType: 'nuget',
depName,
currentValue,
Expand Down Expand Up @@ -103,7 +103,7 @@ export async function extractPackageFile(
depType: 'nuget',
depName,
currentValue,
datasource: datasourceNuget.id,
datasource: NugetDatasource.id,
};
if (registryUrls) {
dep.registryUrls = registryUrls;
Expand Down
4 changes: 2 additions & 2 deletions lib/manager/nuget/extract/global-manifest.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as datasourceNuget from '../../../datasource/nuget';
import { NugetDatasource } from '../../../datasource/nuget';
import { logger } from '../../../logger';
import type { PackageDependency, PackageFile } from '../../types';
import type { MsbuildGlobalManifest } from '../types';
Expand Down Expand Up @@ -41,7 +41,7 @@ export function extractMsbuildGlobalManifest(
depType: 'msbuild-sdk',
depName,
currentValue,
datasource: datasourceNuget.id,
datasource: NugetDatasource.id,
};

deps.push(dep);
Expand Down
4 changes: 2 additions & 2 deletions lib/manager/nuget/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ProgrammingLanguage } from '../../constants';
import * as datasourceNuget from '../../datasource/nuget';
import { NugetDatasource } from '../../datasource/nuget';

export { extractPackageFile } from './extract';
export { updateArtifacts } from './artifacts';
Expand All @@ -15,4 +15,4 @@ export const defaultConfig = {
],
};

export const supportedDatasources = [datasourceNuget.id];
export const supportedDatasources = [NugetDatasource.id];
13 changes: 6 additions & 7 deletions lib/manager/nuget/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import cryptoRandomString from 'crypto-random-string';
import findUp from 'find-up';
import upath from 'upath';
import { XmlDocument } from 'xmldoc';
import * as datasourceNuget from '../../datasource/nuget';
import { defaultRegistryUrls } from '../../datasource/nuget';
import { logger } from '../../logger';
import { readFile } from '../../util/fs';
import { regEx } from '../../util/regex';
Expand All @@ -22,13 +22,12 @@ export function getRandomString(): string {
return cryptoRandomString({ length: 16 });
}

const defaultRegistries = defaultRegistryUrls.map(
(registryUrl) => ({ url: registryUrl } as Registry)
);

export function getDefaultRegistries(): Registry[] {
return datasourceNuget.defaultRegistryUrls.map(
(registryUrl) =>
({
url: registryUrl,
} as Registry)
);
return [...defaultRegistries];
}

export async function getConfiguredRegistries(
Expand Down
Loading

0 comments on commit b0ce30b

Please sign in to comment.