Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -3011,6 +3011,11 @@ This field behaves the same as `matchPackageNames` except it matches against `de
### matchDepTypes

Use this field if you want to limit a `packageRule` to certain `depType` values.
This matching can be an exact match, Glob match, or Regular Expression match.

For more details on supported syntax see Renovate's [string pattern matching documentation](./string-pattern-matching.md).
Note that Glob matching (including exact name matching) is case-insensitive.

Invalid if used outside of a `packageRule`.

### matchFileNames
Expand Down
2 changes: 1 addition & 1 deletion lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ const options: RenovateOptions[] = [
description:
'Change this value to override the default Renovate sidecar image.',
type: 'string',
default: 'ghcr.io/containerbase/sidecar:13.8.18',
default: 'ghcr.io/containerbase/sidecar:13.8.19',
globalOnly: true,
},
{
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/manager/gomod/artifacts-extra.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { diffLines } from 'diff';
import markdownTable from 'markdown-table';
import { markdownTable } from 'markdown-table';
import { parseLine } from './line-parser';
import type { ExtraDep } from './types';

Expand Down
50 changes: 50 additions & 0 deletions lib/workers/global/config/parse/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import upath from 'upath';
import * as _decrypt from '../../../../config/decrypt';
import { CONFIG_PRESETS_INVALID } from '../../../../constants/error-messages';
import { getCustomEnv } from '../../../../util/env';
import { getParentDir, readSystemFile } from '../../../../util/fs';
import getArgv from './__fixtures__/argv';
import * as _hostRulesFromEnv from './host-rules-from-env';
import * as httpMock from '~test/http-mock';

vi.mock('../../../../modules/datasource/npm');
vi.mock('../../../../util/fs');
Expand Down Expand Up @@ -170,6 +172,54 @@ describe('workers/global/config/parse/index', () => {
expect(parsed).toContainEntries([['dryRun', 'full']]);
});

it('resolves global presets', async () => {
// The remote preset defined in globalExtends of the config file
httpMock
.scope('http://example.com/')
.get('/config.json')
.reply(200, { repositories: ['g/r1', 'g/r2'], druRun: 'full' });

// Mock the default config file to return a preset
const defaultConfig = upath.join(__dirname, '__fixtures__/default.js');
vi.doMock(defaultConfig, () => ({
default: {
globalExtends: ['http://example.com/config.json', ':pinVersions'],
dryRun: 'extract',
},
}));

const parsedConfig = await configParser.parseConfigs(
defaultEnv,
defaultArgv,
);
vi.doUnmock(defaultConfig);

// Remote preset in globalExtends should be resolved
expect(parsedConfig).toContainEntries([
['repositories', ['g/r1', 'g/r2']],
]);
// :pinVersion in globalExtends should be resolved
expect(parsedConfig).toContainEntries([['rangeStrategy', 'pin']]);
// `globalExtends` should be an empty array after merging
expect(parsedConfig).toContainEntries([['globalExtends', []]]);
// `dryRun` from globalExtends should be overwritten with value defined in config file
expect(parsedConfig).toContainEntries([['dryRun', 'extract']]);
});

it('throws exception if global presets cannot be resolved', async () => {
httpMock
.scope('http://example.com/')
.get('/config.json')
.reply(404, 'Not Found');

await expect(
configParser.resolveGlobalExtends([
'http://example.com/config.json',
':pinVersions',
]),
).rejects.toThrow(CONFIG_PRESETS_INVALID);
});

it('cli dryRun replaced to full', async () => {
defaultArgv = defaultArgv.concat(['--dry-run']);
const parsed = await configParser.parseConfigs(defaultEnv, defaultArgv);
Expand Down
30 changes: 30 additions & 0 deletions lib/workers/global/config/parse/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import is from '@sindresorhus/is';
import { setPrivateKeys } from '../../../../config/decrypt';
import * as defaultsParser from '../../../../config/defaults';
import { resolveConfigPresets } from '../../../../config/presets';
import { applySecretsToConfig } from '../../../../config/secrets';
import type { AllConfig } from '../../../../config/types';
import { mergeChildConfig } from '../../../../config/utils';
import { CONFIG_PRESETS_INVALID } from '../../../../constants/error-messages';
import { logger, setContext } from '../../../../logger';
import { detectAllGlobalConfig } from '../../../../modules/manager';
import { coerceArray } from '../../../../util/array';
Expand All @@ -17,6 +19,21 @@ import * as envParser from './env';
import * as fileParser from './file';
import { hostRulesFromEnv } from './host-rules-from-env';

export async function resolveGlobalExtends(
globalExtends: string[],
ignorePresets?: string[],
): Promise<AllConfig> {
try {
// Make a "fake" config to pass to resolveConfigPresets and resolve globalPresets
const config = { extends: globalExtends, ignorePresets };
const resolvedConfig = await resolveConfigPresets(config);
return resolvedConfig;
} catch (err) {
logger.error({ err }, 'Error resolving config preset');
throw new Error(CONFIG_PRESETS_INVALID);
}
}

export async function parseConfigs(
env: NodeJS.ProcessEnv,
argv: string[],
Expand All @@ -34,6 +51,18 @@ export async function parseConfigs(

config = await codespaces.setConfig(config);

let resolvedGlobalExtends: AllConfig | undefined;

if (is.nonEmptyArray(config?.globalExtends)) {
// resolve global presets immediately
resolvedGlobalExtends = await resolveGlobalExtends(
config.globalExtends,
config.ignorePresets,
);
config = mergeChildConfig(resolvedGlobalExtends, config);
delete config.globalExtends;
}

const combinedConfig = config;

config = mergeChildConfig(defaultConfig, config);
Expand Down Expand Up @@ -78,6 +107,7 @@ export async function parseConfigs(
logger.debug({ config: fileConfig }, 'File config');
logger.debug({ config: cliConfig }, 'CLI config');
logger.debug({ config: envConfig }, 'Env config');
logger.debug({ config: resolvedGlobalExtends }, 'Resolved global extends');
logger.debug({ config: combinedConfig }, 'Combined config');

if (config.detectGlobalManagerConfig) {
Expand Down
31 changes: 0 additions & 31 deletions lib/workers/global/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { ERROR, WARN } from 'bunyan';
import fs from 'fs-extra';
import { GlobalConfig } from '../../config/global';
import * as _presets from '../../config/presets';
import { CONFIG_PRESETS_INVALID } from '../../constants/error-messages';
import { DockerDatasource } from '../../modules/datasource/docker';
import * as platform from '../../modules/platform';
import * as secrets from '../../util/sanitize';
Expand All @@ -15,7 +13,6 @@ import type { RenovateConfig } from '~test/util';

vi.mock('../repository');
vi.mock('../../util/fs');
vi.mock('../../config/presets');

vi.mock('fs-extra', async () => {
const realFs = await vi.importActual<typeof fs>('fs-extra');
Expand All @@ -38,9 +35,6 @@ vi.mock('fs-extra', async () => {
// TODO: why do we need git here?
vi.unmock('../../util/git');

// imports are readonly
const presets = vi.mocked(_presets);

const addSecretForSanitizing = vi.spyOn(secrets, 'addSecretForSanitizing');
const parseConfigs = vi.spyOn(configParser, 'parseConfigs');
const initPlatform = vi.spyOn(platform, 'initPlatform');
Expand Down Expand Up @@ -94,31 +88,6 @@ describe('workers/global/index', () => {
expect(addSecretForSanitizing).toHaveBeenCalledTimes(2);
});

it('resolves global presets immediately', async () => {
parseConfigs.mockResolvedValueOnce({
repositories: [],
globalExtends: [':pinVersions'],
hostRules: [{ matchHost: 'github.com', token: 'abc123' }],
});
presets.resolveConfigPresets.mockResolvedValueOnce({});
await expect(globalWorker.start()).resolves.toBe(0);
expect(presets.resolveConfigPresets).toHaveBeenCalledWith({
extends: [':pinVersions'],
});
expect(parseConfigs).toHaveBeenCalledTimes(1);
});

it('throws if global presets could not be resolved', async () => {
presets.resolveConfigPresets.mockImplementationOnce(() => {
throw new Error('some-error');
});
await expect(
globalWorker.resolveGlobalExtends(['some-preset']),
).rejects.toThrow(CONFIG_PRESETS_INVALID);
expect(presets.resolveConfigPresets).toHaveBeenCalled();
expect(parseConfigs).not.toHaveBeenCalled();
});

it('handles zero repos', async () => {
parseConfigs.mockResolvedValueOnce({
baseDir: '/tmp/base',
Expand Down
26 changes: 0 additions & 26 deletions lib/workers/global/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import fs from 'fs-extra';
import semver from 'semver';
import upath from 'upath';
import * as configParser from '../../config';
import { mergeChildConfig } from '../../config';
import { GlobalConfig } from '../../config/global';
import { resolveConfigPresets } from '../../config/presets';
import { validateConfigSecrets } from '../../config/secrets';
Expand Down Expand Up @@ -94,21 +93,6 @@ export async function validatePresets(config: AllConfig): Promise<void> {
}
}

export async function resolveGlobalExtends(
globalExtends: string[],
ignorePresets?: string[],
): Promise<AllConfig> {
try {
// Make a "fake" config to pass to resolveConfigPresets and resolve globalPresets
const config = { extends: globalExtends, ignorePresets };
const resolvedConfig = await resolveConfigPresets(config);
return resolvedConfig;
} catch (err) {
logger.error({ err }, 'Error resolving config preset');
throw new Error(CONFIG_PRESETS_INVALID);
}
}

export async function start(): Promise<number> {
// istanbul ignore next
if (regexEngineStatus.type === 'available') {
Expand All @@ -134,16 +118,6 @@ export async function start(): Promise<number> {
await instrument('config', async () => {
// read global config from file, env and cli args
config = await getGlobalConfig();
if (is.nonEmptyArray(config?.globalExtends)) {
// resolve global presets immediately
config = mergeChildConfig(
await resolveGlobalExtends(
config.globalExtends,
config.ignorePresets,
),
config,
);
}

// Set allowedHeaders and userAgent in case hostRules headers are configured in file config
GlobalConfig.set({
Expand Down
4 changes: 2 additions & 2 deletions lib/workers/repository/updates/generate.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import is from '@sindresorhus/is';
import { DateTime } from 'luxon';
import mdTable from 'markdown-table';
import { markdownTable } from 'markdown-table';
import semver from 'semver';
import { mergeChildConfig } from '../../../config';
import { CONFIG_SECRETS_EXPOSED } from '../../../constants/error-messages';
Expand Down Expand Up @@ -482,7 +482,7 @@ export function generateBranchConfig(
seenRows.add(key);
table.push(row);
}
config.commitMessage += '\n\n' + mdTable(table) + '\n';
config.commitMessage += '\n\n' + markdownTable(table) + '\n';
}
const additionalReviewers = uniq(
config.upgrades
Expand Down
5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@
"klona": "2.0.6",
"luxon": "3.6.1",
"markdown-it": "14.1.0",
"markdown-table": "2.0.0",
"markdown-table": "3.0.4",
"minimatch": "10.0.1",
"moo": "0.5.2",
"ms": "2.1.3",
Expand Down Expand Up @@ -298,12 +298,11 @@
"@types/lodash": "4.17.16",
"@types/luxon": "3.6.2",
"@types/markdown-it": "14.1.2",
"@types/markdown-table": "2.0.0",
"@types/marshal": "0.5.3",
"@types/mdast": "3.0.15",
"@types/moo": "0.5.10",
"@types/ms": "2.1.0",
"@types/node": "22.15.2",
"@types/node": "22.15.3",
"@types/parse-link-header": "2.0.3",
"@types/punycode": "2.1.4",
"@types/semver": "7.7.0",
Expand Down
Loading
Loading