From 3bdd530ae55ea0132ac4e16e5bcc53e548f838bd Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Sat, 2 Mar 2024 11:42:43 +0100 Subject: [PATCH] feat: forkCreation (#27686) --- docs/usage/self-hosted-configuration.md | 6 ++++++ lib/config/options/index.ts | 11 ++++++++++ lib/constants/error-messages.ts | 1 + lib/modules/platform/github/index.spec.ts | 25 +++++++++++++++++++++++ lib/modules/platform/github/index.ts | 7 ++++++- lib/modules/platform/github/types.ts | 1 + lib/modules/platform/types.ts | 1 + lib/workers/repository/error.spec.ts | 2 ++ lib/workers/repository/error.ts | 5 +++++ 9 files changed, 58 insertions(+), 1 deletion(-) diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index 57e7e33536..b38bfcd446 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -555,6 +555,12 @@ In practice, it is implemented by converting the `force` configuration into a `p This is set to `true` by default, meaning that any settings (such as `schedule`) take maximum priority even against custom settings existing inside individual repositories. It will also override any settings in `packageRules`. +## forkCreation + +This configuration lets you disable the runtime forking of repositories when running in "fork mode". + +Usually you will need to keep this as the default `true`, and only set to `false` if you have some out of band process to handle the creation of forks. + ## forkOrg This configuration option lets you choose an organization you want repositories forked into when "fork mode" is enabled. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 00459b4fa2..cdf1f8cb18 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -530,6 +530,17 @@ const options: RenovateOptions[] = [ supportedPlatforms: ['gitlab'], globalOnly: true, }, + { + name: 'forkCreation', + description: + 'Whether to create forks as needed at runtime when running in "fork mode".', + stage: 'repository', + type: 'boolean', + globalOnly: true, + supportedPlatforms: ['github'], + experimental: true, + default: true, + }, { name: 'forkToken', description: 'Set a personal access token here to enable "fork mode".', diff --git a/lib/constants/error-messages.ts b/lib/constants/error-messages.ts index 490e963733..aa7da4b79e 100644 --- a/lib/constants/error-messages.ts +++ b/lib/constants/error-messages.ts @@ -28,6 +28,7 @@ export const REPOSITORY_CLOSED_ONBOARDING = 'disabled-closed-onboarding'; export const REPOSITORY_DISABLED_BY_CONFIG = 'disabled-by-config'; export const REPOSITORY_NO_CONFIG = 'disabled-no-config'; export const REPOSITORY_EMPTY = 'empty'; +export const REPOSITORY_FORK_MISSING = 'fork-missing'; export const REPOSITORY_FORK_MODE_FORKED = 'fork-mode-forked'; export const REPOSITORY_FORKED = 'fork'; export const REPOSITORY_MIRRORED = 'mirror'; diff --git a/lib/modules/platform/github/index.spec.ts b/lib/modules/platform/github/index.spec.ts index 1f7e15ef8f..d887628eb9 100644 --- a/lib/modules/platform/github/index.spec.ts +++ b/lib/modules/platform/github/index.spec.ts @@ -8,6 +8,7 @@ import { PLATFORM_UNKNOWN_ERROR, REPOSITORY_CANNOT_FORK, REPOSITORY_FORKED, + REPOSITORY_FORK_MISSING, REPOSITORY_NOT_FOUND, REPOSITORY_RENAMED, } from '../../../constants/error-messages'; @@ -546,10 +547,26 @@ describe('modules/platform/github/index', () => { const config = await github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }); expect(config).toMatchSnapshot(); }); + it('should throw if fork needed but forkCreation=false', async () => { + const scope = httpMock.scope(githubApiHost); + forkInitRepoMock(scope, 'some/repo', false); + scope.get('/user').reply(200, { + login: 'forked', + }); + await expect( + github.initRepo({ + repository: 'some/repo', + forkToken: 'true', + forkCreation: false, + }), + ).rejects.toThrow(REPOSITORY_FORK_MISSING); + }); + it('throws if the repo is a fork', async () => { const repo = 'some/repo'; const branch = 'master'; @@ -559,6 +576,7 @@ describe('modules/platform/github/index', () => { github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }), ).rejects.toThrow(REPOSITORY_FORKED); }); @@ -573,6 +591,7 @@ describe('modules/platform/github/index', () => { github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }), ).rejects.toThrow(REPOSITORY_CANNOT_FORK); }); @@ -585,6 +604,7 @@ describe('modules/platform/github/index', () => { github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }), ).rejects.toThrow(REPOSITORY_CANNOT_FORK); }); @@ -597,6 +617,7 @@ describe('modules/platform/github/index', () => { github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }), ).rejects.toThrow(REPOSITORY_CANNOT_FORK); }); @@ -613,6 +634,7 @@ describe('modules/platform/github/index', () => { github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, forkOrg: 'forked', }), ).rejects.toThrow(REPOSITORY_CANNOT_FORK); @@ -625,6 +647,7 @@ describe('modules/platform/github/index', () => { const config = await github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, forkOrg: 'forked', }); expect(config).toMatchSnapshot(); @@ -642,6 +665,7 @@ describe('modules/platform/github/index', () => { const config = await github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }); expect(config).toMatchSnapshot(); }); @@ -2568,6 +2592,7 @@ describe('modules/platform/github/index', () => { await github.initRepo({ repository: 'some/repo', forkToken: 'true', + forkCreation: true, }); }); diff --git a/lib/modules/platform/github/index.ts b/lib/modules/platform/github/index.ts index a5894572cd..b5c6948fe4 100644 --- a/lib/modules/platform/github/index.ts +++ b/lib/modules/platform/github/index.ts @@ -16,6 +16,7 @@ import { REPOSITORY_DISABLED, REPOSITORY_EMPTY, REPOSITORY_FORKED, + REPOSITORY_FORK_MISSING, REPOSITORY_FORK_MODE_FORKED, REPOSITORY_NOT_FOUND, REPOSITORY_RENAMED, @@ -434,6 +435,7 @@ export async function createFork( export async function initRepo({ endpoint, repository, + forkCreation, forkOrg, forkToken, renovateUsername, @@ -682,10 +684,13 @@ export async function initRepo({ } throw new ExternalHostError(err); } - } else { + } else if (forkCreation) { logger.debug('Forked repo is not found - attempting to create it'); forkedRepo = await createFork(forkToken, repository, forkOrg); config.repository = forkedRepo.full_name; + } else { + logger.debug('Forked repo is not found and forkCreation is disabled'); + throw new Error(REPOSITORY_FORK_MISSING); } } diff --git a/lib/modules/platform/github/types.ts b/lib/modules/platform/github/types.ts index f3c0e06661..48c41ef007 100644 --- a/lib/modules/platform/github/types.ts +++ b/lib/modules/platform/github/types.ts @@ -95,6 +95,7 @@ export interface LocalRepoConfig { parentRepo: string | null; forkOrg?: string; forkToken?: string; + forkCreation?: boolean; prList: GhPr[] | null; issueList: any[] | null; mergeMethod: 'rebase' | 'squash' | 'merge'; diff --git a/lib/modules/platform/types.ts b/lib/modules/platform/types.ts index 8a27564666..eff914fb7d 100644 --- a/lib/modules/platform/types.ts +++ b/lib/modules/platform/types.ts @@ -41,6 +41,7 @@ export interface RepoParams { repository: string; endpoint?: string; gitUrl?: GitUrlOption; + forkCreation?: boolean; forkOrg?: string; forkToken?: string; forkProcessing?: 'enabled' | 'disabled'; diff --git a/lib/workers/repository/error.spec.ts b/lib/workers/repository/error.spec.ts index 1c2a662370..021836c21c 100644 --- a/lib/workers/repository/error.spec.ts +++ b/lib/workers/repository/error.spec.ts @@ -18,6 +18,7 @@ import { REPOSITORY_DISABLED, REPOSITORY_EMPTY, REPOSITORY_FORKED, + REPOSITORY_FORK_MISSING, REPOSITORY_FORK_MODE_FORKED, REPOSITORY_MIRRORED, REPOSITORY_NOT_FOUND, @@ -48,6 +49,7 @@ describe('workers/repository/error', () => { REPOSITORY_DISABLED, REPOSITORY_CHANGED, REPOSITORY_FORKED, + REPOSITORY_FORK_MISSING, REPOSITORY_FORK_MODE_FORKED, REPOSITORY_NO_PACKAGE_FILES, CONFIG_SECRETS_EXPOSED, diff --git a/lib/workers/repository/error.ts b/lib/workers/repository/error.ts index 6e02b09315..04a7515950 100644 --- a/lib/workers/repository/error.ts +++ b/lib/workers/repository/error.ts @@ -21,6 +21,7 @@ import { REPOSITORY_DISABLED_BY_CONFIG, REPOSITORY_EMPTY, REPOSITORY_FORKED, + REPOSITORY_FORK_MISSING, REPOSITORY_FORK_MODE_FORKED, REPOSITORY_MIRRORED, REPOSITORY_NOT_FOUND, @@ -110,6 +111,10 @@ export default async function handleError( logger.info('Cannot fork repository - skipping'); return err.message; } + if (err.message === REPOSITORY_FORK_MISSING) { + logger.info('Cannot find fork required for fork mode - skipping'); + return err.message; + } if (err.message === REPOSITORY_NO_PACKAGE_FILES) { logger.info('Repository has no package files - skipping'); return err.message; -- GitLab