Skip to content

Commit

Permalink
feat(config)!: forkProcessing (#20759)
Browse files Browse the repository at this point in the history
Removes "includeForks" option and replaces with "forkProcessing". New default behavior is to process forks if automerge=false.

Closes #20752

BREAKING CHANGE: Forked repos will now be processed automatically if autodiscover=false. includeForks is removed and replaced by new option forkProcessing.
  • Loading branch information
rarkins committed Mar 10, 2023
1 parent d53d39b commit a4ab452
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 41 deletions.
2 changes: 1 addition & 1 deletion docs/development/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ e.g. apply one set of labels for `backend/package.json` and a different set of l
module.exports = {
npmrc: '//registry.npmjs.org/:_authToken=abc123',
baseDir: '/tmp/renovate',
includeForks: true,
forkProcessing: 'enabled',
gradle: { enabled: false },
};
```
Expand Down
11 changes: 0 additions & 11 deletions docs/development/local-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,17 +171,6 @@ To do this, see these GitHub guides:

## Tips and tricks

### Running Renovate against forked repositories

Quite often, the quickest way for you to test or fix something is to fork an existing repository.
But by default Renovate skips over repositories that are forked.
To override this default, you need to specify the setting `includeForks` as `true`.

Tell Renovate to run on your forked repository by doing one of the following:

1. Add `"includeForks": true` to the `renovate.json` file in your forked repository
1. Run Renovate with the CLI flag `--renovate-fork=true`

### Log files

Usually, `debug` is good enough to troubleshoot most problems or verify functionality.
Expand Down
18 changes: 10 additions & 8 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -923,6 +923,16 @@ If this option is enabled, reviewers will need to create a new PR if additional
!!! note
This option is only relevant if you set `forkToken`.

## forkProcessing

By default, Renovate will skip over any repositories that are forked if Renovate is using `autodiscover` mode.
This includes if the forked repository has a Renovate config file, because Renovate can't tell if that file was added by the original repository or not.
If you wish to enable processing of a forked repository by Renovate when autodiscovering, you need to add `"forkProcessing": "enabled"` to your repository config or run the CLI command with `--fork-processing=enabled`.

If you are running in non-autodiscover mode (e.g. supplying a list of repositories to Renovate) but wish to skip forked repositories, you need to configure `"forkProcessing": "disabled"` in your global config.

If you are using the hosted Mend Renovate then this option will be configured to `"enabled"` automatically if you "Selected" repositories individually but `"disabled"` if you installed for "All" repositories. If you have installed Renovate into "All" repositories but have a fork you want to use, then add `"forkProcessing": "enabled"` to the repository's `renovate.json` file.

## gitAuthor

You can customize the Git author that's used whenever Renovate creates a commit.
Expand Down Expand Up @@ -1417,14 +1427,6 @@ If you need to force permanent unstable updates for a package, you can add a pac

Also check out the `followTag` configuration option above if you wish Renovate to keep you pinned to a particular release tag.

## includeForks

By default, Renovate will skip over any repositories that are forked.
This includes if the forked repository has a Renovate config file, because Renovate can't tell if that file was added by the original repository or not.
If you wish to enable processing of a forked repository by Renovate, you need to add `"includeForks": true` to your repository config or run the CLI command with `--include-forks=true`.

If you are using the hosted Mend Renovate then this option will be configured to `true` automatically if you "Selected" repositories individually but remain as `false` if you installed for "All" repositories.

## includePaths

If you wish for Renovate to process only select paths in the repository, use `includePaths`.
Expand Down
2 changes: 1 addition & 1 deletion lib/config/__snapshots__/migration.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates config 1`
"config:js-lib",
":dependencyDashboard",
],
"forkProcessing": "enabled",
"hostRules": [
{
"hostType": "docker",
Expand All @@ -142,7 +143,6 @@ exports[`config/migration migrateConfig(config, parentConfig) migrates config 1`
"ignorePaths": [
"node_modules/",
],
"includeForks": true,
"lockFileMaintenance": {
"automerge": true,
"exposeAllEnv": false,
Expand Down
34 changes: 34 additions & 0 deletions lib/config/migrations/custom/include-forks-migration.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { RenovateForkMigration } from './include-forks-migration';

describe('config/migrations/custom/include-forks-migration', () => {
it('should migrate true', () => {
expect(RenovateForkMigration).toMigrate(
{
includeForks: true,
},
{
forkProcessing: 'enabled',
}
);
});

it('should migrate false', () => {
expect(RenovateForkMigration).toMigrate(
{
includeForks: false,
},
{
forkProcessing: 'disabled',
}
);
});

it('should not migrate non boolean value', () => {
expect(RenovateForkMigration).toMigrate(
{
includeForks: 'test',
},
{}
);
});
});
13 changes: 13 additions & 0 deletions lib/config/migrations/custom/include-forks-migration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import is from '@sindresorhus/is';
import { AbstractMigration } from '../base/abstract-migration';

export class RenovateForkMigration extends AbstractMigration {
override readonly deprecated = true;
override readonly propertyName = 'includeForks';

override run(value: unknown): void {
if (is.boolean(value)) {
this.setSafely('forkProcessing', value ? 'enabled' : 'disabled');
}
}
}
4 changes: 2 additions & 2 deletions lib/config/migrations/custom/renovate-fork-migration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ describe('config/migrations/custom/renovate-fork-migration', () => {
renovateFork: true,
},
{
includeForks: true,
forkProcessing: 'enabled',
}
);
});
Expand All @@ -18,7 +18,7 @@ describe('config/migrations/custom/renovate-fork-migration', () => {
renovateFork: false,
},
{
includeForks: false,
forkProcessing: 'disabled',
}
);
});
Expand Down
2 changes: 1 addition & 1 deletion lib/config/migrations/custom/renovate-fork-migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class RenovateForkMigration extends AbstractMigration {

override run(value: unknown): void {
if (is.boolean(value)) {
this.setSafely('includeForks', value);
this.setSafely('forkProcessing', value ? 'enabled' : 'disabled');
}
}
}
9 changes: 5 additions & 4 deletions lib/config/options/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -419,12 +419,13 @@ const options: RenovateOptions[] = [
experimentalIssues: [17633],
},
{
name: 'includeForks',
name: 'forkProcessing',
description:
'Whether to process forked repositories. By default, all forked repositories are skipped.',
'Whether to process forked repositories. By default, all forked repositories are skipped when in autodiscover mode.',
stage: 'repository',
type: 'boolean',
default: false,
type: 'string',
allowedValues: ['auto', 'enabled', 'disabled'],
default: 'auto',
},
{
name: 'forkToken',
Expand Down
2 changes: 1 addition & 1 deletion lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export interface RenovateConfig
hostRules?: HostRule[];

ignorePresets?: string[];
includeForks?: boolean;
forkProcessing?: 'auto' | 'enabled' | 'disabled';
isFork?: boolean;

fileList?: string[];
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/platform/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export interface RepoParams {
endpoint?: string;
gitUrl?: GitUrlOption;
forkToken?: string;
includeForks?: boolean;
forkProcessing?: 'enabled' | 'disabled';
renovateUsername?: string;
cloneSubmodules?: boolean;
ignorePrAuthor?: boolean;
Expand Down
2 changes: 2 additions & 0 deletions lib/workers/global/config/parse/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export function getConfig(input: string[]): AllConfig {
.replace(/^--dry-run$/, '--dry-run=true')
.replace(/^--require-config$/, '--require-config=true')
.replace('--aliases', '--registry-aliases')
.replace('--include-forks=true', '--fork-processing=enabled')
.replace('--include-forks', '--fork-processing=enabled')
)
.filter((a) => !a.startsWith('--git-fs'));
const options = getOptions();
Expand Down
6 changes: 6 additions & 0 deletions lib/workers/global/config/parse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ export async function parseConfigs(
config.endpoint = ensureTrailingSlash(config.endpoint);
}

// Massage forkProcessing
if (!config.autodiscover && config.forkProcessing !== 'disabled') {
logger.debug('Enabling forkProcessing while in non-autodiscover mode');
config.forkProcessing = 'enabled';
}

// Remove log file entries
delete config.logFile;
delete config.logFileLevel;
Expand Down
2 changes: 1 addition & 1 deletion lib/workers/repository/configured.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function checkIfConfigured(config: RenovateConfig): void {
if (config.enabled === false) {
throw new Error(REPOSITORY_DISABLED_BY_CONFIG);
}
if (config.isFork && !config.includeForks) {
if (config.isFork && config.forkProcessing !== 'enabled') {
throw new Error(REPOSITORY_FORKED);
}
}
33 changes: 26 additions & 7 deletions lib/workers/repository/init/apis.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('workers/repository/init/apis', () => {
config.warnings = [];
config.token = 'some-token';
delete config.optimizeForDisabled;
delete config.includeForks;
delete config.forkProcessing;
});

afterEach(() => {
Expand Down Expand Up @@ -53,15 +53,30 @@ describe('workers/repository/init/apis', () => {
isFork: true,
repoFingerprint: '123',
});
platform.getJsonFile.mockResolvedValueOnce({ includeForks: false });
platform.getJsonFile.mockResolvedValueOnce({
forkProcessing: 'disabled',
});
await expect(
initApis({
...config,
includeForks: false,
forkProcessing: 'disabled',
})
).rejects.toThrow(REPOSITORY_FORKED);
});

it('does not throw for includeForks=true', async () => {
platform.initRepo.mockResolvedValueOnce({
defaultBranch: 'master',
isFork: true,
repoFingerprint: '123',
});
platform.getJsonFile.mockResolvedValueOnce({
includeForks: true,
});
const workerPlatformConfig = await initApis(config);
expect(workerPlatformConfig).toBeTruthy();
});

it('ignores platform.getJsonFile() failures', async () => {
platform.initRepo.mockResolvedValueOnce({
defaultBranch: 'master',
Expand All @@ -73,7 +88,7 @@ describe('workers/repository/init/apis', () => {
initApis({
...config,
optimizeForDisabled: true,
includeForks: false,
forkProcessing: 'disabled',
isFork: true,
})
).resolves.not.toThrow();
Expand All @@ -85,7 +100,9 @@ describe('workers/repository/init/apis', () => {
isFork: false,
repoFingerprint: '123',
});
platform.getJsonFile.mockResolvedValueOnce({ includeForks: false });
platform.getJsonFile.mockResolvedValueOnce({
forkProcessing: 'disabled',
});
const workerPlatformConfig = await initApis({
...config,
optimizeForDisabled: true,
Expand All @@ -107,7 +124,9 @@ describe('workers/repository/init/apis', () => {
isFork: false,
repoFingerprint: '123',
});
platform.getJsonFile.mockResolvedValueOnce({ includeForks: false });
platform.getJsonFile.mockResolvedValueOnce({
forkProcessing: 'disabled',
});
const workerPlatformConfig = await initApis({
...config,
optimizeForDisabled: true,
Expand All @@ -124,7 +143,7 @@ describe('workers/repository/init/apis', () => {
isFork: false,
repoFingerprint: '123',
});
platform.getJsonFile.mockResolvedValueOnce({ includeForks: false });
platform.getJsonFile.mockResolvedValueOnce({ forkProcessing: false });
const workerPlatformConfig = await initApis({
...config,
optimizeForDisabled: true,
Expand Down
9 changes: 7 additions & 2 deletions lib/workers/repository/init/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
REPOSITORY_DISABLED_BY_CONFIG,
REPOSITORY_FORKED,
} from '../../../constants/error-messages';
import { logger } from '../../../logger';
import { RepoParams, RepoResult, platform } from '../../../modules/platform';

// TODO: fix types (#7154)
Expand Down Expand Up @@ -37,11 +38,15 @@ async function validateOptimizeForDisabled(
}

async function validateIncludeForks(config: RenovateConfig): Promise<void> {
if (!config.includeForks && config.isFork) {
if (config.forkProcessing !== 'enabled' && config.isFork) {
const renovateConfig = await getJsonFile(defaultConfigFile(config));
if (!renovateConfig?.includeForks) {
if (
renovateConfig?.includeForks !== true &&
renovateConfig?.forkProcessing !== 'enabled'
) {
throw new Error(REPOSITORY_FORKED);
}
logger.debug('Repository config enables forks - continuing');
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/workers/repository/onboarding/branch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export async function checkOnboardingBranch(
logger.debug('Repo is onboarded');
return { ...config, repoIsOnboarded };
}
if (config.isFork && !config.includeForks) {
if (config.isFork && config.forkProcessing !== 'enabled') {
throw new Error(REPOSITORY_FORKED);
}
logger.debug('Repo is not onboarded');
Expand Down

0 comments on commit a4ab452

Please sign in to comment.