From 5511f33d06a39902702a2dbf1de01c6837f2763c Mon Sep 17 00:00:00 2001 From: Philip <42116482+PhilipAbed@users.noreply.github.com> Date: Tue, 2 May 2023 11:54:49 +0300 Subject: [PATCH] feat: checkedBranches (#21845) Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- docs/usage/self-hosted-configuration.md | 9 +++++++ lib/config/options/index.ts | 10 ++++++++ lib/config/types.ts | 2 ++ .../repository/dependency-dashboard.spec.ts | 25 +++++++++++++++++++ .../repository/dependency-dashboard.ts | 17 ++++++++++++- .../repository/update/branch/index.spec.ts | 21 ++++++++++++++++ lib/workers/repository/update/branch/index.ts | 3 +++ 7 files changed, 86 insertions(+), 1 deletion(-) diff --git a/docs/usage/self-hosted-configuration.md b/docs/usage/self-hosted-configuration.md index e0fb0cc5ed..fcf72c943a 100644 --- a/docs/usage/self-hosted-configuration.md +++ b/docs/usage/self-hosted-configuration.md @@ -219,6 +219,15 @@ Results which are soft expired are reused in the following manner: - The `etag` from the cached results will be reused, and may result in a 304 response, meaning cached results are revalidated - If an error occurs when querying the `npmjs` registry, then soft expired results will be reused if they are present +## checkedBranches + +This array will allow you to set the names of the branches you want to rebase/create, as if you selected their checkboxes in the Dependency Dashboard issue. + +It has been designed with the intention of being run on one repository, in a one-off manner, e.g. to "force" the rebase of a known existing branch. +It is highly unlikely that you should ever need to add this to your permanent global config. + +Example: `renovate --checked-branches=renovate/chalk-4.x renovate-reproductions/checked` will rebase the `renovate/chalk-4.x` branch in the `renovate-reproductions/checked` repository.` + ## containerbaseDir This directory is used to cache downloads when `binarySource=docker` or `binarySource=install`. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 60153f1ef7..a020d9dae7 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -2624,6 +2624,16 @@ const options: RenovateOptions[] = [ type: 'boolean', default: false, }, + { + name: 'checkedBranches', + description: + 'A list of branch names to mark for creation or rebasing as if it was selected in the Dependency Dashboard issue.', + type: 'array', + subType: 'string', + experimental: true, + globalOnly: true, + default: [], + }, ]; export function getOptions(): RenovateOptions[] { diff --git a/lib/config/types.ts b/lib/config/types.ts index aedf88d623..0df00b27a9 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -260,6 +260,8 @@ export interface RenovateConfig skipInstalls?: boolean | null; constraintsFiltering?: ConstraintsFilter; + + checkedBranches?: string[]; } export interface AllConfig diff --git a/lib/workers/repository/dependency-dashboard.spec.ts b/lib/workers/repository/dependency-dashboard.spec.ts index 6170c3dcdc..a2d9b97782 100644 --- a/lib/workers/repository/dependency-dashboard.spec.ts +++ b/lib/workers/repository/dependency-dashboard.spec.ts @@ -104,6 +104,31 @@ describe('workers/repository/dependency-dashboard', () => { }); }); + it('reads dashboard body and apply checkedBranches', async () => { + const conf: RenovateConfig = {}; + conf.prCreation = 'approval'; + conf.checkedBranches = ['branch1', 'branch2']; + platform.findIssue.mockResolvedValueOnce({ + title: '', + number: 1, + body: Fixtures.get('dependency-dashboard-with-8-PR.txt'), + }); + await dependencyDashboard.readDashboardBody(conf); + expect(conf).toEqual({ + checkedBranches: ['branch1', 'branch2'], + dependencyDashboardAllPending: false, + dependencyDashboardAllRateLimited: false, + dependencyDashboardChecks: { + branch1: 'global-config', + branch2: 'global-config', + }, + dependencyDashboardIssue: 1, + dependencyDashboardRebaseAllOpen: false, + dependencyDashboardTitle: 'Dependency Dashboard', + prCreation: 'approval', + }); + }); + it('reads dashboard body all pending approval', async () => { const conf: RenovateConfig = {}; conf.prCreation = 'approval'; diff --git a/lib/workers/repository/dependency-dashboard.ts b/lib/workers/repository/dependency-dashboard.ts index ac00cdd0fe..6054f0e58e 100644 --- a/lib/workers/repository/dependency-dashboard.ts +++ b/lib/workers/repository/dependency-dashboard.ts @@ -113,7 +113,22 @@ export async function readDashboardBody( const issue = await platform.findIssue(config.dependencyDashboardTitle); if (issue) { config.dependencyDashboardIssue = issue.number; - Object.assign(config, parseDashboardIssue(issue.body!)); + const dashboardChecks = parseDashboardIssue(issue.body!); + + if (config.checkedBranches) { + const checkedBranchesRec: Record<string, string> = Object.fromEntries( + config.checkedBranches.map((branchName) => [ + branchName, + 'global-config', + ]) + ); + dashboardChecks.dependencyDashboardChecks = { + ...dashboardChecks.dependencyDashboardChecks, + ...checkedBranchesRec, + }; + } + + Object.assign(config, dashboardChecks); } } } diff --git a/lib/workers/repository/update/branch/index.spec.ts b/lib/workers/repository/update/branch/index.spec.ts index 7609eab2d2..636803ec39 100644 --- a/lib/workers/repository/update/branch/index.spec.ts +++ b/lib/workers/repository/update/branch/index.spec.ts @@ -2015,6 +2015,27 @@ describe('workers/repository/update/branch/index', () => { expect(commit.commitFilesToBranch).toHaveBeenCalled(); }); + it('continues when checked by checkedBranches', async () => { + getUpdated.getUpdatedPackageFiles.mockResolvedValueOnce( + updatedPackageFiles + ); + npmPostExtract.getAdditionalFiles.mockResolvedValueOnce({ + artifactErrors: [], + updatedArtifacts: [], + }); + scm.branchExists.mockResolvedValue(true); + commit.commitFilesToBranch.mockResolvedValueOnce(null); + expect( + await branchWorker.processBranch({ + ...config, + dependencyDashboardChecks: { + 'renovate/some-branch': 'global-config', + }, + }) + ).toMatchObject({ result: 'done' }); + expect(commit.commitFilesToBranch).toHaveBeenCalled(); + }); + it('does nothing when branchPrefixOld/branch and its pr exists', async () => { getUpdated.getUpdatedPackageFiles.mockResolvedValueOnce({ ...updatedPackageFiles, diff --git a/lib/workers/repository/update/branch/index.ts b/lib/workers/repository/update/branch/index.ts index 81c8c7b758..ba93eee78e 100644 --- a/lib/workers/repository/update/branch/index.ts +++ b/lib/workers/repository/update/branch/index.ts @@ -367,6 +367,9 @@ export async function processBranch( if (userRebaseRequested) { logger.debug('Manual rebase requested via Dependency Dashboard'); config.reuseExistingBranch = false; + } else if (dependencyDashboardCheck === 'global-config') { + logger.debug(`Manual create/rebase requested via checkedBranches`); + config.reuseExistingBranch = false; } else if (userApproveAllPendingPR) { logger.debug( 'A user manually approved all pending PRs via the Dependency Dashboard.' -- GitLab