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

feat(config): inheritConfig #27864

Merged
merged 43 commits into from
Mar 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
021dd61
refactor: config file parsing
rarkins Mar 12, 2024
3b4b08e
feat(config): support inherited org config
rarkins Mar 12, 2024
f99961c
lint
rarkins Mar 12, 2024
dd3ce72
globalOnly
rarkins Mar 12, 2024
6c74c52
add docs
rarkins Mar 12, 2024
9c37f85
fix 2 TODO
rarkins Mar 12, 2024
472adbb
refactor(config): use enum for config type
rarkins Mar 12, 2024
f7eab71
feat(config): support inherited org config
rarkins Mar 12, 2024
9fbb321
lint
rarkins Mar 12, 2024
27b7f8e
globalOnly
rarkins Mar 12, 2024
ceb819a
add docs
rarkins Mar 12, 2024
83af479
fix 2 TODO
rarkins Mar 12, 2024
87b5ef6
validation
rarkins Mar 12, 2024
a206f51
Merge branch 'feat/22212-inherited-org-config' of https://github.com/…
rarkins Mar 12, 2024
7ed32f9
drop warn
rarkins Mar 12, 2024
435d015
drop optimize
rarkins Mar 12, 2024
5ab6c35
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 13, 2024
3ad7761
Apply suggestions from code review
rarkins Mar 13, 2024
f961628
Apply suggestions from code review
viceice Mar 15, 2024
f237dbd
Update inherited.ts
rarkins Mar 15, 2024
db399c2
Update inherited.ts
rarkins Mar 15, 2024
f52a563
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 15, 2024
418b690
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 17, 2024
0d52afc
Update lib/config/options/index.ts
rarkins Mar 17, 2024
1ca86ae
fix validation tests
rarkins Mar 17, 2024
75606ae
more testing
rarkins Mar 17, 2024
85d4a86
finish tests
rarkins Mar 17, 2024
b2732f0
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 17, 2024
109ebc1
fix merge error
rarkins Mar 17, 2024
64f1d1f
Update lib/workers/repository/init/inherited.ts
rarkins Mar 18, 2024
4a581ed
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 18, 2024
9a7e73a
refactor
rarkins Mar 18, 2024
299f563
Apply suggestions from code review
rarkins Mar 18, 2024
34f392b
apply suggestion
rarkins Mar 18, 2024
b7d0c2c
Update docs/usage/self-hosted-configuration.md
rarkins Mar 21, 2024
d7fb1e9
Apply suggestions from code review
rarkins Mar 21, 2024
656ebc0
lint-fix
rarkins Mar 22, 2024
d4d09fd
fix global filtering
rarkins Mar 22, 2024
7286b8a
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 22, 2024
05bb31a
fix lint
rarkins Mar 22, 2024
e1c272d
add standalone tests
rarkins Mar 23, 2024
cfbfb72
drop unnecessary clear
rarkins Mar 23, 2024
ea48bd9
Merge branch 'main' into feat/22212-inherited-org-config
rarkins Mar 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 52 additions & 0 deletions docs/usage/self-hosted-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,58 @@ By default, Renovate does not autodiscover repositories that are mirrors.

Change this setting to `true` to include repositories that are mirrors as Renovate targets.

## inheritConfig

When you enable this option, Renovate will look for the `inheritConfigFileName` file in the `inheritConfigRepoName` repository before processing a repository, and read this in as config.

If the repository is in a nested organization or group on a supported platform such as GitLab, such as `topGroup/nestedGroup/projectName` then Renovate will look in `topGroup/nestedGroup/renovate-config`.

If `inheritConfig` is `true` but the inherited config file does _not_ exist then Renovate will proceed without warning.
If the file exists but cannot be parsed, then Renovate will raise a config warning issue and abort the job.

The inherited config may include all valid repository config and these config options:
rarkins marked this conversation as resolved.
Show resolved Hide resolved

- `bbUseDevelopmentBranch`
- `onboarding`
- `onboardingBranch`
- `onboardingCommitMessage`
- `onboardingConfig`
- `onboardingConfigFileName`
- `onboardingNoDeps`
- `onboardingPrTitle`
- `onboardingRebaseCheckbox`
- `requireConfig`

rarkins marked this conversation as resolved.
Show resolved Hide resolved
<!-- prettier-ignore -->
!!! note
The above list is prepared manually and may become out of date.
Consult the self-hosted configuration docs and look for `inheritConfigSupport` values there for the definitive list.

This way organizations can change/control the default behavior, like whether configs are required and how repositories are onboarded.

