mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-11 22:46:27 +00:00
feat: schedule support for lock file maintenance
This feature now allows a custom schedule to be defined for lock file maintenance. It is now enabled by default but runs only before 5m on Sundays. Closes #399 BREAKING CHANGE: lock file maintenance is enabled by default. Rules will apply to both yarn and npm (npm is yet to be implemented however). Existing mainainYarn* variables are removed and replaced by new lockFileMaintenance object.
This commit is contained in:
parent
3a68dafab2
commit
6f49927a45
20 changed files with 165 additions and 99 deletions
|
@ -98,7 +98,6 @@ $ node renovate --help
|
||||||
--automerge <string> What types of upgrades to merge to base branch automatically. Values: none, minor or any
|
--automerge <string> What types of upgrades to merge to base branch automatically. Values: none, minor or any
|
||||||
--automerge-type <string> How to automerge - "branch-merge-commit", "branch-push" or "pr". Branch support is GitHub-only
|
--automerge-type <string> How to automerge - "branch-merge-commit", "branch-push" or "pr". Branch support is GitHub-only
|
||||||
--yarn-cache-folder <string> Location of yarn cache folder to use. Set to empty string to disable
|
--yarn-cache-folder <string> Location of yarn cache folder to use. Set to empty string to disable
|
||||||
--maintain-yarn-lock [boolean] Keep yarn.lock files updated in base branch
|
|
||||||
--lazy-grouping [boolean] Use group names only when multiple dependencies upgraded
|
--lazy-grouping [boolean] Use group names only when multiple dependencies upgraded
|
||||||
--group-name <string> Human understandable name for the dependency group
|
--group-name <string> Human understandable name for the dependency group
|
||||||
--group-slug <string> Slug to use for group (e.g. in branch name). Will be calculated from groupName if null
|
--group-slug <string> Slug to use for group (e.g. in branch name). Will be calculated from groupName if null
|
||||||
|
@ -177,11 +176,14 @@ Obviously, you can't set repository or package file location with this method.
|
||||||
| `prTitle` | Pull Request title template | string | `"{{semanticPrefix}}{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}{{newVersionMajor}}.x{{else}}{{newVersion}}{{/if}}{{/if}}"` | `RENOVATE_PR_TITLE` | |
|
| `prTitle` | Pull Request title template | string | `"{{semanticPrefix}}{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}{{newVersionMajor}}.x{{else}}{{newVersion}}{{/if}}{{/if}}"` | `RENOVATE_PR_TITLE` | |
|
||||||
| `prBody` | Pull Request body template | string | `"This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates dependency [{{depName}}]({{repositoryUrl}}) from version `{{currentVersion}}` to `{{newVersion}}`\n{{#if releases.length}}\n\n### Commits\n\n<details>\n<summary>{{githubName}}</summary>\n\n{{#each releases as |release|}}\n#### {{release.version}}\n{{#each release.commits as |commit|}}\n- [`{{commit.shortSha}}`]({{commit.url}}) {{commit.message}}\n{{/each}}\n{{/each}}\n\n</details>\n{{/if}}\n<br />\n\nThis {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://keylocation.sg/our-tech/renovate)."` | `RENOVATE_PR_BODY` | |
|
| `prBody` | Pull Request body template | string | `"This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates dependency [{{depName}}]({{repositoryUrl}}) from version `{{currentVersion}}` to `{{newVersion}}`\n{{#if releases.length}}\n\n### Commits\n\n<details>\n<summary>{{githubName}}</summary>\n\n{{#each releases as |release|}}\n#### {{release.version}}\n{{#each release.commits as |commit|}}\n- [`{{commit.shortSha}}`]({{commit.url}}) {{commit.message}}\n{{/each}}\n{{/each}}\n\n</details>\n{{/if}}\n<br />\n\nThis {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://keylocation.sg/our-tech/renovate)."` | `RENOVATE_PR_BODY` | |
|
||||||
| `yarnCacheFolder` | Location of yarn cache folder to use. Set to empty string to disable | string | `"/tmp/yarn-cache"` | `RENOVATE_YARN_CACHE_FOLDER` | `--yarn-cache-folder` |
|
| `yarnCacheFolder` | Location of yarn cache folder to use. Set to empty string to disable | string | `"/tmp/yarn-cache"` | `RENOVATE_YARN_CACHE_FOLDER` | `--yarn-cache-folder` |
|
||||||
| `maintainYarnLock` | Keep yarn.lock files updated in base branch | boolean | `false` | `RENOVATE_MAINTAIN_YARN_LOCK` | `--maintain-yarn-lock` |
|
| `lockFileMaintenance` | Configuration for lock file maintenance | json | `{
|
||||||
| `yarnMaintenanceBranchName` | Branch name template when maintaining yarn.lock | string | `"renovate/yarn-lock"` | `RENOVATE_YARN_MAINTENANCE_BRANCH_NAME` | |
|
"enabled": true,
|
||||||
| `yarnMaintenanceCommitMessage` | Commit message template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | `RENOVATE_YARN_MAINTENANCE_COMMIT_MESSAGE` | |
|
"branchName": "renovate/lock-files",
|
||||||
| `yarnMaintenancePrTitle` | Pull Request title template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | `RENOVATE_YARN_MAINTENANCE_PR_TITLE` | |
|
"commitMessage": "{{semanticPrefix}}Update lock file",
|
||||||
| `yarnMaintenancePrBody` | Pull Request body template when maintaining yarn.lock | string | `"This PR regenerates yarn.lock files based on the existing `package.json` files."` | `RENOVATE_YARN_MAINTENANCE_PR_BODY` | |
|
"prTitle": "{{semanticPrefix}}Lock file maintenance",
|
||||||
|
"prBody": "This PR regenerates lock files to keep them up-to-date.",
|
||||||
|
"schedule": "before 5am on monday"
|
||||||
|
}` | | |
|
||||||
| `lazyGrouping` | Use group names only when multiple dependencies upgraded | boolean | `true` | `RENOVATE_LAZY_GROUPING` | `--lazy-grouping` |
|
| `lazyGrouping` | Use group names only when multiple dependencies upgraded | boolean | `true` | `RENOVATE_LAZY_GROUPING` | `--lazy-grouping` |
|
||||||
| `groupName` | Human understandable name for the dependency group | string | `null` | `RENOVATE_GROUP_NAME` | `--group-name` |
|
| `groupName` | Human understandable name for the dependency group | string | `null` | `RENOVATE_GROUP_NAME` | `--group-name` |
|
||||||
| `groupSlug` | Slug to use for group (e.g. in branch name). Will be calculated from groupName if null | string | `null` | `RENOVATE_GROUP_SLUG` | `--group-slug` |
|
| `groupSlug` | Slug to use for group (e.g. in branch name). Will be calculated from groupName if null | string | `null` | `RENOVATE_GROUP_SLUG` | `--group-slug` |
|
||||||
|
|
|
@ -85,7 +85,7 @@ Set configuration option `pinVersions` to `false`.
|
||||||
|
|
||||||
### Keep `yarn.lock` sub-dependencies up-to-date, even when `package.json` hasn't changed
|
### Keep `yarn.lock` sub-dependencies up-to-date, even when `package.json` hasn't changed
|
||||||
|
|
||||||
Set configuration option `maintainYarnLock` to `true`.
|
This is enabled by default, but its schedule is set to 'before 5am on monday'. If you want it more frequently, then update the `schedule` field inside the `lockFileMaintenance` object.
|
||||||
|
|
||||||
### Wait until tests have passed before creating the PR
|
### Wait until tests have passed before creating the PR
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ const defaultValues = {
|
||||||
boolean: true,
|
boolean: true,
|
||||||
list: [],
|
list: [],
|
||||||
string: null,
|
string: null,
|
||||||
|
json: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getDefault(option) {
|
function getDefault(option) {
|
||||||
|
|
|
@ -256,48 +256,22 @@ const options = [
|
||||||
default: '/tmp/yarn-cache',
|
default: '/tmp/yarn-cache',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'maintainYarnLock',
|
name: 'lockFileMaintenance',
|
||||||
description: 'Keep yarn.lock files updated in base branch',
|
description: 'Configuration for lock file maintenance',
|
||||||
level: 'packageFile',
|
level: 'packageFile',
|
||||||
type: 'boolean',
|
type: 'json',
|
||||||
default: false,
|
default: {
|
||||||
|
enabled: true,
|
||||||
|
branchName: 'renovate/lock-files',
|
||||||
|
commitMessage: '{{semanticPrefix}}Update lock file',
|
||||||
|
prTitle: '{{semanticPrefix}}Lock file maintenance',
|
||||||
|
prBody: 'This PR regenerates lock files to keep them up-to-date.',
|
||||||
|
schedule: 'before 5am on monday',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'yarnMaintenanceBranchName',
|
|
||||||
description: 'Branch name template when maintaining yarn.lock',
|
|
||||||
level: 'packageFile',
|
|
||||||
type: 'string',
|
|
||||||
default: 'renovate/yarn-lock',
|
|
||||||
cli: false,
|
|
||||||
onboarding: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yarnMaintenanceCommitMessage',
|
|
||||||
description: 'Commit message template when maintaining yarn.lock',
|
|
||||||
level: 'packageFile',
|
|
||||||
type: 'string',
|
|
||||||
default: 'Renovate yarn.lock file',
|
|
||||||
cli: false,
|
|
||||||
onboarding: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yarnMaintenancePrTitle',
|
|
||||||
description: 'Pull Request title template when maintaining yarn.lock',
|
|
||||||
level: 'packageFile',
|
|
||||||
type: 'string',
|
|
||||||
default: 'Renovate yarn.lock file',
|
|
||||||
cli: false,
|
|
||||||
onboarding: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'yarnMaintenancePrBody',
|
|
||||||
description: 'Pull Request body template when maintaining yarn.lock',
|
|
||||||
level: 'packageFile',
|
|
||||||
type: 'string',
|
|
||||||
default:
|
|
||||||
'This PR regenerates yarn.lock files based on the existing `package.json` files.',
|
|
||||||
cli: false,
|
cli: false,
|
||||||
|
env: false,
|
||||||
onboarding: false,
|
onboarding: false,
|
||||||
|
mergeable: true,
|
||||||
},
|
},
|
||||||
// Dependency Groups
|
// Dependency Groups
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,6 +13,7 @@ const githubApp = require('./github-app');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parseConfigs,
|
parseConfigs,
|
||||||
|
mergeChildConfig,
|
||||||
filterConfig,
|
filterConfig,
|
||||||
getOnboardingConfig,
|
getOnboardingConfig,
|
||||||
};
|
};
|
||||||
|
@ -117,6 +118,25 @@ async function parseConfigs(env, argv) {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mergeChildConfig(parentConfig, childConfig) {
|
||||||
|
const config = Object.assign({}, parentConfig, childConfig);
|
||||||
|
for (const option of definitions.getOptions()) {
|
||||||
|
if (option.mergeable && childConfig[option.name]) {
|
||||||
|
logger.debug(`mergeable option: ${option.name}`);
|
||||||
|
// TODO: handle arrays
|
||||||
|
config[option.name] = Object.assign(
|
||||||
|
{},
|
||||||
|
parentConfig[option.name],
|
||||||
|
childConfig[option.name]
|
||||||
|
);
|
||||||
|
logger.debug(
|
||||||
|
`config.${option.name}=${JSON.stringify(config[option.name])}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
function filterConfig(inputConfig, filterLevel) {
|
function filterConfig(inputConfig, filterLevel) {
|
||||||
const outputConfig = Object.assign({}, inputConfig);
|
const outputConfig = Object.assign({}, inputConfig);
|
||||||
const levelScores = {
|
const levelScores = {
|
||||||
|
|
|
@ -78,7 +78,8 @@ async function ensureBranch(upgrades) {
|
||||||
const packageFiles = {};
|
const packageFiles = {};
|
||||||
const commitFiles = [];
|
const commitFiles = [];
|
||||||
for (const upgrade of upgrades) {
|
for (const upgrade of upgrades) {
|
||||||
if (upgrade.upgradeType === 'maintainYarnLock') {
|
if (upgrade.upgradeType === 'lockFileMaintenance') {
|
||||||
|
logger.debug('branch lockFileMaintenance');
|
||||||
try {
|
try {
|
||||||
const newYarnLock = await yarn.maintainLockFile(upgrade);
|
const newYarnLock = await yarn.maintainLockFile(upgrade);
|
||||||
if (newYarnLock) {
|
if (newYarnLock) {
|
||||||
|
@ -220,7 +221,7 @@ async function updateBranch(upgrades) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (
|
||||||
upgrade0.upgradeType !== 'maintainYarnLock' &&
|
upgrade0.upgradeType !== 'lockFileMaintenance' &&
|
||||||
upgrade0.groupName === null &&
|
upgrade0.groupName === null &&
|
||||||
!upgrade0.recreateClosed &&
|
!upgrade0.recreateClosed &&
|
||||||
(await upgrade0.api.checkForClosedPr(branchName, prTitle))
|
(await upgrade0.api.checkForClosedPr(branchName, prTitle))
|
||||||
|
@ -243,7 +244,12 @@ async function updateBranch(upgrades) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeStandaloneBranches(upgrades) {
|
async function removeStandaloneBranches(upgrades) {
|
||||||
if (upgrades.length > 1) {
|
if (upgrades.length <= 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (upgrades[0].upgradeType === 'lockFileMaintenance') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (const upgrade of upgrades) {
|
for (const upgrade of upgrades) {
|
||||||
const standaloneBranchName = handlebars.compile(upgrade.branchName)(
|
const standaloneBranchName = handlebars.compile(upgrade.branchName)(
|
||||||
upgrade
|
upgrade
|
||||||
|
@ -258,4 +264,3 @@ async function removeStandaloneBranches(upgrades) {
|
||||||
upgrade.branchName = upgrade.groupBranchName;
|
upgrade.branchName = upgrade.groupBranchName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ async function getLockFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
async function maintainLockFile(inputConfig) {
|
async function maintainLockFile(inputConfig) {
|
||||||
logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`);
|
logger.debug(`maintainLockFile(${JSON.stringify(inputConfig)})`);
|
||||||
const packageContent = await inputConfig.api.getFileContent(
|
const packageContent = await inputConfig.api.getFileContent(
|
||||||
inputConfig.packageFile
|
inputConfig.packageFile
|
||||||
);
|
);
|
||||||
|
|
|
@ -50,7 +50,7 @@ async function findUpgrades(packageContent, config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDepConfig(depTypeConfig, dep) {
|
function getDepConfig(depTypeConfig, dep) {
|
||||||
const depConfig = Object.assign({}, depTypeConfig, dep);
|
const depConfig = configParser.mergeChildConfig(depTypeConfig, dep);
|
||||||
// Apply any matching package rules
|
// Apply any matching package rules
|
||||||
if (depConfig.packages) {
|
if (depConfig.packages) {
|
||||||
let packageRuleApplied = false;
|
let packageRuleApplied = false;
|
||||||
|
|
|
@ -32,7 +32,7 @@ function getRepositoryConfig(globalConfig, index) {
|
||||||
if (typeof repository === 'string') {
|
if (typeof repository === 'string') {
|
||||||
repository = { repository };
|
repository = { repository };
|
||||||
}
|
}
|
||||||
const repoConfig = Object.assign({}, globalConfig, repository);
|
const repoConfig = configParser.mergeChildConfig(globalConfig, repository);
|
||||||
repoConfig.logger = logger.child({
|
repoConfig.logger = logger.child({
|
||||||
repository: repoConfig.repository,
|
repository: repoConfig.repository,
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const configParser = require('../../config');
|
const configParser = require('../../config');
|
||||||
const depTypeWorker = require('../dep-type');
|
const depTypeWorker = require('../dep-type');
|
||||||
|
const schedule = require('../package/schedule');
|
||||||
|
|
||||||
let logger = require('../../logger');
|
let logger = require('../../logger');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -7,7 +9,8 @@ module.exports = {
|
||||||
getDepTypeConfig,
|
getDepTypeConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function findUpgrades(config) {
|
async function findUpgrades(packageFileConfig) {
|
||||||
|
let config = Object.assign({}, packageFileConfig);
|
||||||
logger = config.logger || logger;
|
logger = config.logger || logger;
|
||||||
logger.info(`Processing package file`);
|
logger.info(`Processing package file`);
|
||||||
// If onboarding, use the package.json in onboarding branch
|
// If onboarding, use the package.json in onboarding branch
|
||||||
|
@ -29,7 +32,7 @@ async function findUpgrades(config) {
|
||||||
'package.json>renovate config'
|
'package.json>renovate config'
|
||||||
);
|
);
|
||||||
// package.json>renovate config takes precedence over existing config
|
// package.json>renovate config takes precedence over existing config
|
||||||
Object.assign(config, packageContent.renovate);
|
config = configParser.mergeChildConfig(config, packageContent.renovate);
|
||||||
} else {
|
} else {
|
||||||
logger.debug('Package file has no renovate configuration');
|
logger.debug('Package file has no renovate configuration');
|
||||||
}
|
}
|
||||||
|
@ -50,24 +53,31 @@ async function findUpgrades(config) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.maintainYarnLock) {
|
// Maintain lock files
|
||||||
const upgrade = Object.assign({}, config, {
|
const lockFileMaintenanceConf = Object.assign(
|
||||||
upgradeType: 'maintainYarnLock',
|
{},
|
||||||
});
|
config,
|
||||||
upgrade.upgradeType = 'maintainYarnLock';
|
config.lockFileMaintenance
|
||||||
upgrade.commitMessage = upgrade.yarnMaintenanceCommitMessage;
|
);
|
||||||
upgrade.branchName = upgrade.yarnMaintenanceBranchName;
|
if (lockFileMaintenanceConf.enabled) {
|
||||||
upgrade.prTitle = upgrade.yarnMaintenancePrTitle;
|
logger.debug('lockFileMaintenance enabled');
|
||||||
upgrade.prBody = upgrade.yarnMaintenancePrBody;
|
lockFileMaintenanceConf.upgradeType = 'lockFileMaintenance';
|
||||||
upgrades.push(upgrade);
|
if (schedule.isScheduledNow(lockFileMaintenanceConf)) {
|
||||||
|
logger.debug(`lock config=${JSON.stringify(lockFileMaintenanceConf)}`);
|
||||||
|
upgrades.push(lockFileMaintenanceConf);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.info('Finished processing package file');
|
logger.info('Finished processing package file');
|
||||||
return upgrades;
|
return upgrades;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDepTypeConfig(packageFileConfig, depType) {
|
function getDepTypeConfig(packageFileConfig, depType) {
|
||||||
let depTypeConfig = typeof depType === 'string' ? { depType } : depType;
|
let depTypeConfig = typeof depType === 'string' ? { depType } : depType;
|
||||||
depTypeConfig = Object.assign({}, packageFileConfig, depTypeConfig);
|
depTypeConfig = configParser.mergeChildConfig(
|
||||||
|
packageFileConfig,
|
||||||
|
depTypeConfig
|
||||||
|
);
|
||||||
depTypeConfig.logger = logger.child({
|
depTypeConfig.logger = logger.child({
|
||||||
repository: depTypeConfig.repository,
|
repository: depTypeConfig.repository,
|
||||||
packageFile: depTypeConfig.packageFile,
|
packageFile: depTypeConfig.packageFile,
|
||||||
|
|
|
@ -16,7 +16,7 @@ async function findUpgrades(config) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// Check schedule
|
// Check schedule
|
||||||
if (config.schedule && !schedule.isPackageScheduled(config)) {
|
if (config.schedule && !schedule.isScheduledNow(config)) {
|
||||||
logger.debug('Skipping package as it is not scheduled');
|
logger.debug('Skipping package as it is not scheduled');
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ const moment = require('moment-timezone');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
hasValidSchedule,
|
hasValidSchedule,
|
||||||
isPackageScheduled,
|
isScheduledNow,
|
||||||
};
|
};
|
||||||
|
|
||||||
function fixShortHours(input) {
|
function fixShortHours(input) {
|
||||||
|
@ -45,7 +45,7 @@ function hasValidSchedule(schedule, logger) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPackageScheduled(config) {
|
function isScheduledNow(config) {
|
||||||
config.logger.debug(`Checking schedule ${JSON.stringify(config.schedule)}`);
|
config.logger.debug(`Checking schedule ${JSON.stringify(config.schedule)}`);
|
||||||
// Massage into array
|
// Massage into array
|
||||||
const configSchedule =
|
const configSchedule =
|
||||||
|
|
|
@ -64,7 +64,10 @@ function getPackageFileConfig(repoConfig, index) {
|
||||||
if (typeof packageFile === 'string') {
|
if (typeof packageFile === 'string') {
|
||||||
packageFile = { packageFile };
|
packageFile = { packageFile };
|
||||||
}
|
}
|
||||||
const packageFileConfig = Object.assign({}, repoConfig, packageFile);
|
const packageFileConfig = configParser.mergeChildConfig(
|
||||||
|
repoConfig,
|
||||||
|
packageFile
|
||||||
|
);
|
||||||
repoConfig.logger.trace({ config: repoConfig }, 'repoConfig');
|
repoConfig.logger.trace({ config: repoConfig }, 'repoConfig');
|
||||||
packageFileConfig.logger = packageFileConfig.logger.child({
|
packageFileConfig.logger = packageFileConfig.logger.child({
|
||||||
repository: packageFileConfig.repository,
|
repository: packageFileConfig.repository,
|
||||||
|
|
12
test/config/__snapshots__/index.spec.js.snap
Normal file
12
test/config/__snapshots__/index.spec.js.snap
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`config/index mergeChildConfig(parentConfig, childConfig) merges 1`] = `
|
||||||
|
Object {
|
||||||
|
"branchName": "renovate/lock-files",
|
||||||
|
"commitMessage": "{{semanticPrefix}}Update lock file",
|
||||||
|
"enabled": true,
|
||||||
|
"prBody": "This PR regenerates lock files to keep them up-to-date.",
|
||||||
|
"prTitle": "{{semanticPrefix}}Lock file maintenance",
|
||||||
|
"schedule": "on monday",
|
||||||
|
}
|
||||||
|
`;
|
|
@ -1,4 +1,5 @@
|
||||||
const argv = require('../_fixtures/config/argv');
|
const argv = require('../_fixtures/config/argv');
|
||||||
|
const defaultConfig = require('../../lib/config/defaults').getConfig();
|
||||||
|
|
||||||
describe('config/index', () => {
|
describe('config/index', () => {
|
||||||
describe('.parseConfigs(env, defaultArgv)', () => {
|
describe('.parseConfigs(env, defaultArgv)', () => {
|
||||||
|
@ -160,4 +161,22 @@ describe('config/index', () => {
|
||||||
expect(glGot.mock.calls.length).toBe(0);
|
expect(glGot.mock.calls.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('mergeChildConfig(parentConfig, childConfig)', () => {
|
||||||
|
it('merges', () => {
|
||||||
|
const parentConfig = Object.assign({}, defaultConfig);
|
||||||
|
const childConfig = {
|
||||||
|
foo: 'bar',
|
||||||
|
pinVersions: false,
|
||||||
|
lockFileMaintenance: {
|
||||||
|
schedule: 'on monday',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const configParser = require('../../lib/config/index.js');
|
||||||
|
const config = configParser.mergeChildConfig(parentConfig, childConfig);
|
||||||
|
expect(config.foo).toEqual('bar');
|
||||||
|
expect(config.pinVersions).toBe(false);
|
||||||
|
expect(config.lockFileMaintenance.schedule).toEqual('on monday');
|
||||||
|
expect(config.lockFileMaintenance).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -279,7 +279,7 @@ describe('workers/branch', () => {
|
||||||
it('maintains lock files if needing updates', async () => {
|
it('maintains lock files if needing updates', async () => {
|
||||||
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
||||||
yarn.maintainLockFile.mockReturnValueOnce('non null response');
|
yarn.maintainLockFile.mockReturnValueOnce('non null response');
|
||||||
config.upgradeType = 'maintainYarnLock';
|
config.upgradeType = 'lockFileMaintenance';
|
||||||
await branchWorker.ensureBranch([config]);
|
await branchWorker.ensureBranch([config]);
|
||||||
expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
|
expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
|
||||||
expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
|
expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
|
||||||
|
@ -290,7 +290,7 @@ describe('workers/branch', () => {
|
||||||
});
|
});
|
||||||
it('skips maintaining lock files if no updates', async () => {
|
it('skips maintaining lock files if no updates', async () => {
|
||||||
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
||||||
config.upgradeType = 'maintainYarnLock';
|
config.upgradeType = 'lockFileMaintenance';
|
||||||
await branchWorker.ensureBranch([config]);
|
await branchWorker.ensureBranch([config]);
|
||||||
expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
|
expect(branchWorker.getParentBranch.mock.calls.length).toBe(1);
|
||||||
expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
|
expect(packageJsonHelper.setNewValue.mock.calls.length).toBe(0);
|
||||||
|
@ -301,7 +301,7 @@ describe('workers/branch', () => {
|
||||||
});
|
});
|
||||||
it('throws error if cannot maintain yarn.lock file', async () => {
|
it('throws error if cannot maintain yarn.lock file', async () => {
|
||||||
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
branchWorker.getParentBranch.mockReturnValueOnce('dummy branch');
|
||||||
config.upgradeType = 'maintainYarnLock';
|
config.upgradeType = 'lockFileMaintenance';
|
||||||
yarn.maintainLockFile.mockImplementationOnce(() => {
|
yarn.maintainLockFile.mockImplementationOnce(() => {
|
||||||
throw new Error('yarn not found');
|
throw new Error('yarn not found');
|
||||||
});
|
});
|
||||||
|
@ -372,6 +372,14 @@ describe('workers/branch', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('removeStandaloneBranches(upgrades)', () => {
|
describe('removeStandaloneBranches(upgrades)', () => {
|
||||||
|
it('returns if length is one or less', async () => {
|
||||||
|
const upgrades = [{}];
|
||||||
|
await branchWorker.removeStandaloneBranches(upgrades);
|
||||||
|
});
|
||||||
|
it('returns if upgradeType is lockFileMaintenance', async () => {
|
||||||
|
const upgrades = [{ upgradeType: 'lockFileMaintenance' }, {}];
|
||||||
|
await branchWorker.removeStandaloneBranches(upgrades);
|
||||||
|
});
|
||||||
it('deletes standalone branch names', async () => {
|
it('deletes standalone branch names', async () => {
|
||||||
const api = {
|
const api = {
|
||||||
deleteBranch: jest.fn(),
|
deleteBranch: jest.fn(),
|
||||||
|
|
|
@ -1,19 +1,25 @@
|
||||||
const packageFileWorker = require('../../../lib/workers/package-file');
|
const packageFileWorker = require('../../../lib/workers/package-file');
|
||||||
const depTypeWorker = require('../../../lib/workers/dep-type');
|
const depTypeWorker = require('../../../lib/workers/dep-type');
|
||||||
|
const schedule = require('../../../lib/workers/package/schedule');
|
||||||
|
const defaultConfig = require('../../../lib/config/defaults').getConfig();
|
||||||
|
|
||||||
|
const logger = require('../../_fixtures/logger');
|
||||||
|
|
||||||
jest.mock('../../../lib/workers/dep-type');
|
jest.mock('../../../lib/workers/dep-type');
|
||||||
|
jest.mock('../../../lib/workers/package/schedule');
|
||||||
|
|
||||||
describe('packageFileWorker', () => {
|
describe('packageFileWorker', () => {
|
||||||
describe('findUpgrades(config)', () => {
|
describe('findUpgrades(config)', () => {
|
||||||
let config;
|
let config;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
config = {
|
config = Object.assign({}, defaultConfig, {
|
||||||
repoIsOnboarded: true,
|
repoIsOnboarded: true,
|
||||||
api: {
|
api: {
|
||||||
getFileJson: jest.fn(),
|
getFileJson: jest.fn(),
|
||||||
},
|
},
|
||||||
depTypes: ['dependencies', 'devDependencies'],
|
depTypes: ['dependencies', 'devDependencies'],
|
||||||
};
|
logger,
|
||||||
|
});
|
||||||
packageFileWorker.updateBranch = jest.fn();
|
packageFileWorker.updateBranch = jest.fn();
|
||||||
});
|
});
|
||||||
it('handles null', async () => {
|
it('handles null', async () => {
|
||||||
|
@ -55,10 +61,17 @@ describe('packageFileWorker', () => {
|
||||||
});
|
});
|
||||||
it('maintains yarn.lock', async () => {
|
it('maintains yarn.lock', async () => {
|
||||||
config.api.getFileJson.mockReturnValueOnce({});
|
config.api.getFileJson.mockReturnValueOnce({});
|
||||||
config.maintainYarnLock = true;
|
|
||||||
depTypeWorker.findUpgrades.mockReturnValue([]);
|
depTypeWorker.findUpgrades.mockReturnValue([]);
|
||||||
|
schedule.isScheduledNow.mockReturnValueOnce(true);
|
||||||
const res = await packageFileWorker.findUpgrades(config);
|
const res = await packageFileWorker.findUpgrades(config);
|
||||||
expect(res).toHaveLength(1);
|
expect(res).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
it('skips yarn.lock', async () => {
|
||||||
|
config.api.getFileJson.mockReturnValueOnce({});
|
||||||
|
depTypeWorker.findUpgrades.mockReturnValue([]);
|
||||||
|
schedule.isScheduledNow.mockReturnValueOnce(false);
|
||||||
|
const res = await packageFileWorker.findUpgrades(config);
|
||||||
|
expect(res).toHaveLength(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -22,14 +22,14 @@ describe('lib/workers/package/index', () => {
|
||||||
});
|
});
|
||||||
it('returns empty if package is not scheduled', async () => {
|
it('returns empty if package is not scheduled', async () => {
|
||||||
config.schedule = 'some schedule';
|
config.schedule = 'some schedule';
|
||||||
schedule.isPackageScheduled.mockReturnValueOnce(false);
|
schedule.isScheduledNow.mockReturnValueOnce(false);
|
||||||
const res = await pkgWorker.findUpgrades(config);
|
const res = await pkgWorker.findUpgrades(config);
|
||||||
expect(res).toMatchObject([]);
|
expect(res).toMatchObject([]);
|
||||||
expect(npmApi.getDependency.mock.calls.length).toBe(0);
|
expect(npmApi.getDependency.mock.calls.length).toBe(0);
|
||||||
});
|
});
|
||||||
it('returns empty if no npm dep found', async () => {
|
it('returns empty if no npm dep found', async () => {
|
||||||
config.schedule = 'some schedule';
|
config.schedule = 'some schedule';
|
||||||
schedule.isPackageScheduled.mockReturnValueOnce(true);
|
schedule.isScheduledNow.mockReturnValueOnce(true);
|
||||||
const res = await pkgWorker.findUpgrades(config);
|
const res = await pkgWorker.findUpgrades(config);
|
||||||
expect(res).toMatchObject([]);
|
expect(res).toMatchObject([]);
|
||||||
expect(npmApi.getDependency.mock.calls.length).toBe(1);
|
expect(npmApi.getDependency.mock.calls.length).toBe(1);
|
||||||
|
|
|
@ -73,7 +73,7 @@ describe('workers/package/schedule', () => {
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('isPackageScheduled(config)', () => {
|
describe('isScheduledNow(config)', () => {
|
||||||
let config;
|
let config;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockDate.set(1498812608678); // 2017-06-30 10:50am
|
mockDate.set(1498812608678); // 2017-06-30 10:50am
|
||||||
|
@ -83,43 +83,43 @@ describe('workers/package/schedule', () => {
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
it('returns true if no schedule', () => {
|
it('returns true if no schedule', () => {
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
it('supports before hours true', () => {
|
it('supports before hours true', () => {
|
||||||
config.schedule = 'before 4:00pm';
|
config.schedule = 'before 4:00pm';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
it('supports before hours false', () => {
|
it('supports before hours false', () => {
|
||||||
config.schedule = 'before 4:00am';
|
config.schedule = 'before 4:00am';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(false);
|
expect(res).toBe(false);
|
||||||
});
|
});
|
||||||
it('supports outside hours', () => {
|
it('supports outside hours', () => {
|
||||||
config.schedule = 'after 4:00pm';
|
config.schedule = 'after 4:00pm';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(false);
|
expect(res).toBe(false);
|
||||||
});
|
});
|
||||||
it('supports timezone', () => {
|
it('supports timezone', () => {
|
||||||
config.schedule = 'after 4:00pm';
|
config.schedule = 'after 4:00pm';
|
||||||
config.timezone = 'Asia/Singapore';
|
config.timezone = 'Asia/Singapore';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
it('supports multiple schedules', () => {
|
it('supports multiple schedules', () => {
|
||||||
config.schedule = ['after 4:00pm', 'before 11:00am'];
|
config.schedule = ['after 4:00pm', 'before 11:00am'];
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
it('supports day match', () => {
|
it('supports day match', () => {
|
||||||
config.schedule = 'on friday and saturday';
|
config.schedule = 'on friday and saturday';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(true);
|
expect(res).toBe(true);
|
||||||
});
|
});
|
||||||
it('supports day mismatch', () => {
|
it('supports day mismatch', () => {
|
||||||
config.schedule = 'on monday and tuesday';
|
config.schedule = 'on monday and tuesday';
|
||||||
const res = schedule.isPackageScheduled(config);
|
const res = schedule.isScheduledNow(config);
|
||||||
expect(res).toBe(false);
|
expect(res).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -96,7 +96,6 @@ Array [
|
||||||
\\"automerge\\": \\"none\\",
|
\\"automerge\\": \\"none\\",
|
||||||
\\"branchName\\": \\"renovate/{{depName}}-{{newVersionMajor}}.x\\",
|
\\"branchName\\": \\"renovate/{{depName}}-{{newVersionMajor}}.x\\",
|
||||||
\\"commitMessage\\": \\"{{semanticPrefix}}Update dependency {{depName}} to version {{newVersion}}\\",
|
\\"commitMessage\\": \\"{{semanticPrefix}}Update dependency {{depName}} to version {{newVersion}}\\",
|
||||||
\\"maintainYarnLock\\": false,
|
|
||||||
\\"labels\\": [],
|
\\"labels\\": [],
|
||||||
\\"assignees\\": [],
|
\\"assignees\\": [],
|
||||||
\\"reviewers\\": []
|
\\"reviewers\\": []
|
||||||
|
|
Loading…
Reference in a new issue