Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(config/inherit): resolve presets #31642

Merged
merged 19 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
6 changes: 6 additions & 0 deletions docs/usage/config-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ Inherited config may use all Repository config settings, and any Global config o

For information on how the Mend Renovate App supports Inherited config, see the dedicated "Mend Renovate App Config" section toward the end of this page.

#### Presets handling

If presets are present in the inherited config, they will be resolved and added to the inherited config prior to being merged on top of global config.
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved

Using `ignorePresets` in your repository config to ignore certain presets will not affect presets present in the inherited config, as inherited config is resolved before repository config.
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved

### Repository config

Repository config is the config loaded from a config file in the repository.
Expand Down
83 changes: 83 additions & 0 deletions lib/workers/repository/init/inherited.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { platform } from '../../../../test/util';
import type { RenovateConfig } from '../../../config/types';
import * as validation from '../../../config/validation';
import {
CONFIG_INHERIT_NOT_FOUND,
CONFIG_INHERIT_PARSE_ERROR,
Expand Down Expand Up @@ -84,4 +85,86 @@ describe('workers/repository/init/inherited', () => {
expect(res.onboarding).toBeFalse();
expect(logger.warn).not.toHaveBeenCalled();
});

it('should resolve presets found in inherited config', async () => {
platform.getRawFile.mockResolvedValue(
'{"onboarding":false,"labels":["test"],"extends":[":automergeAll"]}',
);
const res = await mergeInheritedConfig(config);
expect(res.labels).toEqual(['test']);
expect(res.onboarding).toBeFalse();
expect(logger.warn).not.toHaveBeenCalled();
expect(logger.debug).toHaveBeenCalledWith(
'Resolving presets found in inherited config',
);
});

it('should warn if presets fails validation with warnings', async () => {
platform.getRawFile.mockResolvedValue(
'{"onboarding":false,"labels":["test"],"extends":[":automergeAll"]}',
);
jest
.spyOn(validation, 'validateConfig')
.mockResolvedValueOnce({
warnings: [],
errors: [],
})
.mockResolvedValueOnce({
warnings: [
{
message: 'some warning',
topic: 'Configuration Error',
},
],
errors: [],
});
const res = await mergeInheritedConfig(config);
expect(res.binarySource).toBeUndefined();
expect(logger.warn).toHaveBeenCalledWith(
{
warnings: [
{
message: 'some warning',
topic: 'Configuration Error',
},
],
},
'Found warnings in presets inside the inherited configuration.',
);
});

it('should throw error if presets fails validation with errors', async () => {
platform.getRawFile.mockResolvedValue(
'{"labels":["test"],"extends":[":automergeAll"]}',
);
jest
.spyOn(validation, 'validateConfig')
.mockResolvedValueOnce({
warnings: [],
errors: [],
})
.mockResolvedValueOnce({
warnings: [],
errors: [
{
message: 'some error',
topic: 'Configuration Error',
},
],
});
await expect(mergeInheritedConfig(config)).rejects.toThrow(
CONFIG_VALIDATION,
);
expect(logger.warn).toHaveBeenCalledWith(
{
errors: [
{
message: 'some error',
topic: 'Configuration Error',
},
],
},
'Found errors in presets inside the inherited configuration.',
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
);
});
});
36 changes: 34 additions & 2 deletions lib/workers/repository/init/inherited.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import is from '@sindresorhus/is';
import { dequal } from 'dequal';
import { mergeChildConfig, removeGlobalConfig } from '../../../config';
import { decryptConfig } from '../../../config/decrypt';
import { parseFileConfig } from '../../../config/parse';
import { resolveConfigPresets } from '../../../config/presets';
import type { RenovateConfig } from '../../../config/types';
import { validateConfig } from '../../../config/validation';
import {
Expand Down Expand Up @@ -78,7 +80,7 @@ export async function mergeInheritedConfig(
}
const inheritedConfig = parseResult.parsedContents as RenovateConfig;
logger.debug({ config: inheritedConfig }, `Inherited config`);
const res = await validateConfig('inherit', inheritedConfig);
let res = await validateConfig('inherit', inheritedConfig);
if (res.errors.length) {
logger.warn(
{ errors: res.errors },
Expand All @@ -99,5 +101,35 @@ export async function mergeInheritedConfig(
'Removed global config from inherited config.',
);
}
return mergeChildConfig(config, filteredConfig);

const decryptedConfig = await decryptConfig(
filteredConfig,
config.repository,
);
let returnConfig = decryptedConfig;
if (is.nonEmptyArray(returnConfig.extends)) {
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
// Decrypt after resolving in case the preset contains npm authentication instead
logger.debug('Resolving presets found in inherited config');
returnConfig = await decryptConfig(
await resolveConfigPresets(returnConfig, config, config.ignorePresets),
config.repository,
);
logger.trace({ config: returnConfig }, 'Resolved inherited config');
res = await validateConfig('inherit', returnConfig);
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
if (res.errors.length) {
logger.warn(
{ errors: res.errors },
'Found errors in presets inside the inherited configuration.',
);
throw new Error(CONFIG_VALIDATION);
}
if (res.warnings.length) {
logger.warn(
{ warnings: res.warnings },
'Found warnings in presets inside the inherited configuration.',
);
}
}

return mergeChildConfig(config, returnConfig);
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
}