We disabled `inheritConfig` in the Mend Renovate App to avoid wasting millions of API calls per week.
This is because each `404` response from the GitHub API due to a missing org inherited config counts as a used API call.
We will add a smart/dynamic approach in future, so that we can selectively enable `inheritConfig` per organization.

## inheritConfigFileName

Change this setting if you want Renovate to look for a different file name within the `inheritConfigRepoName` repository.
You may use nested files, for example: `"some-dir/config.json"`.

## inheritConfigRepoName

Change this setting if you want Renovate to look in an alternative repository for the inherited config.
The repository must be on the same platform and endpoint, and Renovate's token must have `read` permissions to the repository.

## inheritConfigStrict

By default Renovate will silently (debug log message only) ignore cases where `inheritConfig=true` but no inherited config is found.
When you set `inheritConfigStrict=true` then Renovate will abort the run and raise a config error if Renovate can't find the inherited config.

<!-- prettier-ignore -->
!!! warning
Only set this config option to `true` if _every_ organization has an inherited config file _and_ you want to make sure Renovate _always_ uses that inherited config.

## logContext

`logContext` is included with each log entry only if `logFormat="json"` - it is not included in the pretty log output.
Expand Down
23 changes: 22 additions & 1 deletion lib/config/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { getConfig } from './defaults';
import { filterConfig, getManagerConfig, mergeChildConfig } from './index';
import {
filterConfig,
getManagerConfig,
mergeChildConfig,
removeGlobalConfig,
} from './index';

jest.mock('../modules/datasource/npm');
jest.mock('../../config.js', () => ({}), { virtual: true });
Expand Down Expand Up @@ -131,4 +136,20 @@ describe('config/index', () => {
expect(config.vulnerabilitySeverity).toBe('CRITICAL');
});
});

describe('removeGlobalConfig()', () => {
it('removes all global config', () => {
const filteredConfig = removeGlobalConfig(defaultConfig, false);
expect(filteredConfig).not.toHaveProperty('onboarding');
expect(filteredConfig).not.toHaveProperty('binarySource');
expect(filteredConfig.prHourlyLimit).toBe(2);
});

it('retains inherited config', () => {
const filteredConfig = removeGlobalConfig(defaultConfig, true);
expect(filteredConfig).toHaveProperty('onboarding');
expect(filteredConfig).not.toHaveProperty('binarySource');
expect(filteredConfig.prHourlyLimit).toBe(2);
});
});
});
17 changes: 17 additions & 0 deletions lib/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ export function getManagerConfig(
return managerConfig;
}

export function removeGlobalConfig(
rarkins marked this conversation as resolved.
Show resolved Hide resolved
config: RenovateConfig,
keepInherited: boolean,
): RenovateConfig {
const outputConfig: RenovateConfig = { ...config };
for (const option of options.getOptions()) {
if (keepInherited && option.inheritConfigSupport) {
continue;
}
if (option.globalOnly) {
delete outputConfig[option.name];
}
}
return outputConfig;
}

