diff --git a/lib/workers/repository/onboarding/pr/index.ts b/lib/workers/repository/onboarding/pr/index.ts index 8efa0695c2e871f623d73899cc126151283f7b82..e0423a12b65c573406ecba885a60270dc9661d2d 100644 --- a/lib/workers/repository/onboarding/pr/index.ts +++ b/lib/workers/repository/onboarding/pr/index.ts @@ -12,11 +12,8 @@ import { } from '../../../../util/git'; import * as template from '../../../../util/template'; import type { BranchConfig } from '../../../types'; -import { - addAssigneesReviewers, - getPlatformPrOptions, - prepareLabels, -} from '../../update/pr'; +import { addAssigneesReviewers, getPlatformPrOptions } from '../../update/pr'; +import { prepareLabels } from '../../update/pr/labels'; import { getBaseBranchDesc } from './base-branch'; import { getConfigDesc } from './config-description'; import { getDepWarnings, getErrors, getWarnings } from './errors-warnings'; diff --git a/lib/workers/repository/update/pr/automerge.spec.ts b/lib/workers/repository/update/pr/automerge.spec.ts index adf095f1a2fb064d156da5002c29648f486a09df..81521555314acdc3d804ac711a15c736c2526cc3 100644 --- a/lib/workers/repository/update/pr/automerge.spec.ts +++ b/lib/workers/repository/update/pr/automerge.spec.ts @@ -26,6 +26,11 @@ describe('workers/repository/update/pr/automerge', () => { jest.clearAllMocks(); }); + it('should not automerge if not configured', async () => { + await prAutomerge.checkAutoMerge(pr, config); + expect(platform.mergePr).toHaveBeenCalledTimes(0); + }); + it('should automerge if enabled and pr is mergeable', async () => { config.automerge = true; config.pruneBranchAfterAutomerge = true; diff --git a/lib/workers/repository/update/pr/index.spec.ts b/lib/workers/repository/update/pr/index.spec.ts index ab25a757b12da1d1757b0311537ffc597d473314..d6dbf7d49f90648d118113dbabbccf11d655a593 100644 --- a/lib/workers/repository/update/pr/index.spec.ts +++ b/lib/workers/repository/update/pr/index.spec.ts @@ -10,7 +10,6 @@ import type { Pr } from '../../../../modules/platform'; import { BranchStatus } from '../../../../types'; import * as _limits from '../../../global/limits'; import type { BranchConfig } from '../../../types'; -import * as prAutomerge from './automerge'; import * as _changelogHelper from './changelog'; import type { ChangeLogResult } from './changelog'; import * as codeOwners from './code-owners'; @@ -116,85 +115,6 @@ function isResultWithoutPr( } describe('workers/repository/update/pr/index', () => { - describe('checkAutoMerge(pr, config)', () => { - let config: BranchConfig; - let pr: Pr; - - beforeEach(() => { - config = partial<BranchConfig>({ - ...getConfig(), - }); - pr = partial<Pr>({}); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should not automerge if not configured', async () => { - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(0); - }); - - it('should automerge if enabled and pr is mergeable', async () => { - config.automerge = true; - platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green); - platform.mergePr.mockResolvedValueOnce(true); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(1); - }); - - it('should automerge comment', async () => { - config.automerge = true; - config.automergeType = 'pr-comment'; - config.automergeComment = '!merge'; - platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.ensureCommentRemoval).toHaveBeenCalledTimes(0); - expect(platform.ensureComment).toHaveBeenCalledTimes(1); - }); - - it('should remove previous automerge comment when rebasing', async () => { - config.automerge = true; - config.automergeType = 'pr-comment'; - config.automergeComment = '!merge'; - config.rebaseRequested = true; - platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.ensureCommentRemoval).toHaveBeenCalledTimes(1); - expect(platform.ensureComment).toHaveBeenCalledTimes(1); - }); - - it('should not automerge if enabled and pr is mergeable but cannot rebase', async () => { - config.automerge = true; - platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.green); - git.isBranchModified.mockResolvedValueOnce(true); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(0); - }); - - it('should not automerge if enabled and pr is mergeable but branch status is not success', async () => { - config.automerge = true; - platform.getBranchStatus.mockResolvedValueOnce(BranchStatus.yellow); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(0); - }); - - it('should not automerge if enabled and pr is mergeable but unstable', async () => { - config.automerge = true; - pr.cannotMergeReason = 'some reason'; - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(0); - }); - - it('should not automerge if enabled and pr is unmergeable', async () => { - config.automerge = true; - git.isBranchConflicted.mockResolvedValueOnce(true); - await prAutomerge.checkAutoMerge(pr, config); - expect(platform.mergePr).toHaveBeenCalledTimes(0); - }); - }); - describe('ensurePr', () => { let config: BranchConfig; // TODO fix type @@ -871,81 +791,4 @@ describe('workers/repository/update/pr/index', () => { }); }); }); - - describe('prepareLabels(config)', () => { - it('returns empty array if no labels are configured', () => { - const result = prWorker.prepareLabels({}); - expect(result).toBeArrayOfSize(0); - }); - - it('only labels', () => { - const result = prWorker.prepareLabels({ labels: ['labelA', 'labelB'] }); - expect(result).toBeArrayOfSize(2); - expect(result).toEqual(['labelA', 'labelB']); - }); - - it('only addLabels', () => { - const result = prWorker.prepareLabels({ - addLabels: ['labelA', 'labelB'], - }); - expect(result).toBeArrayOfSize(2); - expect(result).toEqual(['labelA', 'labelB']); - }); - - it('merge labels and addLabels', () => { - const result = prWorker.prepareLabels({ - labels: ['labelA', 'labelB'], - addLabels: ['labelC'], - }); - expect(result).toBeArrayOfSize(3); - expect(result).toEqual(['labelA', 'labelB', 'labelC']); - }); - - it('deduplicate merged labels and addLabels', () => { - const result = prWorker.prepareLabels({ - labels: ['labelA', 'labelB'], - addLabels: ['labelB', 'labelC'], - }); - expect(result).toBeArrayOfSize(3); - expect(result).toEqual(['labelA', 'labelB', 'labelC']); - }); - - it('empty labels ignored', () => { - const result = prWorker.prepareLabels({ - labels: ['labelA', ''], - addLabels: [' ', 'labelB'], - }); - expect(result).toBeArrayOfSize(2); - expect(result).toEqual(['labelA', 'labelB']); - }); - - it('null labels ignored', () => { - const result = prWorker.prepareLabels({ - labels: ['labelA', null], - // an empty space between two commas in an array is categorized as a null value - // eslint-disable-next-line no-sparse-arrays - addLabels: ['labelB', '', undefined, , ,], - }); - expect(result).toBeArrayOfSize(2); - expect(result).toEqual(['labelA', 'labelB']); - }); - - it('template labels', () => { - const result = prWorker.prepareLabels({ - labels: ['datasource-{{{datasource}}}'], - datasource: 'npm', - }); - expect(result).toBeArrayOfSize(1); - expect(result).toEqual(['datasource-npm']); - }); - - it('template labels with empty datasource', () => { - const result = prWorker.prepareLabels({ - labels: ['{{{datasource}}}', ' {{{datasource}}} '], - datasource: null, - }); - expect(result).toBeArrayOfSize(0); - expect(result).toEqual([]); - }); - }); }); diff --git a/lib/workers/repository/update/pr/index.ts b/lib/workers/repository/update/pr/index.ts index ad81190bc2a3a2f6bee3645ba7d89e2da4da8eab..e44e576a975eb149bef4c53d215d760de5b092a4 100644 --- a/lib/workers/repository/update/pr/index.ts +++ b/lib/workers/repository/update/pr/index.ts @@ -1,4 +1,3 @@ -import is from '@sindresorhus/is'; import { GlobalConfig } from '../../../../config/global'; import type { RenovateConfig } from '../../../../config/types'; import { @@ -15,7 +14,6 @@ import { sampleSize } from '../../../../util'; import { stripEmojis } from '../../../../util/emoji'; import { deleteBranch, getBranchLastCommitTime } from '../../../../util/git'; import { regEx } from '../../../../util/regex'; -import * as template from '../../../../util/template'; import { Limit, incLimitedValue, isLimitReached } from '../../../global/limits'; import type { BranchConfig, @@ -26,6 +24,7 @@ import { resolveBranchStatus } from '../branch/status-checks'; import { getPrBody } from './body'; import { ChangeLogError } from './changelog/types'; import { codeOwnersForPr } from './code-owners'; +import { prepareLabels } from './labels'; function noWhitespaceOrHeadings(input: string): string { return input.replace(regEx(/\r?\n|\r|\s|#/g), ''); @@ -59,15 +58,6 @@ function prepareAssigneesReviewers( return filterUnavailableUsers(config, normalizedUsernames); } -export function prepareLabels(config: RenovateConfig): string[] { - const labels = config.labels ?? []; - const addLabels = config.addLabels ?? []; - return [...new Set([...labels, ...addLabels])] - .filter(is.nonEmptyStringAndNotWhitespace) - .map((label) => template.compile(label, config)) - .filter(is.nonEmptyStringAndNotWhitespace); -} - export async function addAssigneesReviewers( config: RenovateConfig, pr: Pr diff --git a/lib/workers/repository/update/pr/labels.spec.ts b/lib/workers/repository/update/pr/labels.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..60f5f8d315f419c2c3ff4c01995bdb3566eb0760 --- /dev/null +++ b/lib/workers/repository/update/pr/labels.spec.ts @@ -0,0 +1,80 @@ +import { prepareLabels } from './labels'; + +describe('workers/repository/update/pr/labels', () => { + describe('prepareLabels(config)', () => { + it('returns empty array if no labels are configured', () => { + const result = prepareLabels({}); + expect(result).toBeArrayOfSize(0); + }); + + it('only labels', () => { + const result = prepareLabels({ labels: ['labelA', 'labelB'] }); + expect(result).toBeArrayOfSize(2); + expect(result).toEqual(['labelA', 'labelB']); + }); + + it('only addLabels', () => { + const result = prepareLabels({ + addLabels: ['labelA', 'labelB'], + }); + expect(result).toBeArrayOfSize(2); + expect(result).toEqual(['labelA', 'labelB']); + }); + + it('merge labels and addLabels', () => { + const result = prepareLabels({ + labels: ['labelA', 'labelB'], + addLabels: ['labelC'], + }); + expect(result).toBeArrayOfSize(3); + expect(result).toEqual(['labelA', 'labelB', 'labelC']); + }); + + it('deduplicate merged labels and addLabels', () => { + const result = prepareLabels({ + labels: ['labelA', 'labelB'], + addLabels: ['labelB', 'labelC'], + }); + expect(result).toBeArrayOfSize(3); + expect(result).toEqual(['labelA', 'labelB', 'labelC']); + }); + + it('empty labels ignored', () => { + const result = prepareLabels({ + labels: ['labelA', ''], + addLabels: [' ', 'labelB'], + }); + expect(result).toBeArrayOfSize(2); + expect(result).toEqual(['labelA', 'labelB']); + }); + + it('null labels ignored', () => { + const result = prepareLabels({ + labels: ['labelA', null], + // an empty space between two commas in an array is categorized as a null value + // eslint-disable-next-line no-sparse-arrays + addLabels: ['labelB', '', undefined, , ,], + }); + expect(result).toBeArrayOfSize(2); + expect(result).toEqual(['labelA', 'labelB']); + }); + + it('template labels', () => { + const result = prepareLabels({ + labels: ['datasource-{{{datasource}}}'], + datasource: 'npm', + }); + expect(result).toBeArrayOfSize(1); + expect(result).toEqual(['datasource-npm']); + }); + + it('template labels with empty datasource', () => { + const result = prepareLabels({ + labels: ['{{{datasource}}}', ' {{{datasource}}} '], + datasource: null, + }); + expect(result).toBeArrayOfSize(0); + expect(result).toEqual([]); + }); + }); +}); diff --git a/lib/workers/repository/update/pr/labels.ts b/lib/workers/repository/update/pr/labels.ts new file mode 100644 index 0000000000000000000000000000000000000000..df04f8012593467243fa14a4ca57db717d16649e --- /dev/null +++ b/lib/workers/repository/update/pr/labels.ts @@ -0,0 +1,12 @@ +import is from '@sindresorhus/is'; +import type { RenovateConfig } from '../../../../config/types'; +import * as template from '../../../../util/template'; + +export function prepareLabels(config: RenovateConfig): string[] { + const labels = config.labels ?? []; + const addLabels = config.addLabels ?? []; + return [...new Set([...labels, ...addLabels])] + .filter(is.nonEmptyStringAndNotWhitespace) + .map((label) => template.compile(label, config)) + .filter(is.nonEmptyStringAndNotWhitespace); +}