diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index b1147e32aae310d6a8f6394cebdd61226099a143..e6ff1a0c970e47c66a1d475efe411d9fef9b02ca 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -585,14 +585,26 @@ Similarly to `onboardingBranch`, if you have an existing Renovate installation a When this option is `true`, Renovate will do the following during repository initialization: -- Try to fetch the default config file (`renovate.json`) +- Try to fetch the default config file (e.g. `renovate.json`) - Check if the file contains `"enabled": false` +- If so, skip cloning and skip the repository immediately + +If `onboardingConfigFileName` is set, that file name will be used instead of the default. If the file exists and the config is disabled, Renovate will skip the repo without cloning it. Otherwise, it will continue as normal. -This option is only useful where the ratio of disabled repos is quite high. -You spend one extra API call per repo, but skip cloning disabled repositories. +It can speed up initialization significantly in cases where most repositories are disabled, at the cost of an extra API call for enabled repositories. + +A second, advanced, use also exists when the bot global config contains `extends: [":disableRenovate"]`. +In that case, Renovate will check for a repo config file containing one of the following: + +- `extends: [":enableRenovate"]` +- `ignorePresets: [":disableRenovate"]` +- `enabled: true` + +If any of those three are found, then the repo initialization will continue. +If not, then Renoate will skip the repository without cloning it. ## password diff --git a/lib/workers/repository/init/apis.spec.ts b/lib/workers/repository/init/apis.spec.ts index 07df2ace20fc8553460f6708c4d139d30312dd17..8295f41bd42f9875c208a987839c7afdf97c8e0a 100644 --- a/lib/workers/repository/init/apis.spec.ts +++ b/lib/workers/repository/init/apis.spec.ts @@ -154,5 +154,39 @@ describe('workers/repository/init/apis', () => { expect(workerPlatformConfig.onboardingConfigFileName).toBe('foo.bar'); expect(platform.getJsonFile).toHaveBeenCalledWith('renovate.json'); }); + + it('checks for re-enablement and continues', async () => { + platform.initRepo.mockResolvedValueOnce({ + defaultBranch: 'master', + isFork: false, + repoFingerprint: '123', + }); + platform.getJsonFile.mockResolvedValueOnce({ + enabled: true, + }); + const workerPlatformConfig = await initApis({ + ...config, + optimizeForDisabled: true, + extends: [':disableRenovate'], + }); + expect(workerPlatformConfig).toBeTruthy(); + expect(platform.getJsonFile).toHaveBeenCalledWith('renovate.json'); + }); + + it('checks for re-enablement and skips', async () => { + platform.initRepo.mockResolvedValueOnce({ + defaultBranch: 'master', + isFork: false, + repoFingerprint: '123', + }); + platform.getJsonFile.mockResolvedValueOnce(null); + await expect( + initApis({ + ...config, + optimizeForDisabled: true, + extends: [':disableRenovate'], + }) + ).rejects.toThrow(REPOSITORY_DISABLED); + }); }); }); diff --git a/lib/workers/repository/init/apis.ts b/lib/workers/repository/init/apis.ts index 823f2fdf0fe9551b85ad0e1dc3c5690871d2f2ab..554e4829dea6d253ef5fdb416bb0c0c8d90c7500 100644 --- a/lib/workers/repository/init/apis.ts +++ b/lib/workers/repository/init/apis.ts @@ -34,6 +34,29 @@ async function validateOptimizeForDisabled( if (renovateConfig?.enabled === false) { throw new Error(REPOSITORY_DISABLED_BY_CONFIG); } + /* + * The following is to support a use case within Mend customers where: + * - Bot admins configure install the bot into every repo + * - Bot admins configure `extends: [':disableRenovate'] in order to skip repos by default + * - Repo users can push a `renovate.json` containing `extends: [':enableRenovate']` to re-enable Renovate + */ + if (config.extends?.includes(':disableRenovate')) { + logger.debug( + 'Global config disables Renovate - checking renovate.json to see if it is re-enabled' + ); + if ( + renovateConfig?.extends?.includes(':enableRenovate') ?? + renovateConfig?.ignorePresets?.includes(':disableRenovate') ?? + renovateConfig?.enabled + ) { + logger.debug('Repository config re-enables Renovate - continuing'); + } else { + logger.debug( + 'Repository config does not re-enable Renovate - skipping' + ); + throw new Error(REPOSITORY_DISABLED_BY_CONFIG); + } + } } }