export function filterConfig(
inputConfig: AllConfig,
targetStage: RenovateConfigStage,
Expand All @@ -39,6 +55,7 @@ export function filterConfig(
const outputConfig: RenovateConfig = { ...inputConfig };
const stages: (string | undefined)[] = [
'global',
'inherit',
'repository',
'package',
'branch',
Expand Down
41 changes: 41 additions & 0 deletions lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ const options: RenovateOptions[] = [
type: 'string',
default: 'renovate/configure',
globalOnly: true,
inheritConfigSupport: true,
cli: false,
},
{
Expand All @@ -131,6 +132,7 @@ const options: RenovateOptions[] = [
type: 'string',
default: null,
globalOnly: true,
inheritConfigSupport: true,
cli: false,
},
{
Expand All @@ -140,6 +142,7 @@ const options: RenovateOptions[] = [
type: 'string',
default: 'renovate.json',
globalOnly: true,
inheritConfigSupport: true,
cli: false,
},
{
Expand All @@ -148,6 +151,7 @@ const options: RenovateOptions[] = [
type: 'boolean',
default: false,
globalOnly: true,
inheritConfigSupport: true,
},
{
name: 'onboardingPrTitle',
Expand All @@ -156,6 +160,7 @@ const options: RenovateOptions[] = [
type: 'string',
default: 'Configure Renovate',
globalOnly: true,
inheritConfigSupport: true,
cli: false,
},
{
Expand Down Expand Up @@ -507,6 +512,7 @@ const options: RenovateOptions[] = [
stage: 'repository',
type: 'boolean',
globalOnly: true,
inheritConfigSupport: true,
},
{
name: 'onboardingConfig',
Expand All @@ -515,6 +521,7 @@ const options: RenovateOptions[] = [
type: 'object',
default: { $schema: 'https://docs.renovatebot.com/renovate-schema.json' },
globalOnly: true,
inheritConfigSupport: true,
mergeable: true,
},
{
Expand Down Expand Up @@ -583,6 +590,38 @@ const options: RenovateOptions[] = [
default: true,
globalOnly: true,
},
{
name: 'inheritConfig',
description:
'If `true`, Renovate will inherit configuration from the `inheritConfigFileName` file in `inheritConfigRepoName',
type: 'boolean',
default: false,
globalOnly: true,
},
{
name: 'inheritConfigRepoName',
description:
'Renovate will look in this repo for the `inheritConfigFileName`.',
type: 'string',
default: '{{parentOrg}}/renovate-config',
globalOnly: true,
},
{
name: 'inheritConfigFileName',
description:
'Renovate will look for this config file name in the `inheritConfigRepoName`.',
type: 'string',
default: 'org-inherited-config.json',
globalOnly: true,
},
{
name: 'inheritConfigStrict',
description:
'If `true`, any `inheritedConfig` fetch errror will result in an aborted run.',
type: 'boolean',
default: false,
globalOnly: true,
},
{
name: 'requireConfig',
description:
Expand All @@ -592,6 +631,7 @@ const options: RenovateOptions[] = [
default: 'required',
allowedValues: ['required', 'optional', 'ignored'],
globalOnly: true,
inheritConfigSupport: true,
},
{
name: 'optimizeForDisabled',
Expand Down Expand Up @@ -1921,6 +1961,7 @@ const options: RenovateOptions[] = [
default: false,
supportedPlatforms: ['bitbucket'],
globalOnly: true,
inheritConfigSupport: true,
rarkins marked this conversation as resolved.
Show resolved Hide resolved
},
// Automatic merging
{
Expand Down
8 changes: 8 additions & 0 deletions lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { MergeConfidence } from '../util/merge-confidence/types';

export type RenovateConfigStage =
| 'global'
| 'inherit'
| 'repository'
| 'package'
| 'branch'
Expand Down Expand Up @@ -232,6 +233,11 @@ export interface RenovateConfig

hostRules?: HostRule[];

inheritConfig?: boolean;
inheritConfigFileName?: string;
inheritConfigRepoName?: string;
inheritConfigStrict?: boolean;

ignorePresets?: string[];
forkProcessing?: 'auto' | 'enabled' | 'disabled';
isFork?: boolean;
Expand Down Expand Up @@ -394,6 +400,8 @@ export interface RenovateOptionBase {
*/
globalOnly?: boolean;

inheritConfigSupport?: boolean;

allowedValues?: string[];

allowString?: boolean;
Expand Down
39 changes: 35 additions & 4 deletions lib/config/validation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,30 @@ describe('config/validation', () => {
expect(warnings).toHaveLength(2);
expect(warnings).toMatchObject([
{
message: `The "binarySource" option is a global option reserved only for Renovate's global configuration and cannot be configured within repository config file.`,
message: `The "binarySource" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
{
message: `The "username" option is a global option reserved only for Renovate's global configuration and cannot be configured within repository config file.`,
message: `The "username" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
]);
});

it('catches global options in inherit config', async () => {
const config = {
binarySource: 'something',
username: 'user',
};
const { warnings } = await configValidation.validateConfig(
'inherit',
config,
);
expect(warnings).toHaveLength(2);
expect(warnings).toMatchObject([
{
message: `The "binarySource" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
{
message: `The "username" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
]);
});
Expand All @@ -70,6 +90,17 @@ describe('config/validation', () => {
expect(warnings).toHaveLength(0);
});

it('does not warn for valid inheritConfig', async () => {
const config = {
onboarding: false,
};
const { warnings } = await configValidation.validateConfig(
'inherit',
config,
);
expect(warnings).toHaveLength(0);
});

it('catches invalid templates', async () => {
const config = {
commitMessage: '{{{something}}',
Expand Down Expand Up @@ -1020,7 +1051,7 @@ describe('config/validation', () => {
expect(warnings).toMatchObject([
{
topic: 'Configuration Error',
message: `The "customEnvVariables" option is a global option reserved only for Renovate's global configuration and cannot be configured within repository config file.`,
message: `The "customEnvVariables" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
]);
});
Expand Down Expand Up @@ -1426,7 +1457,7 @@ describe('config/validation', () => {
},
{
topic: 'Configuration Error',
message: `The "binarySource" option is a global option reserved only for Renovate's global configuration and cannot be configured within repository config file.`,
message: `The "binarySource" option is a global option reserved only for Renovate's global configuration and cannot be configured within a repository's config file.`,
},
]);
});
Expand Down