Skip to content

Commit

Permalink
feat(self-hosted): mergeConfidenceEndpoint and `mergeConfidenceData…
Browse files Browse the repository at this point in the history
…sources` (#28880)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
  • Loading branch information
4 people committed May 21, 2024
1 parent ae15a51 commit 044dc0f
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 93 deletions.
33 changes: 33 additions & 0 deletions docs/usage/self-hosted-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,39 @@ If left as default (null), a random short ID will be selected.

## logFileLevel

## mergeConfidenceDatasources

This feature is applicable only if you have an access token for Mend's Merge Confidence API.

If set, Renovate will query the merge-confidence JSON API only for datasources that are part of this list.
Otherwise, it queries all the supported datasources (check default value).

Example:

```js
modules.exports = {
mergeConfidenceDatasources: ['npm'],
};
```

## mergeConfidenceEndpoint

This feature is applicable only if you have an access token for Mend's Merge Confidence API.

If set, Renovate will retrieve Merge Confidence data by querying this API.
Otherwise, it will use the default URL, which is <https://developer.mend.io/>.

If you use the Mend Renovate Enterprise Edition (Renovate EE) and:

- have a static merge confidence token that you set via `MEND_RNV_MC_TOKEN`
- _or_ set `MEND_RNV_MC_TOKEN` to `auto`

Then you must set this variable at the _server_ and the _workers_.

But if you have specified the token as a [`matchConfidence`](configuration-options.md#matchconfidence) `hostRule`, you only need to set this variable at the _workers_.

This feature is in private beta.

## migratePresets

Use this if you have repositories that extend from a particular preset, which has now been renamed or removed.
Expand Down
20 changes: 0 additions & 20 deletions docs/usage/self-hosted-experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,26 +90,6 @@ Suppress the default warning when a deprecated version of Node.js is used to run

Skip initializing `RE2` for regular expressions and instead use Node-native `RegExp` instead.

## `RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL`

If set, Renovate will query this API for Merge Confidence data.

If you use the Mend Renovate Enterprise Edition (Renovate EE) and:

- have a static merge confidence token that you set via `MEND_RNV_MC_TOKEN`
- _or_ set `MEND_RNV_MC_TOKEN` to `auto`

Then you must set this variable at the _server_ and the _workers_.

But if you have specified the token as a [`matchConfidence`](configuration-options.md#matchconfidence) `hostRule`, you only need to set this variable at the _workers_.

This feature is in private beta.

## `RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES`

If set, Renovate will query the merge-confidence JSON API only for datasources that are part of this list.
The expected value for this environment variable is a JSON array of strings.

## `RENOVATE_X_NUGET_DOWNLOAD_NUPKGS`

If set to any value, Renovate will download `nupkg` files for determining package metadata.
Expand Down
2 changes: 2 additions & 0 deletions lib/config/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export class GlobalConfig {
'httpCacheTtlDays',
'autodiscoverRepoSort',
'autodiscoverRepoOrder',
'mergeConfidenceEndpoint',
'mergeConfidenceDatasources',
'userAgent',
];

Expand Down
20 changes: 20 additions & 0 deletions lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { getManagers } from '../../modules/manager';
import { getCustomManagers } from '../../modules/manager/custom';
import { getPlatformList } from '../../modules/platform';
import { getVersioningList } from '../../modules/versioning';
import { supportedDatasources } from '../presets/internal/merge-confidence';
import type { RenovateOptions } from '../types';

const options: RenovateOptions[] = [
Expand Down Expand Up @@ -68,6 +69,25 @@ const options: RenovateOptions[] = [
default: false,
globalOnly: true,
},
{
name: 'mergeConfidenceEndpoint',
description:
'If set, Renovate will query this API for Merge Confidence data.',
type: 'string',
default: 'https://developer.mend.io/',
advancedUse: true,
globalOnly: true,
},
{
name: 'mergeConfidenceDatasources',
description:
'If set, Renovate will query the merge-confidence JSON API only for datasources that are part of this list.',
allowedValues: supportedDatasources,
default: supportedDatasources,
type: 'array',
subType: 'string',
globalOnly: true,
},
{
name: 'useCloudMetadataServices',
description:
Expand Down
2 changes: 2 additions & 0 deletions lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ export interface RepoGlobalConfig {
githubTokenWarn?: boolean;
includeMirrors?: boolean;
localDir?: string;
mergeConfidenceEndpoint?: string;
mergeConfidenceDatasources?: string[];
migratePresets?: Record<string, string>;
platform?: PlatformId;
presetCachePersistence?: boolean;
Expand Down
6 changes: 6 additions & 0 deletions lib/config/validation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1590,6 +1590,7 @@ describe('config/validation', () => {
allowedPostUpgradeCommands: ['cmd'],
checkedBranches: 'invalid-type',
gitNoVerify: ['invalid'],
mergeConfidenceDatasources: [1],
};
const { warnings } = await configValidation.validateConfig(
'global',
Expand All @@ -1602,6 +1603,11 @@ describe('config/validation', () => {
'Configuration option `checkedBranches` should be a list (Array).',
topic: 'Configuration Error',
},
{
topic: 'Configuration Error',
message:
'Invalid value `1` for `mergeConfidenceDatasources`. The allowed values are go, maven, npm, nuget, packagist, pypi, rubygems.',
},
{
message:
'Invalid value for `gitNoVerify`. The allowed values are commit, push.',
Expand Down
12 changes: 12 additions & 0 deletions lib/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { GlobalConfig } from './global';
import { migrateConfig } from './migration';
import { getOptions } from './options';
import { resolveConfigPresets } from './presets';
import { supportedDatasources } from './presets/internal/merge-confidence';
import {
AllowedParents,
type RenovateConfig,
Expand Down Expand Up @@ -1006,6 +1007,17 @@ async function validateGlobalConfig(
}
}
}
if (key === 'mergeConfidenceDatasources') {
const allowedValues = supportedDatasources;
for (const value of val as string[]) {
if (!allowedValues.includes(value)) {
warnings.push({
topic: 'Configuration Error',
message: `Invalid value \`${value}\` for \`${currentPath}\`. The allowed values are ${allowedValues.join(', ')}.`,
});
}
}
}
} else {
warnings.push({
topic: 'Configuration Error',
Expand Down
70 changes: 32 additions & 38 deletions lib/util/merge-confidence/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as httpMock from '../../../test/http-mock';
import { GlobalConfig } from '../../config/global';
import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
import { logger } from '../../logger';
import type { HostRule } from '../../types';
Expand All @@ -17,6 +18,15 @@ import {
describe('util/merge-confidence/index', () => {
const apiBaseUrl = 'https://www.baseurl.com/';
const defaultApiBaseUrl = 'https://developer.mend.io/';
const supportedDatasources = [
'go',
'maven',
'npm',
'nuget',
'packagist',
'pypi',
'rubygems',
];

describe('isActiveConfidenceLevel()', () => {
it('returns false if null', () => {
Expand Down Expand Up @@ -57,10 +67,10 @@ describe('util/merge-confidence/index', () => {
};

beforeEach(() => {
process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL = apiBaseUrl;
hostRules.add(hostRule);
initConfig();
memCache.reset();
GlobalConfig.set({ mergeConfidenceEndpoint: apiBaseUrl });
});

afterEach(() => {
Expand Down Expand Up @@ -302,16 +312,13 @@ describe('util/merge-confidence/index', () => {
});

it('using default base url if none is set', async () => {
delete process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL;
GlobalConfig.reset();
httpMock
.scope(defaultApiBaseUrl)
.get(`/api/mc/availability`)
.reply(200);

await expect(initMergeConfidence()).toResolve();
expect(logger.trace).toHaveBeenCalledWith(
'using default merge confidence API base URL',
);
expect(logger.debug).toHaveBeenCalledWith(
{
supportedDatasources: [
Expand All @@ -329,8 +336,7 @@ describe('util/merge-confidence/index', () => {
});

it('warns and then resolves if base url is invalid', async () => {
process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL =
'invalid-url.com';
GlobalConfig.set({ mergeConfidenceEndpoint: 'invalid-url.com' });
httpMock
.scope(defaultApiBaseUrl)
.get(`/api/mc/availability`)
Expand All @@ -349,7 +355,7 @@ describe('util/merge-confidence/index', () => {

it('uses a custom base url containing path', async () => {
const renovateApi = 'https://domain.com/proxy/renovate-api';
process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL = renovateApi;
GlobalConfig.set({ mergeConfidenceEndpoint: renovateApi });
httpMock.scope(renovateApi).get(`/api/mc/availability`).reply(200);

await expect(initMergeConfidence()).toResolve();
Expand Down Expand Up @@ -423,54 +429,42 @@ describe('util/merge-confidence/index', () => {
});

describe('parseSupportedDatasourceList()', () => {
type ParseSupportedDatasourceTestCase = {
name: string;
datasourceListString: string | undefined;
expected: string[] | undefined;
};

afterEach(() => {
delete process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES;
GlobalConfig.reset();
});

it.each([
{
name: 'it should do nothing when the input is undefined',
datasourceListString: undefined,
expected: undefined,
name: 'it should do return default value when the input is undefined',
datasources: undefined,
expected: supportedDatasources,
},
{
name: 'it should successfully parse the given datasource list',
datasourceListString: `["go","npm"]`,
datasources: ['go', 'npm'],
expected: ['go', 'npm'],
},
{
name: 'it should gracefully handle invalid json',
datasourceListString: `{`,
expected: undefined,
name: 'it should gracefully handle invalid JSON',
datasources: `{`,
expected: supportedDatasources,
},
{
name: 'it should discard non-array JSON input',
datasourceListString: `{}`,
expected: undefined,
datasources: `{}`,
expected: supportedDatasources,
},
{
name: 'it should discard non-string array JSON input',
datasourceListString: `[1,2]`,
expected: undefined,
datasources: `[1,2]`,
expected: supportedDatasources,
},
])(
`$name`,
({
datasourceListString,
expected,
}: ParseSupportedDatasourceTestCase) => {
process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES =
datasourceListString;

expect(parseSupportedDatasourceString()).toStrictEqual(expected);
},
);
])(`$name`, ({ datasources, expected }) => {
GlobalConfig.set({
mergeConfidenceDatasources: datasources,
});
expect(parseSupportedDatasourceString()).toStrictEqual(expected);
});
});
});
});
Expand Down
47 changes: 16 additions & 31 deletions lib/util/merge-confidence/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import is from '@sindresorhus/is';
import { GlobalConfig } from '../../config/global';
import { supportedDatasources as presetSupportedDatasources } from '../../config/presets/internal/merge-confidence';
import type { UpdateType } from '../../config/types';
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/errors/external-host-error';
import * as packageCache from '../cache/package';
import { parseJson } from '../common';
import * as hostRules from '../host-rules';
import { Http } from '../http';
import { regEx } from '../regex';
Expand All @@ -28,41 +28,28 @@ export const confidenceLevels: Record<MergeConfidence, number> = {
export function initConfig(): void {
apiBaseUrl = getApiBaseUrl();
token = getApiToken();
supportedDatasources =
parseSupportedDatasourceString() ?? presetSupportedDatasources;
supportedDatasources = parseSupportedDatasourceString();

if (!is.nullOrUndefined(token)) {
logger.debug(`Merge confidence token found for ${apiBaseUrl}`);
}
}

export function parseSupportedDatasourceString(): string[] | undefined {
const supportedDatasourceString =
process.env.RENOVATE_X_MERGE_CONFIDENCE_SUPPORTED_DATASOURCES;

if (!is.string(supportedDatasourceString)) {
return undefined;
}

let parsedDatasourceList: unknown;
try {
parsedDatasourceList = parseJson(supportedDatasourceString, '.json5');
} catch (err) {
logger.error(
{ supportedDatasourceString, err },
'Failed to parse supported datasources list; Invalid JSON format',
);
}
export function parseSupportedDatasourceString(): string[] {
const supportedDatasources = GlobalConfig.get(
'mergeConfidenceDatasources',
presetSupportedDatasources,
);

if (!is.array<string>(parsedDatasourceList, is.string)) {
if (!is.array(supportedDatasources, is.string)) {
logger.warn(
{ parsedDatasourceList },
`Expected a string array but got ${typeof parsedDatasourceList}`,
{ supportedDatasources },
`Expected a string array but got ${typeof supportedDatasources} - using default value instead`,
);
return undefined;
return presetSupportedDatasources;
}

return parsedDatasourceList;
return supportedDatasources;
}

export function resetConfig(): void {
Expand Down Expand Up @@ -242,12 +229,10 @@ export async function initMergeConfidence(): Promise<void> {

function getApiBaseUrl(): string {
const defaultBaseUrl = 'https://developer.mend.io/';
const baseFromEnv = process.env.RENOVATE_X_MERGE_CONFIDENCE_API_BASE_URL;

if (is.nullOrUndefined(baseFromEnv)) {
logger.trace('using default merge confidence API base URL');
return defaultBaseUrl;
}
const baseFromEnv = GlobalConfig.get(
'mergeConfidenceEndpoint',
defaultBaseUrl,
);

try {
const parsedBaseUrl = new URL(baseFromEnv).toString();
Expand Down

0 comments on commit 044dc0f

Please sign in to comment.