diff --git a/docs/configuration.md b/docs/configuration.md index dc22d9aa838ef6d1dd7ad9b609719612d18d8e60..c6ca5d55258277aea1ecd1192cf902a230558e0f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -84,7 +84,7 @@ $ node renovate --help --respect-latest [boolean] Ignore versions newer than npm "latest" version --recreate-closed [boolean] Recreate PRs even if same ones were closed previously --rebase-stale-prs [boolean] Rebase stale PRs (GitHub only) - --maintain-yarn-lock [boolean] Keep yarn.lock updated in base branch (no monorepo support) + --maintain-yarn-lock [boolean] Keep yarn.lock files updated in base branch --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 --labels <list> Labels to add to Pull Request @@ -142,7 +142,7 @@ Obviously, you can't set repository or package file location with this method. | `commitMessage` | Commit message template | string | `"Update dependency {{depName}} to version {{newVersion}}"` | | | | `prTitle` | Pull Request title template | string | `"{{#if isPin}}Pin{{else}}Update{{/if}} dependency {{depName}} to version {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}{{newVersionMajor}}.x{{else}}{{newVersion}}{{/if}}{{/if}}"` | | | | `prBody` | Pull Request body template | string | `"This Pull Request updates dependency {{depName}} from version `{{currentVersion}}` to `{{newVersion}}`\n\n{{changelog}}"` | | | -| `maintainYarnLock` | Keep yarn.lock updated in base branch (no monorepo support) | boolean | `false` | `RENOVATE_MAINTAIN_YARN_LOCK` | `--maintain-yarn-lock` | +| `maintainYarnLock` | Keep yarn.lock files updated in base branch | boolean | `false` | `RENOVATE_MAINTAIN_YARN_LOCK` | `--maintain-yarn-lock` | | `yarnMaintenanceBranchName` | Branch name template when maintaining yarn.lock | string | `"renovate/yarn-lock"` | | | | `yarnMaintenanceCommitMessage` | Commit message template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | | | | `yarnMaintenancePrTitle` | Pull Request title template when maintaining yarn.lock | string | `"Renovate yarn.lock file"` | | | diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 683764ee94c92f55a82089c481742e5c2eadedbe..aa0c3f85155f7a1f3a1f764490f972857baceac2 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -123,7 +123,7 @@ const options = [ // Yarn Lock Maintenance { name: 'maintainYarnLock', - description: 'Keep yarn.lock updated in base branch (no monorepo support)', + description: 'Keep yarn.lock files updated in base branch', type: 'boolean', default: false, }, diff --git a/lib/worker.js b/lib/worker.js index d440a6cdd446da509217c233d019ae972a09c0d4..69bb958c7cbe693e8f969e6ee28b0600822243b6 100644 --- a/lib/worker.js +++ b/lib/worker.js @@ -1,5 +1,4 @@ const logger = require('winston'); -const path = require('path'); const stringify = require('json-stringify-pretty-compact'); const githubApi = require('./api/github'); const gitlabApi = require('./api/gitlab'); @@ -19,7 +18,6 @@ module.exports = { updateBranch, assignDepConfigs, getDepTypeConfig, - maintainYarnLock, }; // This function manages the queue per-package file @@ -67,7 +65,12 @@ async function processPackageFile(repoName, packageFile, packageConfig) { const upgrades = await findUpgrades(dependencies); // Process all upgrades sequentially if (config.maintainYarnLock) { - await maintainYarnLock(config); + const upgrade = Object.assign({}, config, { upgradeType: 'maintainYarnLock' }); + upgrade.upgradeType = 'maintainYarnLock'; + upgrade.branchName = upgrade.yarnMaintenanceBranchName; + upgrade.prTitle = upgrade.yarnMaintenancePrTitle; + upgrade.prBody = upgrade.yarnMaintenancePrBody; + upgrades.push(upgrade); } return upgrades; } @@ -126,31 +129,6 @@ function getDepTypeConfig(depTypes, depTypeName) { return depTypeConfig; } -async function maintainYarnLock(inputConfig) { - const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile); - const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock'); - logger.debug(`Checking for ${yarnLockFileName}`); - const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName); - if (!existingYarnLock) { - return; - } - logger.debug('Found existing yarn.lock file'); - const newYarnLock = await branchWorker.getYarnLockFile(packageContent, inputConfig); - if (existingYarnLock === newYarnLock.contents) { - logger.debug('Yarn lock file does not need updating'); - return; - } - logger.debug('Yarn lock needs updating'); - // API will know whether to create new branch or not - const params = Object.assign({}, inputConfig); - const commitMessage = handlebars.compile(params.yarnMaintenanceCommitMessage)(params); - params.branchName = params.yarnMaintenanceBranchName; - params.prTitle = params.yarnMaintenancePrTitle; - params.prBody = params.yarnMaintenancePrBody; - await inputConfig.api.commitFilesToBranch(params.branchName, [newYarnLock], commitMessage); - prWorker.ensurePr(params); -} - async function findUpgrades(dependencies) { const allUpgrades = []; // findDepUpgrades can add more than one upgrade to allUpgrades @@ -222,12 +200,15 @@ async function updateBranch(upgrades) { logger.verbose(`branchName '${branchName}' length is ${upgrades.length}`); try { - if (!upgrade0.recreateClosed && await upgrade0.api.checkForClosedPr(branchName, prTitle)) { + if (upgrade0.upgradeType !== 'maintainYarnLock' && + !upgrade0.recreateClosed && await upgrade0.api.checkForClosedPr(branchName, prTitle)) { logger.verbose(`Skipping ${branchName} upgrade as matching closed PR already existed`); return; } - await branchWorker.ensureBranch(upgrades); - await prWorker.ensurePr(upgrade0); + const branchCreated = await branchWorker.ensureBranch(upgrades); + if (branchCreated) { + await prWorker.ensurePr(upgrade0); + } } catch (error) { logger.error(`Error updating branch ${branchName}: ${error}`); // Don't throw here - we don't want to stop the other renovations diff --git a/lib/workers/branch.js b/lib/workers/branch.js index 52a7a4d068bb3cf52aaa4709dbdbe58a53155a9c..eb65ba4b01e7107dfc4a47afaa26e19124b2e3b1 100644 --- a/lib/workers/branch.js +++ b/lib/workers/branch.js @@ -8,6 +8,7 @@ module.exports = { getParentBranch, getYarnLockFile, ensureBranch, + maintainYarnLock, }; async function getParentBranch(branchName, config) { @@ -70,6 +71,28 @@ async function getYarnLockFile(packageFile, packageContent, api) { }); } +async function maintainYarnLock(inputConfig) { + logger.debug(`maintainYarnLock(${JSON.stringify(inputConfig)})`); + const packageContent = await inputConfig.api.getFileContent(inputConfig.packageFile); + const yarnLockFileName = path.join(path.dirname(inputConfig.packageFile), 'yarn.lock'); + logger.debug(`Checking for ${yarnLockFileName}`); + const existingYarnLock = await inputConfig.api.getFileContent(yarnLockFileName); + logger.silly(`existingYarnLock:\n${existingYarnLock}`); + if (!existingYarnLock) { + return null; + } + logger.debug('Found existing yarn.lock file'); + const newYarnLock = + await getYarnLockFile(inputConfig.packageFile, packageContent, inputConfig.api); + logger.silly(`newYarnLock:\n${newYarnLock.contents}`); + if (existingYarnLock.toString() === newYarnLock.contents.toString()) { + logger.debug('Yarn lock file does not need updating'); + return null; + } + logger.debug('Yarn lock needs updating'); + return newYarnLock; +} + // Ensure branch exists with appropriate content async function ensureBranch(upgrades) { logger.debug(`ensureBranch(${JSON.stringify(upgrades)})`); @@ -81,29 +104,38 @@ async function ensureBranch(upgrades) { const commitMessage = handlebars.compile(upgrades[0].commitMessage)(upgrades[0]); const api = upgrades[0].api; const packageFiles = {}; + const commitFiles = []; for (const upgrade of upgrades) { - // See if this is the first time editing this file - if (!packageFiles[upgrade.packageFile]) { - // If we are rebasing then existing content will be from master - packageFiles[upgrade.packageFile] = - await api.getFileContent(upgrade.packageFile, parentBranch); - } - const newContent = packageJsonHelper.setNewValue( - packageFiles[upgrade.packageFile], - upgrade.depType, - upgrade.depName, - upgrade.newVersion); - if (packageFiles[upgrade.packageFile] === newContent) { - logger.debug('packageFile content unchanged'); - delete packageFiles[upgrade.packageFile]; + if (upgrade.upgradeType === 'maintainYarnLock') { + const newYarnLock = await maintainYarnLock(upgrade); + if (newYarnLock) { + commitFiles.push(newYarnLock); + } } else { - logger.debug('Updating packageFile content'); - packageFiles[upgrade.packageFile] = newContent; + // See if this is the first time editing this file + if (!packageFiles[upgrade.packageFile]) { + // If we are rebasing then existing content will be from master + packageFiles[upgrade.packageFile] = + await api.getFileContent(upgrade.packageFile, parentBranch); + } + const newContent = packageJsonHelper.setNewValue( + packageFiles[upgrade.packageFile], + upgrade.depType, + upgrade.depName, + upgrade.newVersion); + if (packageFiles[upgrade.packageFile] === newContent) { + logger.debug('packageFile content unchanged'); + delete packageFiles[upgrade.packageFile]; + } else { + logger.debug('Updating packageFile content'); + packageFiles[upgrade.packageFile] = newContent; + } } } if (Object.keys(packageFiles).length > 0) { - const commitFiles = []; + logger.debug(`${Object.keys(packageFiles).length} package file(s) need updating.`); for (const packageFile of Object.keys(packageFiles)) { + logger.debug(`Adding ${packageFile}`); commitFiles.push({ name: packageFile, contents: packageFiles[packageFile], @@ -112,11 +144,17 @@ async function ensureBranch(upgrades) { await module.exports.getYarnLockFile(packageFile, packageFiles[packageFile], api); if (yarnLockFile) { // Add new yarn.lock file too + logger.debug(`Adding ${yarnLockFile.name}`); commitFiles.push(yarnLockFile); } } - + } + if (commitFiles.length) { + logger.debug(`Commit ${commitFiles.length} files to branch ${branchName}`); // API will know whether to create new branch or not await api.commitFilesToBranch(branchName, commitFiles, commitMessage, parentBranch); + return true; } + logger.debug(`No files to commit to branch ${branchName}`); + return false; } diff --git a/readme.md b/readme.md index 30bc5a2095335f29d534e5b6c1638e5a8c559fe8..24c48f4c4b30489712165bf902aeeb72d87a0adc 100644 --- a/readme.md +++ b/readme.md @@ -53,7 +53,7 @@ $ node renovate --help --respect-latest [boolean] Ignore versions newer than npm "latest" version --recreate-closed [boolean] Recreate PRs even if same ones were closed previously --rebase-stale-prs [boolean] Rebase stale PRs (GitHub only) - --maintain-yarn-lock [boolean] Keep yarn.lock updated in base branch (no monorepo support) + --maintain-yarn-lock [boolean] Keep yarn.lock files updated in base branch --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 --labels <list> Labels to add to Pull Request