From 7b5485edaa7348686e3b99fc405b12e5af95d515 Mon Sep 17 00:00:00 2001 From: David Straub <Scinvention@gmail.com> Date: Tue, 14 Jan 2020 22:32:31 -0500 Subject: [PATCH] feat(workers): implement `additionalReviewers` option (#5152) Closes #5121 --- docs/usage/configuration-options.md | 4 ++++ lib/config/definitions.ts | 8 ++++++++ lib/workers/pr/index.ts | 19 +++++++++++++------ renovate-schema.json | 7 +++++++ .../pr/__snapshots__/index.spec.ts.snap | 14 ++++++++++++++ test/workers/pr/index.spec.ts | 8 ++++++++ 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index e044922481..d5d7863fc5 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -21,6 +21,10 @@ Also, be sure to check out Renovate's [shareable config presets](/config-presets If you have any questions about the below config options, or would like to get help/feedback about a config, please post it as an issue in [renovatebot/config-help](https://github.com/renovatebot/config-help) where we will do our best to answer your question. +## additionalReviewers + +In contrast to `reviewers`, this option adds to the existing reviewer list, rather than replacing it. This makes it suitable for augmenting a preset or base list without displacing the original, for example when adding focused reviewers for a specific package group. + ## aliases The `aliases` object is used for configuring registry aliases. Currently it is needed/supported for the `helm-requiremenets` manager only. diff --git a/lib/config/definitions.ts b/lib/config/definitions.ts index 2e7ef9f80c..c10561b22a 100644 --- a/lib/config/definitions.ts +++ b/lib/config/definitions.ts @@ -1335,6 +1335,14 @@ const options: RenovateOptions[] = [ type: 'integer', default: null, }, + { + name: 'additionalReviewers', + description: + 'Additional reviewers for Pull Requests (in contrast to `reviewers`, this option adds to the existing reviewer list, rather than replacing it)', + type: 'array', + subType: 'string', + mergeable: true, + }, { name: 'fileMatch', description: 'RegEx (re2) pattern for matching manager files', diff --git a/lib/workers/pr/index.ts b/lib/workers/pr/index.ts index ca0be895dd..c8f9df166d 100644 --- a/lib/workers/pr/index.ts +++ b/lib/workers/pr/index.ts @@ -1,4 +1,5 @@ import sampleSize from 'lodash/sampleSize'; +import uniq from 'lodash/uniq'; import { logger } from '../../logger'; import { getChangeLogJSON } from './changelog'; import { getPrBody } from './body'; @@ -15,12 +16,14 @@ function noWhitespace(input: string): string { return input.replace(/\r?\n|\r|\s/g, ''); } +function noLeadingAtSymbol(input: string): string { + return input.length && input[0] === '@' ? input.slice(1) : input; +} + async function addAssigneesReviewers(config, pr: Pr): Promise<void> { if (config.assignees.length > 0) { try { - let assignees = config.assignees.map(assignee => - assignee.length && assignee[0] === '@' ? assignee.slice(1) : assignee - ); + let assignees = config.assignees.map(noLeadingAtSymbol); if (config.assigneesSampleSize !== null) { assignees = sampleSize(assignees, config.assigneesSampleSize); } @@ -40,9 +43,13 @@ async function addAssigneesReviewers(config, pr: Pr): Promise<void> { } if (config.reviewers.length > 0) { try { - let reviewers = config.reviewers.map(reviewer => - reviewer.length && reviewer[0] === '@' ? reviewer.slice(1) : reviewer - ); + let reviewers = config.reviewers.map(noLeadingAtSymbol); + if (config.additionalReviewers.length > 0) { + const additionalReviewers = config.additionalReviewers.map( + noLeadingAtSymbol + ); + reviewers = uniq(reviewers.concat(additionalReviewers)); + } if (config.reviewersSampleSize !== null) { reviewers = sampleSize(reviewers, config.reviewersSampleSize); } diff --git a/renovate-schema.json b/renovate-schema.json index 4bdb19e3d0..43b2586739 100644 --- a/renovate-schema.json +++ b/renovate-schema.json @@ -855,6 +855,13 @@ "type": "integer", "default": null }, + "additionalReviewers": { + "description": "Additional reviewers for Pull Requests (in contrast to `reviewers`, this option adds to the existing reviewer list, rather than replacing it)", + "type": "array", + "items": { + "type": "string" + } + }, "fileMatch": { "description": "RegEx (re2) pattern for matching manager files", "type": "array", diff --git a/test/workers/pr/__snapshots__/index.spec.ts.snap b/test/workers/pr/__snapshots__/index.spec.ts.snap index 29bb32942e..a80821eaf3 100644 --- a/test/workers/pr/__snapshots__/index.spec.ts.snap +++ b/test/workers/pr/__snapshots__/index.spec.ts.snap @@ -1,5 +1,19 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`workers/pr ensurePr should add and deduplicate additionalReviewers on new PR 1`] = ` +Array [ + Array [ + undefined, + Array [ + "foo", + "bar", + "baz", + "boo", + ], + ], +] +`; + exports[`workers/pr ensurePr should add assignees and reviewers to new PR 1`] = ` Array [ Array [ diff --git a/test/workers/pr/index.spec.ts b/test/workers/pr/index.spec.ts index 39f83a0ef2..a056263dc6 100644 --- a/test/workers/pr/index.spec.ts +++ b/test/workers/pr/index.spec.ts @@ -325,6 +325,14 @@ describe('workers/pr', () => { expect(reviewers.length).toEqual(2); expect(config.reviewers).toEqual(expect.arrayContaining(reviewers)); }); + it('should add and deduplicate additionalReviewers on new PR', async () => { + config.reviewers = ['@foo', 'bar']; + config.additionalReviewers = ['bar', 'baz', '@boo']; + const pr = await prWorker.ensurePr(config); + expect(pr).toMatchObject({ displayNumber: 'New Pull Request' }); + expect(platform.addReviewers).toHaveBeenCalledTimes(1); + expect(platform.addReviewers.mock.calls).toMatchSnapshot(); + }); it('should return unmodified existing PR', async () => { platform.getBranchPr.mockResolvedValueOnce(existingPr); config.semanticCommitScope = null; -- GitLab