mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-02 18:43:40 +00:00
f2896deaaf
* fix(merge-confidence): don't require auth in `platform=local` When dry-running Renovate against a repository to validate it[0], if a repository is using `matchConfidence`, the whole Renovate run is aborted due to missing API credentials. This can be frustrating, and the workaround available is to temporarily remove all package rules use `matchConfidence`, which isn't the best experience. Instead, we should follow the existing pattern to return `null` when loading a Package Rule with `matchConfidence`, as well as DEBUG logging to inform the user why this is happening. [0]: https://www.jvt.me/posts/2026/03/08/renovate-test-config/ * fixup! fix(merge-confidence): don't validate auth in a With debugging from Claude to work out how to get the test to pass. Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io> --------- Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
1629 lines
42 KiB
TypeScript
1629 lines
42 KiB
TypeScript
import { hostRules } from '~test/util.ts';
|
|
import { GlobalConfig } from '../../config/global.ts';
|
|
import type { PackageRuleInputConfig, UpdateType } from '../../config/types.ts';
|
|
import { MISSING_API_CREDENTIALS } from '../../constants/error-messages.ts';
|
|
import { DockerDatasource } from '../../modules/datasource/docker/index.ts';
|
|
import { OrbDatasource } from '../../modules/datasource/orb/index.ts';
|
|
import type { HostRule } from '../../types/index.ts';
|
|
import type { MergeConfidence } from '../merge-confidence/types.ts';
|
|
import { applyPackageRules } from './index.ts';
|
|
|
|
type TestConfig = PackageRuleInputConfig & {
|
|
x?: number;
|
|
y?: number;
|
|
groupName?: string;
|
|
};
|
|
|
|
describe('util/package-rules/index', () => {
|
|
afterEach(() => {
|
|
GlobalConfig.reset();
|
|
});
|
|
|
|
const config1: TestConfig = {
|
|
foo: 'bar',
|
|
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['a', 'b', 'xyz/**', '!xyz/foo**'],
|
|
// @ts-expect-error -- testing
|
|
x: 2,
|
|
},
|
|
{
|
|
matchPackageNames: ['/a/', '/b/', '!aa', '!/d/'],
|
|
// @ts-expect-error -- testing
|
|
y: 2,
|
|
},
|
|
{
|
|
matchPackageNames: ['xyz/**', '!xyz/foo'],
|
|
groupName: 'xyz',
|
|
},
|
|
],
|
|
};
|
|
|
|
it('applies', async () => {
|
|
const config: PackageRuleInputConfig = {
|
|
packageName: 'a',
|
|
updateType: 'minor',
|
|
isBump: true,
|
|
currentValue: '1.0.0',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['*'],
|
|
matchCurrentVersion: '<= 2.0.0',
|
|
},
|
|
{
|
|
matchPackageNames: ['b'],
|
|
matchCurrentVersion: '<= 2.0.0',
|
|
},
|
|
{
|
|
matchUpdateTypes: ['bump'],
|
|
labels: ['bump'],
|
|
},
|
|
{
|
|
matchPackageNames: ['b', '!a'],
|
|
},
|
|
{
|
|
matchCurrentVersion: '<= 2.0.0',
|
|
},
|
|
],
|
|
};
|
|
await expect(applyPackageRules(config)).resolves.toEqual({
|
|
...config,
|
|
labels: ['bump'],
|
|
});
|
|
});
|
|
|
|
it('applies both rules for a', async () => {
|
|
const dep = {
|
|
packageName: 'a',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBe(2);
|
|
expect(res.y).toBe(2);
|
|
expect(res.groupName).toBeUndefined();
|
|
});
|
|
|
|
it('applies both rules for b', async () => {
|
|
const dep = {
|
|
packageName: 'b',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBe(2);
|
|
expect(res.y).toBe(2);
|
|
expect(res.groupName).toBeUndefined();
|
|
});
|
|
|
|
it('applies the second rule', async () => {
|
|
const dep = {
|
|
packageName: 'abc',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
expect(res.y).toBe(2);
|
|
expect(res.groupName).toBeUndefined();
|
|
});
|
|
|
|
it('applies matchPackageNames', async () => {
|
|
const dep = {
|
|
packageName: 'xyz/foo',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.groupName).toBeUndefined();
|
|
});
|
|
|
|
it('applies the second second rule', async () => {
|
|
const dep = {
|
|
packageName: 'bc',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
expect(res.y).toBe(2);
|
|
});
|
|
|
|
it('excludes package name', async () => {
|
|
const dep = {
|
|
packageName: 'aa',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
expect(res.y).toBeUndefined();
|
|
});
|
|
|
|
it('excludes package pattern', async () => {
|
|
const dep = {
|
|
packageName: 'bcd',
|
|
};
|
|
const res = await applyPackageRules({ ...config1, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
expect(res.y).toBeUndefined();
|
|
});
|
|
|
|
it('ignores patterns if lock file maintenance', async () => {
|
|
const dep = {
|
|
automerge: true,
|
|
updateType: 'lockFileMaintenance' as UpdateType,
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['!/^foo/'],
|
|
automerge: false,
|
|
},
|
|
],
|
|
};
|
|
// This should not match
|
|
const res = await applyPackageRules(dep);
|
|
expect(res.automerge).toBeTrue();
|
|
});
|
|
|
|
it('do apply rule with matchPackageName', async () => {
|
|
const dep = {
|
|
automerge: true,
|
|
updateType: 'lockFileMaintenance' as UpdateType,
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['foo'],
|
|
automerge: false,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep);
|
|
expect(res.automerge).toBeTrue();
|
|
const res2 = await applyPackageRules({ ...dep, packageName: 'foo' });
|
|
expect(res2.automerge).toBeFalse();
|
|
});
|
|
|
|
it('sets skipReason=package-rules if enabled=false', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeFalse();
|
|
expect(res.skipReason).toBe('package-rules');
|
|
expect(res.skipStage).toBe('datasource-merge');
|
|
});
|
|
|
|
it('unsets skipReason=package-rules if enabled=true', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
{
|
|
enabled: true,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeTrue();
|
|
expect(res.skipReason).toBeUndefined();
|
|
expect(res.skipStage).toBeUndefined();
|
|
});
|
|
|
|
it('does not set skipReason=package-rules if the last packageRule has force.enabled=true', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
{
|
|
// this is a vulnerability alert
|
|
force: {
|
|
enabled: true,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeTrue();
|
|
expect(res.skipReason).toBeUndefined();
|
|
expect(res.skipStage).toBeUndefined();
|
|
});
|
|
|
|
it('does not set skipReason=package-rules if the last packageRule has force.enabled=true (if config.enabled=false)', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
enabled: false,
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
{
|
|
// this is a vulnerability alert
|
|
force: {
|
|
enabled: true,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeTrue();
|
|
expect(res.skipReason).toBeUndefined();
|
|
expect(res.skipStage).toBeUndefined();
|
|
});
|
|
|
|
it('does not set skipReason=package-rules if the last packageRule has enabled=true (if config.force.enabled=false)', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
enabled: false,
|
|
// for instance, if we've already merged a vulnrability alert
|
|
force: {
|
|
enabled: true,
|
|
},
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeTrue();
|
|
expect(res.skipReason).toBeUndefined();
|
|
expect(res.skipStage).toBeUndefined();
|
|
});
|
|
|
|
// TODO naming
|
|
|
|
it('sets skipReason=package-rules if the last packageRule has force.enabled=false (if config.force.enabled=false)', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
enabled: false,
|
|
// for instance, if we've already merged a vulnerability alert
|
|
force: {
|
|
enabled: true,
|
|
},
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
{
|
|
force: {
|
|
enabled: false,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeFalse();
|
|
expect(res.skipReason).toBe('package-rules');
|
|
expect(res.skipStage).toBe('datasource-merge');
|
|
});
|
|
|
|
it('sets skipReason=package-rules if the last packageRule has force.enabled=false', async () => {
|
|
const dep: any = {
|
|
depName: 'foo',
|
|
packageRules: [
|
|
{
|
|
enabled: true,
|
|
},
|
|
{
|
|
force: {
|
|
enabled: false,
|
|
},
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep, 'datasource-merge');
|
|
expect(res.enabled).toBeFalse();
|
|
expect(res.skipReason).toBe('package-rules');
|
|
expect(res.skipStage).toBe('datasource-merge');
|
|
});
|
|
|
|
it('skips skipReason=package-rules if enabled=true', async () => {
|
|
const dep: any = {
|
|
enabled: false,
|
|
depName: 'foo',
|
|
packageRules: [
|
|
{
|
|
enabled: false,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(dep);
|
|
expect(res.skipReason).toBeUndefined();
|
|
});
|
|
|
|
it('matches anything if missing inclusive rules', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['!foo'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'foo',
|
|
});
|
|
expect(res1.x).toBeUndefined();
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'bar',
|
|
});
|
|
expect(res2.x).toBeDefined();
|
|
});
|
|
|
|
it('supports inclusive or', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['neutrino', '/^@neutrino\\//'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'neutrino',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: '@neutrino/something',
|
|
});
|
|
expect(res2.x).toBeDefined();
|
|
});
|
|
|
|
it('filters requested depType', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepTypes: ['dependencies', 'peerDependencies'],
|
|
matchPackageNames: ['a'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters from list of requested depTypes', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepTypes: ['test'],
|
|
matchPackageNames: ['a'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depTypes: ['build', 'test'],
|
|
packageName: 'a',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('returns false if no depTypes', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepTypes: ['test'],
|
|
matchPackageNames: ['a'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const input = { ...config, packageName: 'a' };
|
|
delete input.depType;
|
|
delete input.depTypes;
|
|
const res = await applyPackageRules(input);
|
|
expect(res).toEqual(input);
|
|
});
|
|
|
|
it('filters managers with matching manager', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchManagers: ['npm', 'meteor'],
|
|
matchPackageNames: ['node'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
manager: 'meteor',
|
|
packageName: 'node',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters managers with non-matching manager', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchManagers: ['dockerfile', 'npm'],
|
|
matchPackageNames: ['node'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
language: 'python',
|
|
categories: ['python'],
|
|
manager: 'pipenv',
|
|
packageName: 'node',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters categories with matching category', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchCategories: ['node'],
|
|
matchPackageNames: ['node'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
categories: ['javascript', 'node'],
|
|
manager: 'meteor',
|
|
packageName: 'node',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters categories with non-matching category', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchCategories: ['docker'],
|
|
matchPackageNames: ['node'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
categories: ['python'],
|
|
manager: 'pipenv',
|
|
packageName: 'node',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters categories with undefined category', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchCategories: ['docker'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
manager: 'pipenv',
|
|
packageName: 'node',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters datasources with matching datasource', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDatasources: [OrbDatasource.id, DockerDatasource.id],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
{
|
|
matchDatasources: [DockerDatasource.id],
|
|
// @ts-expect-error -- testing
|
|
y: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
datasource: OrbDatasource.id,
|
|
baseBranch: 'master',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
expect(res.y).toBeUndefined();
|
|
});
|
|
|
|
it('filters branches with matching branch', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchBaseBranches: ['master', 'staging'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
datasource: OrbDatasource.id,
|
|
baseBranch: 'master',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters datasources with non-matching datasource', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDatasources: [OrbDatasource.id],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
baseBranch: 'staging',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters branches with non-matching branch', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchBaseBranches: ['master'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
baseBranch: 'staging',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters branches with matching branch regex', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchBaseBranches: ['/^release\\/.*/'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
datasource: OrbDatasource.id,
|
|
baseBranch: 'release/5.8',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters branches with non-matching branch regex', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchBaseBranches: ['/^release\\/.*/'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
datasource: OrbDatasource.id,
|
|
baseBranch: 'master',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('filters updateType', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchUpdateTypes: ['minor', 'patch'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
{
|
|
matchUpdateTypes: ['minor'],
|
|
// @ts-expect-error -- testing
|
|
y: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
expect(res.y).toBeUndefined();
|
|
});
|
|
|
|
it('matches matchSourceUrls with glob', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar**',
|
|
'https://github.com/renovatebot/**',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/renovatebot/presets',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('non-matches matchSourceUrls with globs', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar**',
|
|
'https://github.com/renovatebot/**',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/vuejs/vue',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('handles matchSourceUrls when missing sourceUrl', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar**',
|
|
'https://github.com/renovatebot/**',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('matches matchSourceUrls', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar',
|
|
'https://github.com/renovatebot/presets',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/renovatebot/presets',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('non-matches matchSourceUrls', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar',
|
|
'https://github.com/react/react',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/react/react-native',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('handles matchRegistryUrls when missing registryUrls', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchRegistryUrls: [
|
|
'https://registry.example.com/**',
|
|
'https://private.registry.com/**',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('matches matchRegistryUrls', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchRegistryUrls: [
|
|
'https://registry.example.com',
|
|
'https://private.registry.com/npm',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
registryUrls: ['https://private.registry.com/npm'],
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('non-matches matchRegistryUrls', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchRegistryUrls: [
|
|
'https://registry.example.com',
|
|
'https://private.registry.com/npm',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
registryUrls: ['https://registry.npmjs.org'],
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
describe('matchConfidence', () => {
|
|
const hostRule: HostRule = {
|
|
hostType: 'merge-confidence',
|
|
token: 'some-token',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
hostRules.clear();
|
|
hostRules.add(hostRule);
|
|
});
|
|
|
|
afterEach(() => {
|
|
GlobalConfig.reset();
|
|
});
|
|
|
|
it('matches matchConfidence', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
mergeConfidenceLevel: 'high' as MergeConfidence,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('non-matches matchConfidence', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
mergeConfidenceLevel: 'low' as MergeConfidence,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('does not match matchConfidence when there is no mergeConfidenceLevel', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
mergeConfidenceLevel: undefined,
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('throws when unauthenticated', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchUpdateTypes: ['major'],
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
hostRules.clear();
|
|
|
|
let error = new Error();
|
|
try {
|
|
await applyPackageRules(config);
|
|
} catch (err) {
|
|
error = err;
|
|
}
|
|
|
|
expect(error).toMatchObject(new Error(MISSING_API_CREDENTIALS));
|
|
expect(error.validationError).toBe('Missing credentials');
|
|
expect(error.validationMessage).toBe(
|
|
'The `matchConfidence` matcher in `packageRules` requires authentication. Please refer to the [documentation](https://docs.renovatebot.com/configuration-options/#packagerulesmatchconfidence) and add the required host rule.',
|
|
);
|
|
});
|
|
|
|
it('does not throw when unauthenticated on platform=local', async () => {
|
|
GlobalConfig.set({
|
|
platform: 'local',
|
|
});
|
|
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchUpdateTypes: ['major'],
|
|
matchConfidence: ['high'],
|
|
},
|
|
],
|
|
};
|
|
hostRules.clear();
|
|
|
|
await expect(applyPackageRules(config)).resolves.not.toThrow();
|
|
});
|
|
|
|
it('does not apply the packageRule on platform=local', async () => {
|
|
GlobalConfig.set({
|
|
platform: 'local',
|
|
});
|
|
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchUpdateTypes: ['major'],
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
hostRules.clear();
|
|
|
|
const res = await applyPackageRules(config);
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('uses productLinks.documentation in error message URL', async () => {
|
|
GlobalConfig.set({
|
|
productLinks: { documentation: 'https://custom.example.com/' },
|
|
});
|
|
hostRules.clear();
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchUpdateTypes: ['major'],
|
|
matchConfidence: ['high'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
|
|
await expect(applyPackageRules(config)).rejects.toMatchObject({
|
|
validationMessage:
|
|
'The `matchConfidence` matcher in `packageRules` requires authentication. Please refer to the [documentation](https://custom.example.com/configuration-options/#packagerulesmatchconfidence) and add the required host rule.',
|
|
});
|
|
});
|
|
});
|
|
|
|
it('filters naked depType', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepTypes: ['dependencies', 'peerDependencies'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('filters out unrequested depType', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepTypes: ['dependencies', 'peerDependencies'],
|
|
matchPackageNames: ['a'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'devDependencies',
|
|
packageName: 'a',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector is valid and satisfies the condition on range overlap', async () => {
|
|
const config: TestConfig = {
|
|
versioning: 'semver',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '<= 2.0.0',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '^1.0.0',
|
|
currentVersion: '1.0.3',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '^1.0.0',
|
|
});
|
|
expect(res2.x).toBeUndefined();
|
|
const res3 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
lockedVersion: '^1.0.0',
|
|
});
|
|
expect(res3.x).toBeUndefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector is valid and satisfies the condition on pinned to range overlap', async () => {
|
|
const config: TestConfig = {
|
|
versioning: 'semver',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '>= 2.0.0',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '2.4.6',
|
|
currentVersion: '2.4.6',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector is a version and matches if currentValue is a range', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '2.1.0',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
versioning: 'npm',
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '^2.0.0',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '~2.0.0',
|
|
});
|
|
expect(res2.x).toBeUndefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector works with static values', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '4.6.0',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '4.6.0',
|
|
currentVersion: '4.6.0',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector works with regular expressions', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '/^4/',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '4.6.0',
|
|
currentVersion: '4.6.0',
|
|
});
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '5.6.0',
|
|
currentVersion: '5.6.0',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
expect(res2.x).toBeUndefined();
|
|
});
|
|
|
|
it('checks if matchCurrentVersion selector works with negated regular expressions', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['test'],
|
|
matchCurrentVersion: '!/^4/',
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '4.6.0',
|
|
currentVersion: '4.6.0',
|
|
});
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
currentValue: '5.6.0',
|
|
currentVersion: '5.6.0',
|
|
});
|
|
expect(res1.x).toBeUndefined();
|
|
expect(res2.x).toBeDefined();
|
|
});
|
|
|
|
it('matches packageFiles', async () => {
|
|
const config: TestConfig = {
|
|
packageFile: 'examples/foo/package.json',
|
|
packageRules: [
|
|
{
|
|
matchFileNames: ['package.json'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
});
|
|
expect(res1.x).toBeUndefined();
|
|
config.packageFile = 'package.json';
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
});
|
|
expect(res2.x).toBeDefined();
|
|
});
|
|
|
|
it('matches lock files', async () => {
|
|
const config: TestConfig = {
|
|
packageFile: 'examples/foo/package.json',
|
|
lockFiles: ['yarn.lock'],
|
|
packageRules: [
|
|
{
|
|
matchFileNames: ['yarn.lock'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.x).toBeDefined();
|
|
});
|
|
|
|
it('matches paths', async () => {
|
|
const config: TestConfig = {
|
|
packageFile: 'examples/foo/package.json',
|
|
packageRules: [
|
|
{
|
|
matchFileNames: ['examples/**', 'lib/'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
});
|
|
expect(res1.x).toBeDefined();
|
|
config.packageFile = 'package.json';
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
});
|
|
expect(res2.x).toBeUndefined();
|
|
config.packageFile = 'lib/a/package.json';
|
|
const res3 = await applyPackageRules({
|
|
...config,
|
|
packageName: 'test',
|
|
});
|
|
expect(res3.x).toBeUndefined();
|
|
});
|
|
|
|
it('empty rules', async () => {
|
|
await expect(
|
|
applyPackageRules({ ...config1, packageRules: null as never }),
|
|
).resolves.toEqual({
|
|
foo: 'bar',
|
|
packageRules: null,
|
|
});
|
|
});
|
|
|
|
it('creates groupSlug if necessary', async () => {
|
|
const config: TestConfig = {
|
|
packageName: 'foo',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['*'],
|
|
groupName: 'A',
|
|
groupSlug: 'a',
|
|
},
|
|
{
|
|
matchPackageNames: ['*'],
|
|
groupName: 'B',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.groupSlug).toBe('b');
|
|
});
|
|
|
|
it('matches matchSourceUrls with patterns (case-insensitive)', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar**',
|
|
'https://github.com/Renovatebot/**',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/renovatebot/Presets',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('matches matchSourceUrls(case-insensitive)', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchSourceUrls: [
|
|
'https://github.com/foo/bar',
|
|
'https://github.com/Renovatebot/renovate',
|
|
],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
depType: 'dependencies',
|
|
packageName: 'a',
|
|
updateType: 'patch' as UpdateType,
|
|
sourceUrl: 'https://github.com/renovatebot/Renovate',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('needs language to match', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['abc'],
|
|
matchCategories: ['js'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
packageName: 'abc',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('needs baseBranch to match', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['abc'],
|
|
matchBaseBranches: ['dev'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
packageName: 'abc',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('needs manager to match', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['abc'],
|
|
matchManagers: ['npm'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
const dep = {
|
|
packageName: 'abc',
|
|
};
|
|
const res = await applyPackageRules({ ...config, ...dep });
|
|
expect(res.x).toBeUndefined();
|
|
});
|
|
|
|
it('matches matchDepNames(depName)', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
matchDepNames: ['test1'],
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
|
|
const res1 = await applyPackageRules({
|
|
...config,
|
|
depName: 'test1',
|
|
});
|
|
const res2 = await applyPackageRules({
|
|
...config,
|
|
depName: 'test2',
|
|
});
|
|
await applyPackageRules(config); // coverage
|
|
|
|
expect(res1.x).toBe(1);
|
|
expect(res2.x).toBeUndefined();
|
|
});
|
|
|
|
it('matches if there are no matchers', async () => {
|
|
const config: TestConfig = {
|
|
packageRules: [
|
|
{
|
|
// @ts-expect-error -- testing
|
|
x: 1,
|
|
},
|
|
],
|
|
};
|
|
|
|
const res = await applyPackageRules({
|
|
...config,
|
|
depName: 'test2',
|
|
});
|
|
|
|
expect(res.x).toBe(1);
|
|
});
|
|
|
|
it('overrides', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'npm',
|
|
depName: 'foo',
|
|
packageName: 'bar',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['npm'],
|
|
matchDepNames: ['foo'],
|
|
overridePackageName: 'baz',
|
|
},
|
|
{
|
|
matchDatasources: ['npm'],
|
|
matchPackageNames: ['baz'],
|
|
overrideDepName: 'f',
|
|
},
|
|
{
|
|
matchDepNames: ['f'],
|
|
overrideDatasource: 'composer',
|
|
},
|
|
{
|
|
matchDatasources: ['composer'],
|
|
matchDepNames: ['f'],
|
|
matchPackageNames: ['baz'],
|
|
enabled: false,
|
|
},
|
|
],
|
|
};
|
|
let res = await applyPackageRules(config);
|
|
expect(res.packageName).toBe('baz');
|
|
res = await applyPackageRules(res);
|
|
expect(res.depName).toBe('f');
|
|
res = await applyPackageRules(res);
|
|
expect(res.datasource).toBe('composer');
|
|
res = await applyPackageRules(res);
|
|
expect(res).toMatchObject({
|
|
datasource: 'composer',
|
|
depName: 'f',
|
|
packageName: 'baz',
|
|
enabled: false,
|
|
});
|
|
});
|
|
|
|
it('overrides with templates', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'docker',
|
|
depName: 'docker.io/library/node',
|
|
packageName: 'docker.io/library/node',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['docker'],
|
|
overrideDepName: '{{replace "docker.io/library/" "" depName}}',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.depName).toBe('node');
|
|
expect(res.packageName).toBe('docker.io/library/node');
|
|
});
|
|
|
|
it('propagates fetchChangeLogs from matching packageRule', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'npm',
|
|
depName: 'some-dep',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['npm'],
|
|
fetchChangeLogs: 'off',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.fetchChangeLogs).toBe('off');
|
|
});
|
|
|
|
it('does not set fetchChangeLogs when packageRule does not match', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'npm',
|
|
depName: 'some-dep',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['pypi'],
|
|
fetchChangeLogs: 'off',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res).not.toHaveProperty('fetchChangeLogs');
|
|
});
|
|
|
|
it('compiles sourceUrl with template helper functions', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'terraform-provider',
|
|
depName: 'aws',
|
|
packageName: 'hashicorp/aws',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['terraform-provider'],
|
|
sourceUrl:
|
|
'https://github.com/{{replace "/" "/terraform-provider-" packageName}}',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.sourceUrl).toBe(
|
|
'https://github.com/hashicorp/terraform-provider-aws',
|
|
);
|
|
});
|
|
|
|
it('compiles sourceUrl with template variables', async () => {
|
|
const config: TestConfig = {
|
|
datasource: 'terraform-provider',
|
|
depName: 'aws',
|
|
packageName: 'hashicorp/aws',
|
|
packageRules: [
|
|
{
|
|
matchDatasources: ['terraform-provider'],
|
|
sourceUrl: 'https://github.com/{{packageName}}',
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.sourceUrl).toBe('https://github.com/hashicorp/aws');
|
|
});
|
|
|
|
describe('packageRules array handling', () => {
|
|
it('returns the input packageRules array without re-cloning it', async () => {
|
|
const config: TestConfig = {
|
|
packageName: 'a',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['a'],
|
|
// @ts-expect-error -- testing
|
|
x: 2,
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.x).toBe(2);
|
|
expect(res.packageRules).toBe(config.packageRules);
|
|
});
|
|
|
|
it('does not add a packageRules key when the input has none', async () => {
|
|
const config: PackageRuleInputConfig = { packageName: 'a' };
|
|
const res = await applyPackageRules(config);
|
|
expect(res.packageRules).toBeUndefined();
|
|
});
|
|
|
|
it('keeps an empty packageRules array', async () => {
|
|
const config: PackageRuleInputConfig = {
|
|
packageName: 'a',
|
|
packageRules: [],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.packageRules).toBe(config.packageRules);
|
|
});
|
|
|
|
it('appends nested packageRules carried by an applied rule', async () => {
|
|
const nestedRule = {
|
|
matchPackageNames: ['b'],
|
|
y: 3,
|
|
};
|
|
const config: TestConfig = {
|
|
packageName: 'a',
|
|
packageRules: [
|
|
{
|
|
matchPackageNames: ['a'],
|
|
packageRules: [nestedRule],
|
|
},
|
|
],
|
|
};
|
|
const res = await applyPackageRules(config);
|
|
expect(res.packageRules).toHaveLength(2);
|
|
expect(res.packageRules![1]).toEqual(nestedRule);
|
|
});
|
|
});
|
|
});
|