Skip to content

Commit

Permalink
feat: hashedBranchLength option (#8502)
Browse files Browse the repository at this point in the history
  • Loading branch information
Turbo87 committed Feb 3, 2021
1 parent f533962 commit ee178df
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 9 deletions.
7 changes: 7 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,13 @@ As a result of the above, the branchName would be `renovate/dev-dependencies` in

Note: you shouldn't usually need to configure this unless you really care about your branch names.

## hashedBranchLength

Some code hosting systems have restrictions on the branch name lengths, this option lets you get around these restrictions.
You can set the `hashedBranchLength` option to a number of characters that works for your system and then Renovate will generate branch names with the appropriate length by hashing `additionalBranchPrefix` and `branchTopic`, and then truncating the hash so that the full branch name (including `branchPrefix`) has the right number of characters.

Example: If you have set `branchPrefix: "deps-"` and `hashedBranchLength: 12` it will result in a branch name like `deps-5bf36ec` instead of the traditional pretty branch name like `deps-react-17.x`.

## hostRules

Currently the purpose of `hostRules` is to configure credentials for host authentication.
Expand Down
1 change: 1 addition & 0 deletions lib/config/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface RenovateSharedConfig {
labels?: string[];
addLabels?: string[];
dependencyDashboardApproval?: boolean;
hashedBranchLength?: number;
npmrc?: string;
platform?: string;
postUpgradeTasks?: PostUpgradeTasks;
Expand Down
8 changes: 8 additions & 0 deletions lib/config/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1393,6 +1393,14 @@ const options: RenovateOptions[] = [
cli: false,
mergeable: true,
},
{
name: 'hashedBranchLength',
description:
'If enabled, branch names will use a hashing function to ensure each branch has that length.',
type: 'integer',
default: null,
cli: false,
},
// Dependency Groups
{
name: 'groupName',
Expand Down
68 changes: 68 additions & 0 deletions lib/workers/repository/updates/branch-name.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,74 @@ describe('workers/repository/updates/branch-name', () => {
generateBranchName(upgrade);
expect(upgrade.branchName).toEqual('dep');
});

it('realistic defaults', () => {
const upgrade: RenovateConfig = {
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).toEqual('renovate/jest-42.x');
});

it('hashedBranchLength hashing', () => {
const upgrade: RenovateConfig = {
branchName:
'{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}',
branchTopic:
'{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}',
hashedBranchLength: 14,
branchPrefix: 'dep-',
depNameSanitized: 'jest',
newMajor: '42',
group: {},
};
generateBranchName(upgrade);
expect(upgrade.branchName).toEqual('dep-df9ca0f348');
});

it('hashedBranchLength hashing with group name', () => {
const upgrade: RenovateConfig = {
hashedBranchLength: 20,
branchPrefix: 'dep-',
depNameSanitized: 'jest',
newMajor: '42',
groupName: 'some group name',
group: {
branchName:
'{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}',
branchTopic:
'{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}',
},
};
generateBranchName(upgrade);
expect(upgrade.branchName).toEqual('dep-df9ca0f34833f3e0');
});

it('hashedBranchLength too short', () => {
const upgrade: RenovateConfig = {
hashedBranchLength: 3,
branchPrefix: 'dep-',
depNameSanitized: 'jest',
newMajor: '42',
groupName: 'some group name',
group: {
branchName:
'{{{branchPrefix}}}{{{additionalBranchPrefix}}}{{{branchTopic}}}',
branchTopic:
'{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}',
},
};
generateBranchName(upgrade);
expect(upgrade.branchName).toEqual('dep-df9ca0');
});

it('enforces valid git branch name', () => {
const fixtures = [
{
Expand Down
47 changes: 38 additions & 9 deletions lib/workers/repository/updates/branch-name.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { clean as cleanGitRef } from 'clean-git-ref';
import hasha from 'hasha';
import slugify from 'slugify';
import { RenovateConfig } from '../../../config/common';
import { logger } from '../../../logger';
import * as template from '../../../util/template';

const MIN_HASH_LENGTH = 6;

/**
* Clean git branch name
*
Expand Down Expand Up @@ -42,16 +45,42 @@ export function generateBranchName(update: RenovateConfig): void {
update.groupSlug = `patch-${update.groupSlug}`;
}
update.branchTopic = update.group.branchTopic || update.branchTopic;
update.branchName = template.compile(
update.group.branchName || update.branchName,
update
);
update.branchName = update.group.branchName || update.branchName;
}

if (update.hashedBranchLength) {
let hashLength = update.hashedBranchLength - update.branchPrefix.length;
if (hashLength <= MIN_HASH_LENGTH) {
logger.warn(
`\`hashedBranchLength\` must allow for at least ${MIN_HASH_LENGTH} characters hashing in addition to \`branchPrefix\`. Using ${MIN_HASH_LENGTH} character hash instead.`
);
hashLength = MIN_HASH_LENGTH;
}

const additionalBranchPrefix = update.additionalBranchPrefix
? template.compile(String(update.additionalBranchPrefix), update)
: '';

const branchTopic = update.branchTopic
? template.compile(String(update.branchTopic), update)
: '';

let hashInput = additionalBranchPrefix + branchTopic;

// Compile extra times in case of nested templates
hashInput = template.compile(hashInput, update);
hashInput = template.compile(hashInput, update);

const hash = hasha(hashInput);

update.branchName = update.branchPrefix + hash.slice(0, hashLength);
} else {
update.branchName = template.compile(update.branchName, update);

// Compile extra times in case of nested templates
update.branchName = template.compile(update.branchName, update);
update.branchName = template.compile(update.branchName, update);
}
// Compile extra times in case of nested templates
update.branchName = template.compile(update.branchName, update);
update.branchName = cleanBranchName(
template.compile(update.branchName, update)
);

update.branchName = cleanBranchName(update.branchName);
}

0 comments on commit ee178df

Please sign in to comment.