test(coverage): lib/config (#5656)

This commit is contained in:
Michael Kriese 2020-03-07 11:27:10 +01:00 committed by GitHub
parent 8ac0f571ff
commit e779d895f7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 840 additions and 48 deletions

View file

@ -1,5 +1,589 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`config/index mergeChildConfig(parentConfig, childConfig) filterConfig() 1`] = `
Object {
"additionalReviewers": Array [],
"aliases": Object {},
"allowedPostUpgradeCommands": Array [],
"assignAutomerge": false,
"assignees": Array [],
"assigneesSampleSize": null,
"automerge": false,
"automergeComment": "automergeComment",
"automergeType": "pr",
"azureAutoComplete": false,
"azureWorkItemId": 0,
"baseDir": null,
"bbUseDefaultReviewers": true,
"binarySource": "auto",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
"branchTopic": "{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}",
"bumpVersion": null,
"cacheDir": null,
"commitBody": null,
"commitBodyTable": false,
"commitMessage": "{{{commitMessagePrefix}}} {{{commitMessageAction}}} {{{commitMessageTopic}}} {{{commitMessageExtra}}} {{{commitMessageSuffix}}}",
"commitMessageAction": "Update",
"commitMessageExtra": "to {{#if isMajor}}v{{{newMajor}}}{{else}}{{#if isSingleVersion}}v{{{toVersion}}}{{else}}{{{newValue}}}{{/if}}{{/if}}",
"commitMessagePrefix": null,
"commitMessageSuffix": null,
"commitMessageTopic": "dependency {{depName}}",
"compatibility": Object {},
"configWarningReuseIssue": true,
"dockerMapDotfiles": false,
"dockerUser": null,
"dryRun": false,
"excludeCommitPaths": Array [],
"gitAuthor": null,
"gitLabAutomerge": false,
"gitPrivateKey": null,
"group": Object {
"branchTopic": "{{{groupSlug}}}",
"commitMessageTopic": "{{{groupName}}}",
},
"groupName": null,
"groupSlug": null,
"ignoreNpmrcFile": false,
"labels": Array [],
"lazyGrouping": true,
"managerBranchPrefix": "",
"masterIssue": false,
"masterIssueApproval": false,
"masterIssueAutoclose": false,
"masterIssueTitle": "Update Dependencies (Renovate Bot)",
"onboardingBranch": "renovate/configure",
"onboardingPrTitle": "Configure Renovate",
"persistRepoData": false,
"platform": "github",
"postUpdateOptions": Array [],
"postUpgradeTasks": Object {
"commands": Array [],
"fileFilters": Array [],
},
"prBodyColumns": Array [
"Package",
"Type",
"Update",
"Change",
],
"prBodyDefinitions": Object {
"Change": "\`{{{displayFrom}}}\` -> \`{{{displayTo}}}\`",
"Current value": "{{{currentValue}}}",
"New value": "{{{newValue}}}",
"Package": "{{{depNameLinked}}}",
"Package file": "{{{packageFile}}}",
"References": "{{{references}}}",
"Type": "{{{depType}}}",
"Update": "{{{updateType}}}",
},
"prBodyNotes": Array [],
"prConcurrentLimit": 0,
"prCreation": "immediate",
"prHourlyLimit": 0,
"prNotPendingHours": 25,
"prPriority": 0,
"prTitle": null,
"printConfig": false,
"productLinks": Object {
"documentation": "https://docs.renovatebot.com/",
"help": "https://github.com/renovatebot/config-help/issues",
"homepage": "https://github.com/renovatebot/renovate",
},
"pruneStaleBranches": true,
"rangeStrategy": "replace",
"rebaseLabel": "rebase",
"rebaseWhen": "auto",
"recreateClosed": false,
"requiredStatusChecks": Array [],
"reviewers": Array [],
"reviewersSampleSize": null,
"rollbackPrs": false,
"schedule": Array [
"at any time",
],
"semanticCommitScope": "deps",
"semanticCommitType": "chore",
"semanticCommits": null,
"separateMajorMinor": true,
"separateMinorPatch": false,
"skipInstalls": null,
"stabilityDays": 0,
"statusCheckVerify": false,
"suppressNotifications": Array [
"deprecationWarningIssues",
],
"timezone": null,
"unicodeEmoji": false,
"unpublishSafe": false,
"updateLockFiles": true,
"versioning": "semver",
"vulnerabilityAlerts": Object {
"commitMessageSuffix": "[SECURITY]",
"groupName": null,
"masterIssueApproval": false,
"rangeStrategy": "update-lockfile",
"schedule": Array [],
},
}
`;
exports[`config/index mergeChildConfig(parentConfig, childConfig) getManagerConfig() 1`] = `
Object {
"additionalReviewers": Array [],
"aliases": Object {},
"allowedPostUpgradeCommands": Array [],
"assignAutomerge": false,
"assignees": Array [],
"assigneesSampleSize": null,
"autodiscover": false,
"autodiscoverFilter": null,
"automerge": false,
"automergeComment": "automergeComment",
"automergeType": "pr",
"azureAutoComplete": false,
"azureWorkItemId": 0,
"baseBranches": Array [],
"baseDir": null,
"bbUseDefaultReviewers": true,
"binarySource": "auto",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
"branchPrefix": "renovate/",
"branchTopic": "{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}",
"bumpVersion": null,
"cacheDir": null,
"commitBody": null,
"commitBodyTable": false,
"commitMessage": "{{{commitMessagePrefix}}} {{{commitMessageAction}}} {{{commitMessageTopic}}} {{{commitMessageExtra}}} {{{commitMessageSuffix}}}",
"commitMessageAction": "Update",
"commitMessageExtra": "to {{#if isMajor}}v{{{newMajor}}}{{else}}{{#if isSingleVersion}}v{{{toVersion}}}{{else}}{{{newValue}}}{{/if}}{{/if}}",
"commitMessagePrefix": null,
"commitMessageSuffix": null,
"commitMessageTopic": "dependency {{depName}}",
"compatibility": Object {},
"configWarningReuseIssue": true,
"description": Array [],
"digest": Object {
"branchTopic": "{{{depNameSanitized}}}-digest",
"commitMessageExtra": "to {{newDigestShort}}",
"commitMessageTopic": "{{{depName}}} commit hash",
},
"dockerMapDotfiles": false,
"dockerUser": null,
"dryRun": false,
"enabled": true,
"enabledManagers": Array [],
"encrypted": null,
"endpoint": null,
"excludeCommitPaths": Array [],
"extends": Array [],
"fileMatch": Array [
"(^|/)package.json$",
],
"followTag": null,
"force": null,
"forceCli": true,
"forkMode": false,
"gitAuthor": null,
"gitLabAutomerge": false,
"gitPrivateKey": null,
"group": Object {
"branchTopic": "{{{groupSlug}}}",
"commitMessageTopic": "{{{groupName}}}",
},
"groupName": null,
"groupSlug": null,
"hostRules": Array [
Object {
"timeout": 60000,
},
],
"ignoreDeprecated": true,
"ignoreDeps": Array [],
"ignoreNpmrcFile": false,
"ignorePaths": Array [
"**/node_modules/**",
"**/bower_components/**",
],
"ignorePresets": Array [],
"ignoreScripts": false,
"ignoreUnstable": true,
"includeForks": false,
"includePaths": Array [],
"java": Object {},
"labels": Array [],
"language": "js",
"lazyGrouping": true,
"lockFileMaintenance": Object {
"branchTopic": "lock-file-maintenance",
"commitMessageAction": "Lock file maintenance",
"commitMessageExtra": null,
"commitMessageTopic": null,
"enabled": false,
"groupName": null,
"prBodyDefinitions": Object {
"Change": "All locks refreshed",
},
"rebaseStalePrs": true,
"recreateClosed": true,
"schedule": Array [
"before 5am on monday",
],
},
"logContext": null,
"logFile": null,
"logFileLevel": "debug",
"logLevel": "info",
"major": Object {},
"manager": "npm",
"managerBranchPrefix": "",
"masterIssue": false,
"masterIssueApproval": false,
"masterIssueAutoclose": false,
"masterIssueTitle": "Update Dependencies (Renovate Bot)",
"minor": Object {},
"npmToken": null,
"npmrc": null,
"onboarding": true,
"onboardingBranch": "renovate/configure",
"onboardingConfig": Object {
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
},
"onboardingPrTitle": "Configure Renovate",
"optimizeForDisabled": false,
"packageRules": Array [],
"password": null,
"patch": Object {},
"persistRepoData": false,
"pin": Object {
"commitMessageAction": "Pin",
"group": Object {
"commitMessageExtra": "",
"commitMessageTopic": "dependencies",
},
"groupName": "Pin Dependencies",
"groupSlug": "pin-dependencies",
"rebaseWhen": "behind-base-branch",
"recreateClosed": true,
"unpublishSafe": false,
},
"pinDigests": false,
"platform": "github",
"postUpdateOptions": Array [],
"postUpgradeTasks": Object {
"commands": Array [],
"fileFilters": Array [],
},
"prBodyColumns": Array [
"Package",
"Type",
"Update",
"Change",
],
"prBodyDefinitions": Object {
"Change": "[{{#if displayFrom}}\`{{{displayFrom}}}\` -> {{else}}{{#if currentValue}}\`{{{currentValue}}}\` -> {{/if}}{{/if}}{{#if displayTo}}\`{{{displayTo}}}\`{{else}}\`{{{newValue}}}\`{{/if}}](https://renovatebot.com/diffs/npm/{{{depNameEscaped}}}/{{{fromVersion}}}/{{{toVersion}}})",
"Current value": "{{{currentValue}}}",
"New value": "{{{newValue}}}",
"Package": "{{{depNameLinked}}}",
"Package file": "{{{packageFile}}}",
"References": "{{{references}}}",
"Type": "{{{depType}}}",
"Update": "{{{updateType}}}",
},
"prBodyNotes": Array [],
"prCommitsPerRunLimit": 0,
"prConcurrentLimit": 0,
"prCreation": "immediate",
"prFooter": "This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
"prHourlyLimit": 0,
"prNotPendingHours": 25,
"prPriority": 0,
"prTitle": null,
"printConfig": false,
"privateKey": null,
"productLinks": Object {
"documentation": "https://docs.renovatebot.com/",
"help": "https://github.com/renovatebot/config-help/issues",
"homepage": "https://github.com/renovatebot/renovate",
},
"pruneStaleBranches": true,
"rangeStrategy": "replace",
"rebaseLabel": "rebase",
"rebaseWhen": "auto",
"recreateClosed": false,
"regexManagers": Array [],
"registryUrls": null,
"repositories": Array [],
"requireConfig": true,
"requiredStatusChecks": Array [],
"respectLatest": true,
"reviewers": Array [],
"reviewersSampleSize": null,
"rollbackPrs": true,
"schedule": Array [
"at any time",
],
"semanticCommitScope": "deps",
"semanticCommitType": "chore",
"semanticCommits": null,
"separateMajorMinor": true,
"separateMinorPatch": false,
"separateMultipleMajor": false,
"skipInstalls": null,
"stabilityDays": 0,
"statusCheckVerify": false,
"supportPolicy": Array [],
"suppressNotifications": Array [
"deprecationWarningIssues",
],
"timezone": null,
"token": null,
"trustLevel": "low",
"unicodeEmoji": false,
"unpublishSafe": false,
"updateLockFiles": true,
"updateNotScheduled": true,
"username": null,
"versioning": "npm",
"vulnerabilityAlerts": Object {
"commitMessageSuffix": "[SECURITY]",
"groupName": null,
"masterIssueApproval": false,
"rangeStrategy": "update-lockfile",
"schedule": Array [],
},
"yarnrc": null,
}
`;
exports[`config/index mergeChildConfig(parentConfig, childConfig) getManagerConfig() 2`] = `
Object {
"additionalReviewers": Array [],
"aliases": Object {},
"allowedPostUpgradeCommands": Array [],
"assignAutomerge": false,
"assignees": Array [],
"assigneesSampleSize": null,
"autodiscover": false,
"autodiscoverFilter": null,
"automerge": false,
"automergeComment": "automergeComment",
"automergeType": "pr",
"azureAutoComplete": false,
"azureWorkItemId": 0,
"baseBranches": Array [],
"baseDir": null,
"bbUseDefaultReviewers": true,
"binarySource": "auto",
"branchName": "{{{branchPrefix}}}{{{managerBranchPrefix}}}{{{branchTopic}}}",
"branchPrefix": "renovate/",
"branchTopic": "{{{depNameSanitized}}}-{{{newMajor}}}{{#if isPatch}}.{{{newMinor}}}{{/if}}.x{{#if isLockfileUpdate}}-lockfile{{/if}}",
"bumpVersion": null,
"cacheDir": null,
"commitBody": null,
"commitBodyTable": false,
"commitMessage": "{{{commitMessagePrefix}}} {{{commitMessageAction}}} {{{commitMessageTopic}}} {{{commitMessageExtra}}} {{{commitMessageSuffix}}}",
"commitMessageAction": "Update",
"commitMessageExtra": "to {{#if isMajor}}v{{{newMajor}}}{{else}}{{#if isSingleVersion}}v{{{toVersion}}}{{else}}{{{newValue}}}{{/if}}{{/if}}",
"commitMessagePrefix": null,
"commitMessageSuffix": null,
"commitMessageTopic": "dependency {{depName}}",
"compatibility": Object {},
"configWarningReuseIssue": true,
"description": Array [],
"digest": Object {
"branchTopic": "{{{depNameSanitized}}}-digest",
"commitMessageExtra": "to {{newDigestShort}}",
"commitMessageTopic": "{{{depName}}} commit hash",
"enabled": false,
},
"dockerMapDotfiles": false,
"dockerUser": null,
"dryRun": false,
"enabled": true,
"enabledManagers": Array [],
"encrypted": null,
"endpoint": null,
"excludeCommitPaths": Array [],
"extends": Array [],
"fileMatch": Array [
"\\\\.html?$",
],
"followTag": null,
"force": null,
"forceCli": true,
"forkMode": false,
"gitAuthor": null,
"gitLabAutomerge": false,
"gitPrivateKey": null,
"group": Object {
"branchTopic": "{{{groupSlug}}}",
"commitMessageTopic": "{{{groupName}}}",
},
"groupName": null,
"groupSlug": null,
"hostRules": Array [
Object {
"timeout": 60000,
},
],
"ignoreDeprecated": true,
"ignoreDeps": Array [],
"ignoreNpmrcFile": false,
"ignorePaths": Array [
"**/node_modules/**",
"**/bower_components/**",
],
"ignorePresets": Array [],
"ignoreScripts": false,
"ignoreUnstable": true,
"includeForks": false,
"includePaths": Array [],
"java": Object {},
"labels": Array [],
"language": undefined,
"lazyGrouping": true,
"lockFileMaintenance": Object {
"branchTopic": "lock-file-maintenance",
"commitMessageAction": "Lock file maintenance",
"commitMessageExtra": null,
"commitMessageTopic": null,
"enabled": false,
"groupName": null,
"prBodyDefinitions": Object {
"Change": "All locks refreshed",
},
"rebaseStalePrs": true,
"recreateClosed": true,
"schedule": Array [
"before 5am on monday",
],
},
"logContext": null,
"logFile": null,
"logFileLevel": "debug",
"logLevel": "info",
"major": Object {},
"manager": "html",
"managerBranchPrefix": "",
"masterIssue": false,
"masterIssueApproval": false,
"masterIssueAutoclose": false,
"masterIssueTitle": "Update Dependencies (Renovate Bot)",
"minor": Object {},
"npmToken": null,
"npmrc": null,
"onboarding": true,
"onboardingBranch": "renovate/configure",
"onboardingConfig": Object {
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
},
"onboardingPrTitle": "Configure Renovate",
"optimizeForDisabled": false,
"packageRules": Array [],
"password": null,
"patch": Object {},
"persistRepoData": false,
"pin": Object {
"commitMessageAction": "Pin",
"group": Object {
"commitMessageExtra": "",
"commitMessageTopic": "dependencies",
},
"groupName": "Pin Dependencies",
"groupSlug": "pin-dependencies",
"rebaseWhen": "behind-base-branch",
"recreateClosed": true,
"unpublishSafe": false,
},
"pinDigests": false,
"platform": "github",
"postUpdateOptions": Array [],
"postUpgradeTasks": Object {
"commands": Array [],
"fileFilters": Array [],
},
"prBodyColumns": Array [
"Package",
"Type",
"Update",
"Change",
],
"prBodyDefinitions": Object {
"Change": "\`{{{displayFrom}}}\` -> \`{{{displayTo}}}\`",
"Current value": "{{{currentValue}}}",
"New value": "{{{newValue}}}",
"Package": "{{{depNameLinked}}}",
"Package file": "{{{packageFile}}}",
"References": "{{{references}}}",
"Type": "{{{depType}}}",
"Update": "{{{updateType}}}",
},
"prBodyNotes": Array [],
"prCommitsPerRunLimit": 0,
"prConcurrentLimit": 0,
"prCreation": "immediate",
"prFooter": "This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).",
"prHourlyLimit": 0,
"prNotPendingHours": 25,
"prPriority": 0,
"prTitle": null,
"printConfig": false,
"privateKey": null,
"productLinks": Object {
"documentation": "https://docs.renovatebot.com/",
"help": "https://github.com/renovatebot/config-help/issues",
"homepage": "https://github.com/renovatebot/renovate",
},
"pruneStaleBranches": true,
"rangeStrategy": "replace",
"rebaseLabel": "rebase",
"rebaseWhen": "auto",
"recreateClosed": false,
"regexManagers": Array [],
"registryUrls": null,
"repositories": Array [],
"requireConfig": true,
"requiredStatusChecks": Array [],
"respectLatest": true,
"reviewers": Array [],
"reviewersSampleSize": null,
"rollbackPrs": false,
"schedule": Array [
"at any time",
],
"semanticCommitScope": "deps",
"semanticCommitType": "chore",
"semanticCommits": null,
"separateMajorMinor": true,
"separateMinorPatch": false,
"separateMultipleMajor": false,
"skipInstalls": null,
"stabilityDays": 0,
"statusCheckVerify": false,
"supportPolicy": Array [],
"suppressNotifications": Array [
"deprecationWarningIssues",
],
"timezone": null,
"token": null,
"trustLevel": "low",
"unicodeEmoji": false,
"unpublishSafe": false,
"updateLockFiles": true,
"updateNotScheduled": true,
"username": null,
"versioning": "semver",
"vulnerabilityAlerts": Object {
"commitMessageSuffix": "[SECURITY]",
"groupName": null,
"masterIssueApproval": false,
"rangeStrategy": "update-lockfile",
"schedule": Array [],
},
"yarnrc": null,
}
`;
exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = ` exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = `
Object { Object {
"branchTopic": "lock-file-maintenance", "branchTopic": "lock-file-maintenance",

View file

@ -27,3 +27,9 @@ Object {
"warnings": Array [], "warnings": Array [],
} }
`; `;
exports[`config/migrate-validate migrateAndValidate() isOnboarded 1`] = `
Object {
"errors": Array [],
}
`;

View file

@ -294,6 +294,18 @@ Object {
} }
`; `;
exports[`config/migration migrateConfig(config, parentConfig) it removes invalid configs 1`] = `
Object {
"baseBranches": Array [],
"commitMessage": "test",
"ignorePaths": Array [],
"includePaths": Array [
"test",
],
"rebaseWhen": "auto",
}
`;
exports[`config/migration migrateConfig(config, parentConfig) migrates before and after schedules 1`] = ` exports[`config/migration migrateConfig(config, parentConfig) migrates before and after schedules 1`] = `
Object { Object {
"major": Object { "major": Object {

View file

@ -0,0 +1,13 @@
import { getOptions } from './definitions';
import { getName } from '../../test/util';
jest.mock('../manager', () => ({
getManagers: jest.fn(() => ({ testManager: {} })),
}));
describe(getName(__filename), () => {
it('test manager should have no defaultConfig', () => {
const opts = getOptions();
expect(opts.filter(o => o.name === 'testManager')).toEqual([]);
});
});

View file

@ -14,12 +14,11 @@ describe('config/index', () => {
describe('.parseConfigs(env, defaultArgv)', () => { describe('.parseConfigs(env, defaultArgv)', () => {
let configParser: typeof import('.'); let configParser: typeof import('.');
let defaultArgv: string[]; let defaultArgv: string[];
beforeEach(() => { beforeEach(async () => {
jest.resetModules(); jest.resetModules();
configParser = require('./index'); configParser = await import('./index');
defaultArgv = getArgv(); defaultArgv = getArgv();
jest.mock('delay'); jest.mock('delay', () => Promise.resolve());
require('delay').mockImplementation(() => Promise.resolve());
}); });
it('supports token in env', async () => { it('supports token in env', async () => {
const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' }; const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' };
@ -35,7 +34,7 @@ describe('config/index', () => {
await configParser.parseConfigs(env, defaultArgv); await configParser.parseConfigs(env, defaultArgv);
}); });
it('supports forceCli', async () => { it('supports forceCli', async () => {
defaultArgv = defaultArgv.concat(['--force-cli=true']); defaultArgv = defaultArgv.concat(['--force-cli=false']);
const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' }; const env: NodeJS.ProcessEnv = { RENOVATE_TOKEN: 'abc' };
await configParser.parseConfigs(env, defaultArgv); await configParser.parseConfigs(env, defaultArgv);
}); });
@ -58,7 +57,7 @@ describe('config/index', () => {
}); });
}); });
describe('mergeChildConfig(parentConfig, childConfig)', () => { describe('mergeChildConfig(parentConfig, childConfig)', () => {
it('merges', () => { it('merges', async () => {
const parentConfig = { ...defaultConfig }; const parentConfig = { ...defaultConfig };
const childConfig = { const childConfig = {
foo: 'bar', foo: 'bar',
@ -67,14 +66,14 @@ describe('config/index', () => {
schedule: ['on monday'], schedule: ['on monday'],
}, },
}; };
const configParser = require('./index'); const configParser = await import('./index');
const config = configParser.mergeChildConfig(parentConfig, childConfig); const config = configParser.mergeChildConfig(parentConfig, childConfig);
expect(config.foo).toEqual('bar'); expect(config.foo).toEqual('bar');
expect(config.rangeStrategy).toEqual('replace'); expect(config.rangeStrategy).toEqual('replace');
expect(config.lockFileMaintenance.schedule).toEqual(['on monday']); expect(config.lockFileMaintenance.schedule).toEqual(['on monday']);
expect(config.lockFileMaintenance).toMatchSnapshot(); expect(config.lockFileMaintenance).toMatchSnapshot();
}); });
it('merges packageRules', () => { it('merges packageRules', async () => {
const parentConfig = { ...defaultConfig }; const parentConfig = { ...defaultConfig };
Object.assign(parentConfig, { Object.assign(parentConfig, {
packageRules: [{ a: 1 }, { a: 2 }], packageRules: [{ a: 1 }, { a: 2 }],
@ -82,7 +81,7 @@ describe('config/index', () => {
const childConfig = { const childConfig = {
packageRules: [{ a: 3 }, { a: 4 }], packageRules: [{ a: 3 }, { a: 4 }],
}; };
const configParser = require('./index'); const configParser = await import('./index');
const config = configParser.mergeChildConfig(parentConfig, childConfig); const config = configParser.mergeChildConfig(parentConfig, childConfig);
expect(config.packageRules.map(rule => rule.a)).toMatchObject([ expect(config.packageRules.map(rule => rule.a)).toMatchObject([
1, 1,
@ -91,7 +90,7 @@ describe('config/index', () => {
4, 4,
]); ]);
}); });
it('handles null parent packageRules', () => { it('handles null parent packageRules', async () => {
const parentConfig = { ...defaultConfig }; const parentConfig = { ...defaultConfig };
Object.assign(parentConfig, { Object.assign(parentConfig, {
packageRules: null, packageRules: null,
@ -99,22 +98,39 @@ describe('config/index', () => {
const childConfig = { const childConfig = {
packageRules: [{ a: 3 }, { a: 4 }], packageRules: [{ a: 3 }, { a: 4 }],
}; };
const configParser = require('./index'); const configParser = await import('./index');
const config = configParser.mergeChildConfig(parentConfig, childConfig); const config = configParser.mergeChildConfig(parentConfig, childConfig);
expect(config.packageRules).toHaveLength(2); expect(config.packageRules).toHaveLength(2);
}); });
it('handles null child packageRules', () => { it('handles null child packageRules', async () => {
const parentConfig = { ...defaultConfig }; const parentConfig = { ...defaultConfig };
parentConfig.packageRules = [{ a: 3 }, { a: 4 }]; parentConfig.packageRules = [{ a: 3 }, { a: 4 }];
const configParser = require('./index'); const configParser = await import('./index');
const config = configParser.mergeChildConfig(parentConfig, {}); const config = configParser.mergeChildConfig(parentConfig, {});
expect(config.packageRules).toHaveLength(2); expect(config.packageRules).toHaveLength(2);
}); });
it('handles undefined childConfig', () => { it('handles undefined childConfig', async () => {
const parentConfig = { ...defaultConfig }; const parentConfig = { ...defaultConfig };
const configParser = require('./index'); const configParser = await import('./index');
const config = configParser.mergeChildConfig(parentConfig, undefined); const config = configParser.mergeChildConfig(parentConfig, undefined);
expect(config).toMatchObject(parentConfig); expect(config).toMatchObject(parentConfig);
}); });
it('getManagerConfig()', async () => {
const parentConfig = { ...defaultConfig };
const configParser = await import('./index');
const config = configParser.getManagerConfig(parentConfig, 'npm');
expect(config).toMatchSnapshot();
expect(
configParser.getManagerConfig(parentConfig, 'html')
).toMatchSnapshot();
});
it('filterConfig()', async () => {
const parentConfig = { ...defaultConfig };
const configParser = await import('./index');
const config = configParser.filterConfig(parentConfig, 'pr');
expect(config).toMatchSnapshot();
});
}); });
}); });

View file

@ -116,7 +116,8 @@ export async function parseConfigs(
config.global[key] = config[key]; config.global[key] = config[key];
delete config[key]; delete config[key];
}); });
global.trustLevel = config.trustLevel || 'low'; global.trustLevel =
config.trustLevel || /* istanbul ignore next: never happen? */ 'low';
delete config.trustLevel; delete config.trustLevel;
return config; return config;

View file

@ -24,5 +24,15 @@ describe('config/migrate-validate', () => {
expect(res).toMatchSnapshot(); expect(res).toMatchSnapshot();
expect(res.errors).toHaveLength(1); expect(res.errors).toHaveLength(1);
}); });
it('isOnboarded', async () => {
const input: RenovateConfig = {};
const res = await migrateAndValidate(
{ ...config, repoIsOnboarded: true, warnings: undefined },
input
);
expect(res.warnings).toBeUndefined();
expect(res).toMatchSnapshot();
});
}); });
}); });

View file

@ -373,5 +373,30 @@ describe('config/migration', () => {
expect(migratedConfig.packageFiles).toBeUndefined(); expect(migratedConfig.packageFiles).toBeUndefined();
expect(migratedConfig.packageRules).toHaveLength(2); expect(migratedConfig.packageRules).toHaveLength(2);
}); });
it('it removes invalid configs', () => {
const config: RenovateConfig = {
pathRules: {},
packageFiles: [{ packageFile: 'test' }],
gomodTidy: false,
pinVersions: undefined,
rebaseStalePrs: true,
rebaseWhen: 'auto',
exposeEnv: undefined,
upgradeInRange: false,
versionStrategy: undefined,
ignoreNodeModules: undefined,
baseBranch: [] as never,
depTypes: [{}],
commitMessage: 'test',
raiseDeprecationWarnings: undefined,
};
const { isMigrated, migratedConfig } = configMigration.migrateConfig(
config,
defaultConfig
);
expect(migratedConfig).toMatchSnapshot();
expect(isMigrated).toBe(true);
});
}); });
}); });

