Skip to content

Commit

Permalink
feat(config): allow multiple branch/pr limits (#32556)
Browse files Browse the repository at this point in the history
  • Loading branch information
RahulGautamSingh authored Jan 21, 2025
1 parent bc20797 commit 03f2229
Show file tree
Hide file tree
Showing 10 changed files with 530 additions and 252 deletions.
1 change: 1 addition & 0 deletions lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export interface RenovateConfig
packageFile?: string;
packageRules?: PackageRule[];
postUpdateOptions?: string[];
branchConcurrentLimit?: number | null;
prConcurrentLimit?: number;
prHourlyLimit?: number;
forkModeDisallowMaintainerEdits?: boolean;
Expand Down
244 changes: 244 additions & 0 deletions lib/workers/global/limits.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { partial } from '../../../test/util';
import type { BranchConfig, BranchUpgradeConfig } from '../types';
import {
calcLimit,
hasMultipleLimits,
incCountValue,
incLimitedValue,
isLimitReached,
resetAllLimits,
setCount,
setMaxLimit,
} from './limits';

Expand Down Expand Up @@ -60,4 +66,242 @@ describe('workers/global/limits', () => {
setMaxLimit('Commits', -1000);
expect(isLimitReached('Commits')).toBeTrue();
});

describe('calcLimit', () => {
it('handles single upgrade', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
]);

expect(calcLimit(upgrades, 'prHourlyLimit')).toBe(10);
expect(calcLimit(upgrades, 'branchConcurrentLimit')).toBe(11);
expect(calcLimit(upgrades, 'prConcurrentLimit')).toBe(12);
});

it('inherits prConcurrentLimit if branchConcurrentLimit is null', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: null,
prConcurrentLimit: 12,
},
]);

expect(calcLimit(upgrades, 'prHourlyLimit')).toBe(10);
expect(calcLimit(upgrades, 'branchConcurrentLimit')).toBe(12);
expect(calcLimit(upgrades, 'prConcurrentLimit')).toBe(12);
});

it('returns 0 if atleast one upgrade has no limit in the branch', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 0,
branchConcurrentLimit: 0,
prConcurrentLimit: 0,
},
{
prHourlyLimit: 1,
branchConcurrentLimit: 1,
prConcurrentLimit: 1,
},
]);

expect(calcLimit(upgrades, 'prHourlyLimit')).toBe(0);
expect(calcLimit(upgrades, 'branchConcurrentLimit')).toBe(0);
expect(calcLimit(upgrades, 'prConcurrentLimit')).toBe(0);
});

it('computes the lowest limit if multiple limits are present', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 1,
branchConcurrentLimit: 1,
prConcurrentLimit: 1,
},
{
prHourlyLimit: 5,
branchConcurrentLimit: 6,
prConcurrentLimit: 3,
},
{
prHourlyLimit: 5,
branchConcurrentLimit: null,
prConcurrentLimit: undefined,
},
{
prHourlyLimit: 5,
branchConcurrentLimit: 6,
prConcurrentLimit: 2,
},
]);

expect(calcLimit(upgrades, 'prHourlyLimit')).toBe(1);
expect(calcLimit(upgrades, 'branchConcurrentLimit')).toBe(1);
expect(calcLimit(upgrades, 'prConcurrentLimit')).toBe(1);
});
});

describe('hasMultipleLimits', () => {
it('handles single limit', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
]);
expect(hasMultipleLimits(upgrades, 'prHourlyLimit')).toBe(false);
expect(hasMultipleLimits(upgrades, 'branchConcurrentLimit')).toBe(false);
expect(hasMultipleLimits(upgrades, 'prConcurrentLimit')).toBe(false);
});

it('returns false if there are multiple limits with value', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
]);
expect(hasMultipleLimits(upgrades, 'prHourlyLimit')).toBe(false);
expect(hasMultipleLimits(upgrades, 'branchConcurrentLimit')).toBe(false);
expect(hasMultipleLimits(upgrades, 'prConcurrentLimit')).toBe(false);
});

it('handles multiple limits', () => {
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 11,
branchConcurrentLimit: 12,
prConcurrentLimit: 13,
},
{
prHourlyLimit: 0,
branchConcurrentLimit: null,
prConcurrentLimit: 3,
},
]);
expect(hasMultipleLimits(upgrades, 'prHourlyLimit')).toBe(true);
expect(hasMultipleLimits(upgrades, 'branchConcurrentLimit')).toBe(true);
expect(hasMultipleLimits(upgrades, 'prConcurrentLimit')).toBe(true);
});
});

describe('isLimitReached', () => {
it('returns false based on concurrent limits', () => {
setCount('ConcurrentPRs', 1);
setCount('HourlyPRs', 1);
incCountValue('Branches'); // using incCountValue so it gets test coverage
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 11,
branchConcurrentLimit: 12,
prConcurrentLimit: 13,
},
{
prHourlyLimit: 0,
branchConcurrentLimit: null,
prConcurrentLimit: 3,
},
]);
expect(
isLimitReached('Branches', partial<BranchConfig>({ upgrades })),
).toBe(false);
expect(
isLimitReached('ConcurrentPRs', partial<BranchConfig>({ upgrades })),
).toBe(false);
});

it('returns true when hourly limit is reached', () => {
setCount('Branches', 2);
setCount('ConcurrentPRs', 2);
setCount('HourlyPRs', 2);
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 11,
branchConcurrentLimit: 12,
prConcurrentLimit: 13,
},
{
prHourlyLimit: 2,
branchConcurrentLimit: null,
prConcurrentLimit: 3,
},
]);
expect(
isLimitReached('Branches', partial<BranchConfig>({ upgrades })),
).toBe(true);
expect(
isLimitReached('ConcurrentPRs', partial<BranchConfig>({ upgrades })),
).toBe(true);
});

it('returns true when concurrent limit is reached', () => {
setCount('Branches', 3);
setCount('ConcurrentPRs', 3);
setCount('HourlyPRs', 4);
const upgrades = partial<BranchUpgradeConfig>([
{
prHourlyLimit: 10,
branchConcurrentLimit: 11,
prConcurrentLimit: 12,
},
{
prHourlyLimit: 11,
branchConcurrentLimit: 12,
prConcurrentLimit: 13,
},
{
prHourlyLimit: 5,
branchConcurrentLimit: null,
prConcurrentLimit: 3,
},
]);
expect(
isLimitReached('Branches', partial<BranchConfig>({ upgrades })),
).toBe(true);
expect(
isLimitReached('ConcurrentPRs', partial<BranchConfig>({ upgrades })),
).toBe(true);
});
});
});
Loading

0 comments on commit 03f2229

Please sign in to comment.