From ca5be4be9af4671636139c2bef7a39b188a99667 Mon Sep 17 00:00:00 2001 From: Adam Setch Date: Fri, 19 Aug 2022 17:14:51 -0400 Subject: [PATCH] feat: new branchNameStrict configuration flag (#17216) --- docs/usage/configuration-options.md | 6 +++ lib/config/options/index.ts | 6 +++ lib/config/types.ts | 1 + .../repository/updates/branch-name.spec.ts | 46 +++++++++++++++++++ lib/workers/repository/updates/branch-name.ts | 25 ++++++++-- 5 files changed, 80 insertions(+), 4 deletions(-) diff --git a/docs/usage/configuration-options.md b/docs/usage/configuration-options.md index 01e974dd7c0a1d..4b904edbef5d18 100644 --- a/docs/usage/configuration-options.md +++ b/docs/usage/configuration-options.md @@ -287,6 +287,12 @@ If you truly need to configure this then it probably means either: - You are hopefully mistaken, and there's a better approach you should use, so open a new "config help" discussion at the [Renovate discussions tab](https://github.com/renovatebot/renovate/discussions) or - You have a use case we didn't expect and we should have a feature request from you to add it to the project +## branchNameStrict + +By default, Renovate does not use strict-mode when slugifying the branch name. This means that certain special characters such as `.` may end up within the branch name. + +By setting this configuration to `true`, all special characters will be removed from the branch name, resulting in a branch name consisting exclusively of alphabetic characters separated by `-`. + ## branchPrefix You can modify this field if you want to change the prefix used. diff --git a/lib/config/options/index.ts b/lib/config/options/index.ts index 66a5b943950b8e..c7911955152ee1 100644 --- a/lib/config/options/index.ts +++ b/lib/config/options/index.ts @@ -2352,6 +2352,12 @@ const options: RenovateOptions[] = [ default: false, supportedPlatforms: ['github'], }, + { + name: 'branchNameStrict', + description: `Whether to be strict about the use of special characters within the branch name.`, + type: 'boolean', + default: false, + }, ]; export function getOptions(): RenovateOptions[] { diff --git a/lib/config/types.ts b/lib/config/types.ts index f9f53cae4c6533..4e11fa6e81d24a 100644 --- a/lib/config/types.ts +++ b/lib/config/types.ts @@ -28,6 +28,7 @@ export interface RenovateSharedConfig { branchPrefix?: string; branchPrefixOld?: string; branchName?: string; + branchNameStrict?: boolean; manager?: string | null; commitMessage?: string; commitMessagePrefix?: string; diff --git a/lib/workers/repository/updates/branch-name.spec.ts b/lib/workers/repository/updates/branch-name.spec.ts index 93ff3a94ee596c..07c368946e8afc 100644 --- a/lib/workers/repository/updates/branch-name.spec.ts +++ b/lib/workers/repository/updates/branch-name.spec.ts @@ -146,6 +146,22 @@ describe('workers/repository/updates/branch-name', () => { expect(upgrade.branchName).toBe('renovate/jest-42.x'); }); + it('realistic defaults with strict branch name enabled', () => { + const upgrade: RenovateConfig = { + branchNameStrict: true, + branchName: + '{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}', + branchTopic: + '{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}', + branchPrefix: 'renovate/', + depNameSanitized: 'jest', + newMajor: '42', + group: {}, + }; + generateBranchName(upgrade); + expect(upgrade.branchName).toBe('renovate/jest-42-x'); + }); + it('hashedBranchLength hashing', () => { const upgrade: RenovateConfig = { branchName: @@ -293,5 +309,35 @@ describe('workers/repository/updates/branch-name', () => { expect(fixture.upgrade.branchName).toEqual(fixture.expectedBranchName); }); }); + + it('strict branch name enabled group', () => { + const upgrade: RenovateConfig = { + branchNameStrict: true, + groupName: 'some group name `~#$%^&*()-_=+[]{}|;,./<>? .version', + group: { + branchName: '{{groupSlug}}-{{branchTopic}}', + branchTopic: 'grouptopic', + }, + }; + generateBranchName(upgrade); + expect(upgrade.branchName).toBe( + 'some-group-name-dollarpercentand-or-lessgreater-version-grouptopic' + ); + }); + + it('strict branch name disabled', () => { + const upgrade: RenovateConfig = { + branchNameStrict: false, + groupName: '[some] group name.#$%version', + group: { + branchName: '{{groupSlug}}-{{branchTopic}}', + branchTopic: 'grouptopic', + }, + }; + generateBranchName(upgrade); + expect(upgrade.branchName).toBe( + 'some-group-name.dollarpercentversion-grouptopic' + ); + }); }); }); diff --git a/lib/workers/repository/updates/branch-name.ts b/lib/workers/repository/updates/branch-name.ts index da71eae75a1d90..b88ec208b3d8e5 100644 --- a/lib/workers/repository/updates/branch-name.ts +++ b/lib/workers/repository/updates/branch-name.ts @@ -10,6 +10,9 @@ import * as template from '../../../util/template'; const MIN_HASH_LENGTH = 6; const RE_MULTIPLE_DASH = regEx(/--+/g); + +const RE_SPECIAL_CHARS_STRICT = regEx(/[`~!@#$%^&*()_=+[\]\\|{};':",.<>?]/g); + /** * Clean git branch name * @@ -17,15 +20,26 @@ const RE_MULTIPLE_DASH = regEx(/--+/g); * - leading dot/leading dot after slash * - trailing dot * - whitespace + * - special characters + * - leading or trailing dashes * - chained dashes(breaks markdown comments) are replaced by single dash */ -function cleanBranchName(branchName: string): string { +function cleanBranchName( + branchName: string, + branchNameStrict?: boolean +): string { + let cleanedBranchName = branchName; + + if (branchNameStrict) { + cleanedBranchName = cleanedBranchName.replace(RE_SPECIAL_CHARS_STRICT, '-'); // massage out all special characters that slip through slugify + } + return cleanGitRef - .clean(branchName) + .clean(cleanedBranchName) .replace(regEx(/^\.|\.$/), '') // leading or trailing dot .replace(regEx(/\/\./g), '/') // leading dot after slash .replace(regEx(/\s/g), '') // whitespace - .replace(regEx(/[[\]?:\\^~]/g), '-') // massage out all these characters: : ? [ \ ^ ~ + .replace(regEx(/[[\]?:\\^~]/g), '-') // massage out all these characters: [ ] ? : \ ^ ~ .replace(regEx(/(^|\/)-+/g), '$1') // leading dashes .replace(regEx(/-+(\/|$)/g), '$1') // trailing dashes .replace(RE_MULTIPLE_DASH, '-'); // chained dashes @@ -94,5 +108,8 @@ export function generateBranchName(update: RenovateConfig): void { update.branchName = template.compile(update.branchName, update); } - update.branchName = cleanBranchName(update.branchName); + update.branchName = cleanBranchName( + update.branchName, + update.branchNameStrict + ); }