View file

@ -265,7 +265,9 @@ export function migrateConfig(
migratedConfig.minor.automerge = true; migratedConfig.minor.automerge = true;
migratedConfig.major = migratedConfig.major || {}; migratedConfig.major = migratedConfig.major || {};
migratedConfig.major.automerge = false; migratedConfig.major.automerge = false;
} else if (val === 'any') { } /* istanbul ignore else: we can never go to else */ else if (
val === 'any'
) {
migratedConfig.automerge = true; migratedConfig.automerge = true;
} }
} else if (key === 'packages') { } else if (key === 'packages') {

View file

@ -275,6 +275,8 @@ Object {
} }
`; `;
exports[`config/presets resolvePreset ignores presets 1`] = `Object {}`;
exports[`config/presets resolvePreset migrates automerge in presets 1`] = ` exports[`config/presets resolvePreset migrates automerge in presets 1`] = `
Object { Object {
"automergeType": "pr", "automergeType": "pr",
@ -696,6 +698,18 @@ exports[`config/presets resolvePreset throws if valid and invalid 2`] = `"Preset
exports[`config/presets resolvePreset throws if valid and invalid 3`] = `undefined`; exports[`config/presets resolvePreset throws if valid and invalid 3`] = `undefined`;
exports[`config/presets resolvePreset throws noconfig 1`] = `undefined`;
exports[`config/presets resolvePreset throws noconfig 2`] = `"Preset package is missing a renovate-config entry (noconfig:base)"`;
exports[`config/presets resolvePreset throws noconfig 3`] = `undefined`;
exports[`config/presets resolvePreset throws throw 1`] = `undefined`;
exports[`config/presets resolvePreset throws throw 2`] = `undefined`;
exports[`config/presets resolvePreset throws throw 3`] = `undefined`;
exports[`config/presets resolvePreset works with valid 1`] = ` exports[`config/presets resolvePreset works with valid 1`] = `
Object { Object {
"foo": 1, "foo": 1,

View file

@ -1,10 +1,11 @@
import * as gitlab from './gitlab'; import * as gitlab from './gitlab';
import { api } from '../../platform/gitlab/gl-got-wrapper'; import { api } from '../../platform/gitlab/gl-got-wrapper';
import { GotResponse } from '../../platform';
jest.mock('../../platform/gitlab/gl-got-wrapper'); jest.mock('../../platform/gitlab/gl-got-wrapper');
jest.mock('../../util/got'); jest.mock('../../util/got');
const glGot: any = api.get; const glGot: jest.Mock<Promise<Partial<GotResponse>>> = api.get as never;
describe('config/presets/gitlab', () => { describe('config/presets/gitlab', () => {
beforeEach(() => { beforeEach(() => {
@ -18,22 +19,25 @@ describe('config/presets/gitlab', () => {
).rejects.toThrow(); ).rejects.toThrow();
}); });
it('throws if no content', async () => { it('throws if no content', async () => {
glGot.mockImplementationOnce(() => ({ glGot.mockResolvedValueOnce({
body: {}, body: {},
})); });
await expect(gitlab.getPreset('some/repo')).rejects.toThrow(); await expect(gitlab.getPreset('some/repo')).rejects.toThrow();
}); });
it('throws if fails to parse', async () => { it('throws if fails to parse', async () => {
glGot.mockImplementationOnce(() => ({ glGot.mockResolvedValueOnce({
body: { body: {
content: Buffer.from('not json').toString('base64'), content: Buffer.from('not json').toString('base64'),
}, },
})); });
await expect(gitlab.getPreset('some/repo')).rejects.toThrow(); await expect(gitlab.getPreset('some/repo')).rejects.toThrow();
}); });
it('should return the preset', async () => { it('should return the preset', async () => {
glGot.mockResolvedValueOnce({ glGot.mockResolvedValueOnce({
body: [ body: [
{
name: 'devel',
},
{ {
name: 'master', name: 'master',
default: true, default: true,

View file

@ -68,7 +68,7 @@ describe('config/presets', () => {
it('throws if invalid preset file', async () => { it('throws if invalid preset file', async () => {
config.foo = 1; config.foo = 1;
config.extends = ['notfound']; config.extends = ['notfound'];
let e; let e: Error;
try { try {
await presets.resolveConfigPresets(config); await presets.resolveConfigPresets(config);
} catch (err) { } catch (err) {
@ -82,7 +82,7 @@ describe('config/presets', () => {
it('throws if invalid preset', async () => { it('throws if invalid preset', async () => {
config.foo = 1; config.foo = 1;
config.extends = ['wrongpreset:invalid-preset']; config.extends = ['wrongpreset:invalid-preset'];
let e; let e: Error;
try { try {
await presets.resolveConfigPresets(config); await presets.resolveConfigPresets(config);
} catch (err) { } catch (err) {
@ -93,6 +93,37 @@ describe('config/presets', () => {
expect(e.validationError).toMatchSnapshot(); expect(e.validationError).toMatchSnapshot();
expect(e.validationMessage).toMatchSnapshot(); expect(e.validationMessage).toMatchSnapshot();
}); });
it('throws noconfig', async () => {
config.foo = 1;
config.extends = ['noconfig:base'];
let e: Error;
try {
await presets.resolveConfigPresets(config);
} catch (err) {
e = err;
}
expect(e).toBeDefined();
expect(e.configFile).toMatchSnapshot();
expect(e.validationError).toMatchSnapshot();
expect(e.validationMessage).toMatchSnapshot();
});
it('throws throw', async () => {
config.foo = 1;
config.extends = ['throw:base'];
let e: Error;
try {
await presets.resolveConfigPresets(config);
} catch (err) {
e = err;
}
expect(e).toBeDefined();
expect(e.configFile).toMatchSnapshot();
expect(e.validationError).toMatchSnapshot();
expect(e.validationMessage).toMatchSnapshot();
});
it('works with valid', async () => { it('works with valid', async () => {
config.foo = 1; config.foo = 1;
config.ignoreDeps = []; config.ignoreDeps = [];
@ -104,7 +135,7 @@ describe('config/presets', () => {
it('throws if valid and invalid', async () => { it('throws if valid and invalid', async () => {
config.foo = 1; config.foo = 1;
config.extends = ['wrongpreset:invalid-preset', ':pinVersions']; config.extends = ['wrongpreset:invalid-preset', ':pinVersions'];
let e; let e: Error;
try { try {
await presets.resolveConfigPresets(config); await presets.resolveConfigPresets(config);
} catch (err) { } catch (err) {
@ -164,6 +195,13 @@ describe('config/presets', () => {
expect(res.automerge).not.toBeDefined(); expect(res.automerge).not.toBeDefined();
expect(res.minor.automerge).toBe(true); expect(res.minor.automerge).toBe(true);
}); });
it('ignores presets', async () => {
config.extends = ['config:base'];
const res = await presets.resolveConfigPresets(config, ['config:base']);
expect(config).toMatchObject(res);
expect(res).toMatchSnapshot();
});
}); });
describe('replaceArgs', () => { describe('replaceArgs', () => {
const argMappings = { const argMappings = {
@ -303,7 +341,7 @@ describe('config/presets', () => {
expect(res).toMatchSnapshot(); expect(res).toMatchSnapshot();
}); });
it('handles 404 packages', async () => { it('handles 404 packages', async () => {
let e; let e: Error;
try { try {
await presets.getPreset('notfound:foo'); await presets.getPreset('notfound:foo');
} catch (err) { } catch (err) {
@ -315,7 +353,7 @@ describe('config/presets', () => {
expect(e.validationMessage).toMatchSnapshot(); expect(e.validationMessage).toMatchSnapshot();
}); });
it('handles no config', async () => { it('handles no config', async () => {
let e; let e: Error;
try { try {
await presets.getPreset('noconfig:foo'); await presets.getPreset('noconfig:foo');
} catch (err) { } catch (err) {
@ -327,7 +365,7 @@ describe('config/presets', () => {
expect(e.validationMessage).toMatchSnapshot(); expect(e.validationMessage).toMatchSnapshot();
}); });
it('handles throw errors', async () => { it('handles throw errors', async () => {
let e; let e: Error;
try { try {
await presets.getPreset('throw:foo'); await presets.getPreset('throw:foo');
} catch (err) { } catch (err) {
@ -339,7 +377,7 @@ describe('config/presets', () => {
expect(e.validationMessage).toMatchSnapshot(); expect(e.validationMessage).toMatchSnapshot();
}); });
it('handles preset not found', async () => { it('handles preset not found', async () => {
let e; let e: Error;
try { try {
await presets.getPreset('wrongpreset:foo'); await presets.getPreset('wrongpreset:foo');
} catch (err) { } catch (err) {

View file

@ -164,7 +164,7 @@ export async function resolveConfigPresets(
logger.debug(`Ignoring preset ${preset} in ${existingPresets}`); logger.debug(`Ignoring preset ${preset} in ${existingPresets}`);
} else { } else {
logger.trace(`Resolving preset "${preset}"`); logger.trace(`Resolving preset "${preset}"`);
let fetchedPreset; let fetchedPreset: RenovateConfig;
try { try {
fetchedPreset = await getPreset(preset); fetchedPreset = await getPreset(preset);
} catch (err) { } catch (err) {
@ -180,7 +180,6 @@ export async function resolveConfigPresets(
if (err.message === 'dep not found') { if (err.message === 'dep not found') {
error.validationError = `Cannot find preset's package (${preset})`; error.validationError = `Cannot find preset's package (${preset})`;
} else if (err.message === 'preset renovate-config not found') { } else if (err.message === 'preset renovate-config not found') {
// istanbul ignore next
error.validationError = `Preset package is missing a renovate-config entry (${preset})`; error.validationError = `Preset package is missing a renovate-config entry (${preset})`;
} else if (err.message === 'preset not found') { } else if (err.message === 'preset not found') {
error.validationError = `Preset name not found within published preset config (${preset})`; error.validationError = `Preset name not found within published preset config (${preset})`;

View file

@ -0,0 +1,9 @@
import { check } from './managers';
import { getName } from '../../../test/util';
describe(getName(__filename), () => {
it('should have no errors', () => {
const res = check({ resolvedRule: { managers: ['npm'] }, currentPath: '' });
expect(res).toEqual([]);
});
});

View file

@ -20,8 +20,7 @@ describe('config/validation', () => {
expect(errors).toMatchSnapshot(); expect(errors).toMatchSnapshot();
}); });
it('returns nested errors', async () => { it('returns nested errors', async () => {
/** @type any */ const config: RenovateConfig = {
const config = {
foo: 1, foo: 1,
schedule: ['after 5pm'], schedule: ['after 5pm'],
timezone: 'Asia/Singapore', timezone: 'Asia/Singapore',
@ -34,6 +33,7 @@ describe('config/validation', () => {
lockFileMaintenance: { lockFileMaintenance: {
bar: 2, bar: 2,
}, },
major: null,
}; };
const { warnings, errors } = await configValidation.validateConfig( const { warnings, errors } = await configValidation.validateConfig(
config config
@ -97,6 +97,7 @@ describe('config/validation', () => {
enabled: false, enabled: false,
}, },
], ],
major: null,
}; };
const { warnings, errors } = await configValidation.validateConfig( const { warnings, errors } = await configValidation.validateConfig(
config config
@ -258,5 +259,52 @@ describe('config/validation', () => {
expect(errors).toMatchSnapshot(); expect(errors).toMatchSnapshot();
expect(errors).toHaveLength(1); expect(errors).toHaveLength(1);
}); });
it('ignore keys', async () => {
const config = {
$schema: 'renovate.json',
};
const { warnings, errors } = await configValidation.validateConfig(
config,
true
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
it('validates timezone preset', async () => {
const config = {
extends: [':timezone', ':timezone(Europe/Berlin)'],
};
const { warnings, errors } = await configValidation.validateConfig(
config,
true
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
it('does not validate compatibility children', async () => {
const config = {
compatibility: { packageRules: [{}] },
};
const { warnings, errors } = await configValidation.validateConfig(
config,
true
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
it('validates object with ignored children', async () => {
const config = {
prBodyDefinitions: {},
};
const { warnings, errors } = await configValidation.validateConfig(
config,
true
);
expect(warnings).toHaveLength(0);
expect(errors).toHaveLength(0);
});
}); });
}); });

View file

@ -336,10 +336,11 @@ export async function validateConfig(
} }
} }
function sortAll(a: ValidationMessage, b: ValidationMessage): number { function sortAll(a: ValidationMessage, b: ValidationMessage): number {
// istanbul ignore else: currently never happen
if (a.depName === b.depName) { if (a.depName === b.depName) {
return a.message > b.message ? 1 : -1; return a.message > b.message ? 1 : -1;
} }
// istanbul ignore next // istanbul ignore next: currently never happen
return a.depName > b.depName ? 1 : -1; return a.depName > b.depName ? 1 : -1;
} }
errors.sort(sortAll); errors.sort(sortAll);

9
lib/types/jest.d.ts vendored
View file

@ -1,9 +0,0 @@
declare namespace jest {
interface Matchers<R, T> {
/**
* only available in `test/website-docs.spec.js`
* @param arg
*/
toContainOption(arg: T): void;
}
}

View file

@ -26,3 +26,8 @@ export type RenovateConfig = _RenovateConfig;
export const defaultConfig = getConfig(); export const defaultConfig = getConfig();
export { getConfig }; export { getConfig };
export function getName(file: string): string {
const [, name] = /lib\/(.*?)\.spec\.ts$/.exec(file.replace(/\\/g, '/'));
return name;
}

View file

@ -1,7 +1,21 @@
import fs from 'fs'; import fs from 'fs';
import { RenovateOptions } from '../lib/config/definitions'; import { getOptions } from '../lib/config/definitions';
const options: RenovateOptions[] = require('../lib/config/definitions').getOptions(); declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace jest {
type ContainsOption<T> = T extends ArrayLike<unknown> ? T[number] : unknown;
interface Matchers<R, T> {
/**
* only available in `test/website-docs.spec.js`
* @param arg Value which current values should contain
*/
toContainOption(arg: ContainsOption<T>): void;
}
}
}
const options = getOptions();
describe('docs', () => { describe('docs', () => {
const doc = fs.readFileSync('docs/usage/configuration-options.md', 'utf8'); const doc = fs.readFileSync('docs/usage/configuration-options.md', 'utf8');
@ -57,12 +71,12 @@ describe('docs', () => {
}); });
// Checking relatedOptions field in definitions // Checking relatedOptions field in definitions
let relatedOptions = options const relatedOptionsMatrix = options
.filter(option => option.relatedOptions) .filter(option => option.relatedOptions)
.map(option => option.relatedOptions) .map(option => option.relatedOptions)
.sort(); .sort();
relatedOptions = [].concat(...relatedOptions); // Converts the matrix to an 1D array let relatedOptions: string[] = [].concat(...relatedOptionsMatrix); // Converts the matrix to an 1D array
relatedOptions = [...new Set(relatedOptions)]; // Makes all options unique relatedOptions = [...new Set(relatedOptions)]; // Makes all options unique
/* /*
@ -70,7 +84,7 @@ describe('docs', () => {
on an error, it throws a custom message. on an error, it throws a custom message.
*/ */
expect.extend({ expect.extend({
toContainOption(received, argument) { toContainOption<T>(received: T[], argument: T) {
if (received.includes(argument)) { if (received.includes(argument)) {
return { return {
message: (): string => message: (): string =>