diff --git a/lib/manager/docker/resolve.js b/lib/manager/docker/resolve.js index e6108c50ba65657f25d7ccc0d738485e1dd9333a..cedb0a4060189d7fd8958b3317c4c3097e5f7c39 100644 --- a/lib/manager/docker/resolve.js +++ b/lib/manager/docker/resolve.js @@ -11,8 +11,7 @@ async function resolvePackageFile(config, inputFile) { `Resolving packageFile ${JSON.stringify(packageFile.packageFile)}` ); packageFile.content = await config.api.getFileContent( - packageFile.packageFile, - config.contentBranch + packageFile.packageFile ); if (!packageFile.content) { logger.debug('No packageFile content'); diff --git a/lib/manager/resolve.js b/lib/manager/resolve.js new file mode 100644 index 0000000000000000000000000000000000000000..00f64e8d296ee22e949a631cdf832ca147f28b21 --- /dev/null +++ b/lib/manager/resolve.js @@ -0,0 +1,141 @@ +const path = require('path'); + +const { migrateAndValidate } = require('../config/migrate-validate'); +const presets = require('../config/presets'); + +const manager = require('./index'); +const dockerResolve = require('../manager/docker/resolve'); +const { mergeChildConfig } = require('../config'); +const { checkMonorepos } = require('../manager/npm/monorepos'); + +module.exports = { + resolvePackageFiles, +}; + +async function resolvePackageFiles(config) { + const { logger } = config; + logger.trace({ config }, 'resolvePackageFiles()'); + const allPackageFiles = config.packageFiles.length + ? config.packageFiles + : await manager.detectPackageFiles(config); + const packageFiles = []; + for (let packageFile of allPackageFiles) { + packageFile = + typeof packageFile === 'string' ? { packageFile } : packageFile; + if (packageFile.packageFile.endsWith('package.json')) { + logger.debug(`Resolving packageFile ${JSON.stringify(packageFile)}`); + const pFileRaw = await config.api.getFileContent(packageFile.packageFile); + if (!pFileRaw) { + logger.info( + { packageFile: packageFile.packageFile }, + 'Cannot find package.json' + ); + config.errors.push({ + depName: packageFile.packageFile, + message: 'Cannot find package.json', + }); + } else { + try { + packageFile.content = JSON.parse(pFileRaw); + } catch (err) { + logger.info( + { packageFile: packageFile.packageFile }, + 'Cannot parse package.json' + ); + config.warnings.push({ + depName: packageFile.packageFile, + message: 'Cannot parse package.json (invalid JSON)', + }); + } + } + if (!config.ignoreNpmrcFile) { + packageFile.npmrc = await config.api.getFileContent( + path.join(path.dirname(packageFile.packageFile), '.npmrc') + ); + } + if (!packageFile.npmrc) { + delete packageFile.npmrc; + } + packageFile.yarnrc = await config.api.getFileContent( + path.join(path.dirname(packageFile.packageFile), '.yarnrc') + ); + if (!packageFile.yarnrc) { + delete packageFile.yarnrc; + } + if (packageFile.content) { + // hoist renovate config if exists + if (packageFile.content.renovate) { + logger.debug( + { + packageFile: packageFile.packageFile, + config: packageFile.content.renovate, + }, + `Found package.json renovate config` + ); + const migratedConfig = migrateAndValidate( + config, + packageFile.content.renovate + ); + logger.debug( + { config: migratedConfig }, + 'package.json migrated config' + ); + const resolvedConfig = await presets.resolveConfigPresets( + migratedConfig, + config.logger + ); + logger.debug( + { config: resolvedConfig }, + 'package.json resolved config' + ); + Object.assign(packageFile, resolvedConfig); + delete packageFile.content.renovate; + } else { + logger.debug( + { packageFile: packageFile.packageFile }, + `No renovate config` + ); + } + // Detect if lock files are used + const yarnLockFileName = path.join( + path.dirname(packageFile.packageFile), + 'yarn.lock' + ); + packageFile.yarnLock = await config.api.getFileContent( + yarnLockFileName + ); + if (packageFile.yarnLock) { + logger.debug( + { packageFile: packageFile.packageFile }, + 'Found yarn.lock' + ); + } + const packageLockFileName = path.join( + path.dirname(packageFile.packageFile), + 'package-lock.json' + ); + packageFile.packageLock = await config.api.getFileContent( + packageLockFileName + ); + if (packageFile.packageLock) { + logger.debug( + { packageFile: packageFile.packageFile }, + 'Found package-lock.json' + ); + } + } else { + continue; // eslint-disable-line + } + } else if (packageFile.packageFile.endsWith('package.js')) { + // meteor + packageFile = mergeChildConfig(config.meteor, packageFile); + } else if (packageFile.packageFile.endsWith('Dockerfile')) { + logger.debug('Resolving Dockerfile'); + packageFile = await dockerResolve.resolvePackageFile(config, packageFile); + } + if (packageFile) { + packageFiles.push(packageFile); + } + } + return checkMonorepos({ ...config, packageFiles }); +} diff --git a/lib/workers/repository/apis.js b/lib/workers/repository/apis.js deleted file mode 100644 index e78af34e8b5ee9e07aa85f37aefd2dd4c15c84d4..0000000000000000000000000000000000000000 --- a/lib/workers/repository/apis.js +++ /dev/null @@ -1,284 +0,0 @@ -const conventionalCommitsDetector = require('conventional-commits-detector'); -const path = require('path'); -const jsonValidator = require('json-dup-key-validator'); -const configParser = require('../../config'); -const presets = require('../../config/presets'); -// API -const githubPlatform = require('../../platform/github'); -const gitlabPlatform = require('../../platform/gitlab'); -const dockerResolve = require('../../manager/docker/resolve'); - -const { decryptConfig } = require('../../config/decrypt'); -const { migrateAndValidate } = require('../../config/migrate-validate'); - -module.exports = { - detectSemanticCommits, - getNpmrc, - initApis, - mergeRenovateJson, - resolvePackageFiles, -}; - -async function detectSemanticCommits(config) { - const { logger } = config; - const commitMessages = await config.api.getCommitMessages(); - logger.trace(`commitMessages=${JSON.stringify(commitMessages)}`); - const type = conventionalCommitsDetector(commitMessages); - if (type === 'unknown') { - logger.debug('No semantic commit type found'); - return false; - } - logger.debug( - `Found semantic commit type ${type} - enabling semantic commits` - ); - return true; -} - -// Check for .npmrc in repository and pass it to npm api if found -async function getNpmrc(config) { - if (config.ignoreNpmrcFile) { - return config; - } - const { logger } = config; - let npmrc; - try { - npmrc = await config.api.getFileContent('.npmrc'); - if (npmrc) { - logger.debug('Found .npmrc file in repository'); - } - } catch (err) { - logger.error('Failed to set .npmrc'); - } - return { ...config, npmrc }; -} - -async function initApis(inputConfig, token) { - function getApi(platform) { - if (platform === 'github') { - return githubPlatform; - } else if (platform === 'gitlab') { - return gitlabPlatform; - } - throw new Error(`Unknown platform: ${platform}`); - } - - const config = { ...inputConfig }; - config.api = getApi(config.platform); - const platformConfig = await config.api.initRepo( - config.repository, - token, - config.endpoint, - config.logger - ); - Object.assign(config, platformConfig); - if (config.semanticCommits === null) { - config.semanticCommits = await module.exports.detectSemanticCommits(config); - } - return module.exports.getNpmrc(config); -} - -// Check for config in `renovate.json` -async function mergeRenovateJson(config, branchName) { - const { logger } = config; - let returnConfig = { ...config }; - const renovateJsonContent = await config.api.getFileContent( - 'renovate.json', - branchName - ); - if (!renovateJsonContent) { - logger.debug('No renovate.json found'); - return returnConfig; - } - logger.debug('Found renovate.json file'); - let renovateJson; - try { - let allowDuplicateKeys = true; - let jsonValidationError = jsonValidator.validate( - renovateJsonContent, - allowDuplicateKeys - ); - if (jsonValidationError) { - const error = { - depName: 'renovate.json', - message: jsonValidationError, - }; - logger.warn(error.message); - returnConfig.errors.push(error); - // Return unless error can be ignored - return returnConfig; - } - allowDuplicateKeys = false; - jsonValidationError = jsonValidator.validate( - renovateJsonContent, - allowDuplicateKeys - ); - if (jsonValidationError) { - const error = { - depName: 'renovate.json', - message: jsonValidationError, - }; - logger.warn(error.message); - returnConfig.errors.push(error); - // Return unless error can be ignored - } - renovateJson = JSON.parse(renovateJsonContent); - logger.debug({ config: renovateJson }, 'renovate.json config'); - const migratedConfig = migrateAndValidate(config, renovateJson); - logger.debug({ config: migratedConfig }, 'renovate.json migrated config'); - const decryptedConfig = decryptConfig( - migratedConfig, - logger, - config.privateKey - ); - const resolvedConfig = await presets.resolveConfigPresets( - decryptedConfig, - config.logger - ); - logger.debug({ config: resolvedConfig }, 'renovate.json resolved config'); - returnConfig = configParser.mergeChildConfig(returnConfig, resolvedConfig); - returnConfig.renovateJsonPresent = true; - } catch (err) { - logger.info({ err, renovateJsonContent }, 'Could not parse renovate.json'); - throw err; - } - return returnConfig; -} - -async function resolvePackageFiles(inputConfig) { - const config = { ...inputConfig }; - const { logger } = config; - logger.trace({ config }, 'resolvePackageFiles()'); - const packageFiles = []; - const contentBranch = config.repoIsOnboarded - ? config.baseBranch || undefined - : config.onboardingBranch; - config.contentBranch = contentBranch; - for (let packageFile of config.packageFiles) { - packageFile = - typeof packageFile === 'string' ? { packageFile } : packageFile; - if (packageFile.packageFile.endsWith('package.json')) { - logger.debug(`Resolving packageFile ${JSON.stringify(packageFile)}`); - const pFileRaw = await config.api.getFileContent( - packageFile.packageFile, - contentBranch - ); - if (!pFileRaw) { - logger.info( - { packageFile: packageFile.packageFile }, - 'Cannot find package.json' - ); - config.errors.push({ - depName: packageFile.packageFile, - message: 'Cannot find package.json', - }); - } else { - try { - packageFile.content = JSON.parse(pFileRaw); - } catch (err) { - logger.info( - { packageFile: packageFile.packageFile }, - 'Cannot parse package.json' - ); - config.warnings.push({ - depName: packageFile.packageFile, - message: 'Cannot parse package.json (invalid JSON)', - }); - } - } - if (!inputConfig.ignoreNpmrcFile) { - packageFile.npmrc = await config.api.getFileContent( - path.join(path.dirname(packageFile.packageFile), '.npmrc'), - contentBranch - ); - } - if (!packageFile.npmrc) { - delete packageFile.npmrc; - } - packageFile.yarnrc = await config.api.getFileContent( - path.join(path.dirname(packageFile.packageFile), '.yarnrc'), - contentBranch - ); - if (!packageFile.yarnrc) { - delete packageFile.yarnrc; - } - if (packageFile.content) { - // hoist renovate config if exists - if (packageFile.content.renovate) { - config.hasPackageJsonRenovateConfig = true; - logger.debug( - { - packageFile: packageFile.packageFile, - config: packageFile.content.renovate, - }, - `Found package.json renovate config` - ); - const migratedConfig = migrateAndValidate( - config, - packageFile.content.renovate - ); - logger.debug( - { config: migratedConfig }, - 'package.json migrated config' - ); - const resolvedConfig = await presets.resolveConfigPresets( - migratedConfig, - config.logger - ); - logger.debug( - { config: resolvedConfig }, - 'package.json resolved config' - ); - Object.assign(packageFile, resolvedConfig); - delete packageFile.content.renovate; - } else { - logger.debug( - { packageFile: packageFile.packageFile }, - `No renovate config` - ); - } - // Detect if lock files are used - const yarnLockFileName = path.join( - path.dirname(packageFile.packageFile), - 'yarn.lock' - ); - packageFile.yarnLock = await config.api.getFileContent( - yarnLockFileName, - contentBranch - ); - if (packageFile.yarnLock) { - logger.debug( - { packageFile: packageFile.packageFile }, - 'Found yarn.lock' - ); - } - const packageLockFileName = path.join( - path.dirname(packageFile.packageFile), - 'package-lock.json' - ); - packageFile.packageLock = await config.api.getFileContent( - packageLockFileName, - contentBranch - ); - if (packageFile.packageLock) { - logger.debug( - { packageFile: packageFile.packageFile }, - 'Found package-lock.json' - ); - } - } else { - continue; // eslint-disable-line - } - } else if (packageFile.packageFile.endsWith('package.js')) { - // meteor - packageFile = configParser.mergeChildConfig(config.meteor, packageFile); - } else if (packageFile.packageFile.endsWith('Dockerfile')) { - logger.debug('Resolving Dockerfile'); - packageFile = await dockerResolve.resolvePackageFile(config, packageFile); - } - if (packageFile) { - packageFiles.push(packageFile); - } - } - config.packageFiles = packageFiles; - return config; -} diff --git a/lib/workers/repository/cleanup.js b/lib/workers/repository/cleanup.js index b58232b1af9f87f9fe515f4d75c80c078c2ad5df..15ecb05abff6bbfe49c10cbdc37739ce2705098c 100644 --- a/lib/workers/repository/cleanup.js +++ b/lib/workers/repository/cleanup.js @@ -2,11 +2,17 @@ module.exports = { pruneStaleBranches, }; -async function pruneStaleBranches(config, branchList) { - const { logger } = config; +async function pruneStaleBranches(config) { + // TODO: try/catch + const { branchList, logger } = config; logger.debug('Removing any stale branches'); - logger.trace({ config, branchList }, `pruneStaleBranches`); + logger.trace({ config }, `pruneStaleBranches`); + if (!config.branchList) { + logger.debug('No branchList'); + return; + } if (config.platform !== 'github') { + // TODO: Implement for GitLab logger.debug('Platform is not GitHub - returning'); return; } @@ -14,36 +20,16 @@ async function pruneStaleBranches(config, branchList) { config.branchPrefix ); logger.debug(`renovateBranches=${renovateBranches}`); - if ( - renovateBranches.indexOf(`${config.branchPrefix}lock-file-maintenance`) !== - -1 - ) { + const lockFileBranch = `${config.branchPrefix}lock-file-maintenance`; + if (renovateBranches.includes(lockFileBranch)) { logger.debug('Checking lock file branch'); - const pr = await config.api.getBranchPr( - `${config.branchPrefix}lock-file-maintenance` - ); - if (pr && pr.isClosed) { - logger.info( - 'Deleting lock file maintenance branch as PR has been closed' - ); - await config.api.deleteBranch( - `${config.branchPrefix}lock-file-maintenance` - ); - } else if (pr && pr.isUnmergeable) { + const pr = await config.api.getBranchPr(lockFileBranch); + if (pr && pr.isUnmergeable) { logger.info('Deleting lock file maintenance branch as it is unmergeable'); - await config.api.deleteBranch( - `${config.branchPrefix}lock-file-maintenance` - ); - } else if (pr && pr.changed_files === 0) { - logger.info( - 'Deleting lock file maintenance branch as it has no changed files' - ); - await config.api.deleteBranch( - `${config.branchPrefix}lock-file-maintenance` - ); + await config.api.deleteBranch(lockFileBranch); } renovateBranches = renovateBranches.filter( - branch => branch !== `${config.branchPrefix}lock-file-maintenance` + branch => branch !== lockFileBranch ); } const remainingBranches = renovateBranches.filter( diff --git a/lib/workers/repository/configured.js b/lib/workers/repository/configured.js new file mode 100644 index 0000000000000000000000000000000000000000..a758ed2759ea2a52486bf230bb797cc6a42967f1 --- /dev/null +++ b/lib/workers/repository/configured.js @@ -0,0 +1,12 @@ +module.exports = { + checkIfConfigured, +}; + +function checkIfConfigured(config) { + if (config.enabled === false) { + throw new Error('disabled'); + } + if (config.isFork && !config.renovateFork) { + throw new Error('fork'); + } +} diff --git a/lib/workers/repository/error.js b/lib/workers/repository/error.js new file mode 100644 index 0000000000000000000000000000000000000000..43bdf43aa107f8de7c815adaac44ddd92db4934c --- /dev/null +++ b/lib/workers/repository/error.js @@ -0,0 +1,28 @@ +module.exports = { + handleError, +}; + +function handleError(config, err) { + const { logger } = config; + if (err.message === 'uninitiated') { + logger.info('Repository is uninitiated - skipping'); + return err.message; + } else if (err.message === 'disabled') { + logger.info('Repository is disabled - skipping'); + return err.message; + } else if (err.message === 'fork') { + logger.info('Repository is a fork and not manually configured - skipping'); + return err.message; + } else if (err.message === 'no-package-files') { + logger.info('Repository has no package files - skipping'); + return err.message; + } else if (err.message === 'loops>5') { + logger.error('Repository has looped 5 times already'); + return err.message; + } + // Swallow this error so that other repositories can be processed + logger.error({ err }, `Repository has unknown error`); + // delete branchList to avoid cleaning up branches + delete config.branchList; // eslint-disable-line no-param-reassign + return 'unknown-error'; +} diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js index 9de200ad23660b847f7c5a5aebcace64babaf4ad..602fed0ebe7a6cf5a0b886cf2827e0a52356edb7 100644 --- a/lib/workers/repository/index.js +++ b/lib/workers/repository/index.js @@ -1,163 +1,40 @@ -const convertHrTime = require('convert-hrtime'); -const tmp = require('tmp-promise'); -const manager = require('../../manager'); -// Workers -const branchWorker = require('../branch'); -// children -const apis = require('./apis'); -const onboarding = require('./onboarding'); -const upgrades = require('./upgrades'); -const cleanup = require('./cleanup'); - -const { checkMonorepos } = require('../../manager/npm/monorepos'); +const { initApis } = require('./init/apis'); +const { initRepo } = require('./init'); +const { determineUpdates } = require('./updates'); const { ensureOnboardingPr } = require('./onboarding/pr'); +const { writeUpdates } = require('./write'); +const { handleError } = require('./error'); +const { pruneStaleBranches } = require('./cleanup'); + +const { resolvePackageFiles } = require('../../manager/resolve'); module.exports = { renovateRepository, }; -async function renovateRepository(repoConfig, token) { - let config = { ...repoConfig }; +async function renovateRepository(repoConfig, token, loop = 1) { + let config = { ...repoConfig, branchList: [] }; const { logger } = config; - logger.trace({ config }, 'renovateRepository'); - config.tmpDir = await tmp.dir({ unsafeCleanup: true }); - config.errors = []; - config.warnings = []; - async function renovateRepositoryInner(count = 1) { - // istanbul ignore if - if (count > 5) { - // This is an arbitrary number added in to cut short any unintended infinite recursion - throw new Error('Existing renovateRepositoryInner after 5 loops'); - } - logger.info(`renovateRepository loop ${count}`); - let branchList = []; - config = await apis.initApis(config, token); - config = await apis.mergeRenovateJson(config); - if (config.enabled === false) { - logger.debug('repository is disabled'); - await cleanup.pruneStaleBranches(config, []); - return null; - } - if (config.isFork) { - if (config.renovateFork) { - logger.info('Processing forked repository'); - } else { - logger.debug('repository is a fork and not manually configured'); - await cleanup.pruneStaleBranches(config, []); - return null; - } - } - if (config.baseBranch) { - // Renovate should read content and target PRs here - if (await config.api.branchExists(config.baseBranch)) { - config.api.setBaseBranch(config.baseBranch); - } else { - // Warn and ignore setting (use default branch) - const message = `The configured baseBranch "${config.baseBranch}" is not present. Ignoring`; - config.errors.push({ - depName: 'baseBranch', - message, - }); - logger.warn(message); - } - } - config = await onboarding.getOnboardingStatus(config); - // Detect package files in default branch if not manually provisioned - if (config.packageFiles.length === 0) { - logger.debug('Detecting package files'); - config.packageFiles = await manager.detectPackageFiles(config); - // If we can't detect any package.json then return - if (config.packageFiles.length === 0) { - logger.info('Cannot detect package files'); - // istanbul ignore if - if (config.repoIsOnboarded === false) { - logger.warn('Need to delete onboarding PR'); - const pr = await config.api.getBranchPr(config.onboardingBranch); - if (pr) { - logger.info('Found onboarding PR'); - await config.api.updatePr( - pr.number, - 'Configure Renovate - canceled', - 'This PR was created in error and is now being deleted automatically. Sorry for the inconvenience.' - ); - await config.api.deleteBranch(config.onboardingBranch); - throw new Error('no package files'); - } - } - return null; - } - logger.info( - { - packageFiles: config.packageFiles, - count: config.packageFiles.length, - }, - `Detected package files` - ); - } - logger.debug('Resolving package files and content'); - config = await apis.resolvePackageFiles(config); - config = await checkMonorepos(config); - logger.trace({ config }, 'post-packageFiles config'); - // TODO: why is this fix needed?! - config.logger = logger; - const allUpgrades = await upgrades.determineRepoUpgrades(config); - const res = await upgrades.branchifyUpgrades(allUpgrades, logger); - config.errors = config.errors.concat(res.errors); - config.warnings = config.warnings.concat(res.warnings); - let branchUpgrades = res.upgrades; - logger.info( - { branches: branchUpgrades.map(upg => upg.branchName) }, - 'branchUpgrades' - ); - logger.debug(`Updating ${branchUpgrades.length} branch(es)`); - logger.trace({ config: branchUpgrades }, 'branchUpgrades'); - if (config.repoIsOnboarded) { - logger.info(`Processing ${branchUpgrades.length} branch(es)`); - const branchStartTime = process.hrtime(); - branchList = branchUpgrades.map(upgrade => upgrade.branchName); - if (branchUpgrades.some(upg => upg.isPin)) { - logger.info('Processing only pin branches first'); - branchUpgrades = branchUpgrades.filter(upg => upg.isPin); - } - for (const branchUpgrade of branchUpgrades) { - const branchResult = await branchWorker.processBranch( - branchUpgrade, - config.errors, - config.warnings - ); - if (branchResult === 'automerged') { - // Stop procesing other branches because base branch has been changed by an automerge - logger.info('Restarting repo renovation after automerge'); - return renovateRepositoryInner(count + 1); - } - } - logger.info( - { seconds: convertHrTime(process.hrtime(branchStartTime)).seconds }, - 'Finished updating branches' - ); - } else { - await ensureOnboardingPr({ ...config, branches: branchUpgrades }); - logger.info('"Configure Renovate" PR needs to be closed first'); - branchList = [`${config.branchPrefix}configure`]; - } - logger.debug(`branchList=${branchList}`); - return branchList; - } + logger.trace({ config, loop }, 'renovateRepository()'); try { - const branchList = await renovateRepositoryInner(); - if (branchList) { - await cleanup.pruneStaleBranches(config, branchList); - } + if (loop > 5) { + throw new Error('loops>5'); + } + config = await initApis(config, token); + config = await initRepo(config); + config = await resolvePackageFiles(config); + config = await determineUpdates(config); + const res = config.repoIsOnboarded + ? await writeUpdates(config) + : await ensureOnboardingPr(config); + if (res === 'automerged') { + logger.info('Restarting repo renovation after automerge'); + return renovateRepository(repoConfig, token, loop + 1); + } + return res; } catch (err) { - // Swallow this error so that other repositories can be processed - if (err.message === 'uninitiated') { - logger.info('Repository is uninitiated - skipping'); - } else if (err.message === 'no package files') { - logger.info('Repository has no package files - skipping'); - } else { - logger.error(`Failed to process repository: ${err.message}`); - logger.debug({ err }); - } + return handleError(config, err); + } finally { + await pruneStaleBranches(config); } - config.tmpDir.cleanup(); } diff --git a/lib/workers/repository/init/apis.js b/lib/workers/repository/init/apis.js new file mode 100644 index 0000000000000000000000000000000000000000..6855575cb4993997a4f44d39da37b8bb0547a43c --- /dev/null +++ b/lib/workers/repository/init/apis.js @@ -0,0 +1,36 @@ +const githubPlatform = require('../../../platform/github'); +const gitlabPlatform = require('../../../platform/gitlab'); +const { detectSemanticCommits } = require('./semantic'); + +function assignPlatform(config) { + const platforms = { + github: githubPlatform, + gitlab: gitlabPlatform, + }; + return { ...config, api: platforms[config.platform] }; +} + +async function getPlatformConfig(config) { + const platformConfig = await config.api.initRepo( + config.repository, + config.token, + config.endpoint, + config.logger + ); + return { + ...config, + ...platformConfig, + }; +} + +async function initApis(input, token) { + let config = { ...input, token }; + config = await assignPlatform(config); + config = await getPlatformConfig(config); + config = await detectSemanticCommits(config); + return config; +} + +module.exports = { + initApis, +}; diff --git a/lib/workers/repository/init/base.js b/lib/workers/repository/init/base.js new file mode 100644 index 0000000000000000000000000000000000000000..314ac5633bf03c6c028eb7a27810dafc3d356085 --- /dev/null +++ b/lib/workers/repository/init/base.js @@ -0,0 +1,25 @@ +async function checkBaseBranch(config) { + const { logger } = config; + let error = []; + if (config.baseBranch) { + // Renovate should read content and target PRs here + if (await config.api.branchExists(config.baseBranch)) { + await config.api.setBaseBranch(config.baseBranch); + } else { + // Warn and ignore setting (use default branch) + const message = `The configured baseBranch "${config.baseBranch}" is not present. Ignoring`; + error = [ + { + depName: 'baseBranch', + message, + }, + ]; + logger.warn(message); + } + } + return { ...config, errors: config.errors.concat(error) }; +} + +module.exports = { + checkBaseBranch, +}; diff --git a/lib/workers/repository/init/config.js b/lib/workers/repository/init/config.js new file mode 100644 index 0000000000000000000000000000000000000000..e6433014b3b151cd96bc107a483a1e1ace5de983 --- /dev/null +++ b/lib/workers/repository/init/config.js @@ -0,0 +1,68 @@ +const jsonValidator = require('json-dup-key-validator'); + +const { mergeChildConfig } = require('../../../config'); +const { migrateAndValidate } = require('../../../config/migrate-validate'); +const { decryptConfig } = require('../../../config/decrypt'); +const presets = require('../../../config/presets'); + +// Check for config in `renovate.json` +async function mergeRenovateJson(config) { + const { logger } = config; + let returnConfig = { ...config }; + const renovateJsonContent = await config.api.getFileContent('renovate.json'); + if (!renovateJsonContent) { + logger.debug('No renovate.json found'); + return returnConfig; + } + logger.debug('Found renovate.json file'); + let allowDuplicateKeys = true; + let jsonValidationError = jsonValidator.validate( + renovateJsonContent, + allowDuplicateKeys + ); + if (jsonValidationError) { + const error = { + depName: 'renovate.json', + message: jsonValidationError, + }; + logger.warn(error.message); + returnConfig.errors.push(error); + // Return unless error can be ignored + return returnConfig; + } + allowDuplicateKeys = false; + jsonValidationError = jsonValidator.validate( + renovateJsonContent, + allowDuplicateKeys + ); + if (jsonValidationError) { + const error = { + depName: 'renovate.json', + message: jsonValidationError, + }; + logger.warn(error.message); + returnConfig.errors.push(error); + // Return unless error can be ignored + } + const renovateJson = JSON.parse(renovateJsonContent); + logger.debug({ config: renovateJson }, 'renovate.json config'); + const migratedConfig = migrateAndValidate(config, renovateJson); + logger.debug({ config: migratedConfig }, 'renovate.json migrated config'); + const decryptedConfig = decryptConfig( + migratedConfig, + config.logger, + config.privateKey + ); + const resolvedConfig = await presets.resolveConfigPresets( + decryptedConfig, + logger + ); + logger.trace({ config: resolvedConfig }, 'renovate.json resolved config'); + returnConfig = mergeChildConfig(returnConfig, resolvedConfig); + returnConfig.renovateJsonPresent = true; + return returnConfig; +} + +module.exports = { + mergeRenovateJson, +}; diff --git a/lib/workers/repository/init/index.js b/lib/workers/repository/init/index.js new file mode 100644 index 0000000000000000000000000000000000000000..d2fa4c196a8f11ad0067b6d4d255dafbaf2968c6 --- /dev/null +++ b/lib/workers/repository/init/index.js @@ -0,0 +1,18 @@ +const { checkOnboardingBranch } = require('../onboarding/branch'); +const { checkIfConfigured } = require('../configured'); + +const { checkBaseBranch } = require('./base'); +const { mergeRenovateJson } = require('./config'); + +async function initRepo(input) { + let config = { ...input, errors: [], warnings: [] }; + config = await checkOnboardingBranch(config); + config = await mergeRenovateJson(config); + checkIfConfigured(config); + await checkBaseBranch(config); + return config; +} + +module.exports = { + initRepo, +}; diff --git a/lib/workers/repository/init/semantic.js b/lib/workers/repository/init/semantic.js new file mode 100644 index 0000000000000000000000000000000000000000..8e4f365ab1131de82991f15b9f28447ccc6e4b74 --- /dev/null +++ b/lib/workers/repository/init/semantic.js @@ -0,0 +1,23 @@ +const conventionalCommitsDetector = require('conventional-commits-detector'); + +async function detectSemanticCommits(config) { + const { logger } = config; + if (config.semanticCommits !== null) { + return config; + } + const commitMessages = await config.api.getCommitMessages(); + logger.trace(`commitMessages=${JSON.stringify(commitMessages)}`); + const type = conventionalCommitsDetector(commitMessages); + if (type === 'unknown') { + logger.debug('No semantic commit type found'); + return { ...config, semanticCommits: false }; + } + logger.debug( + `Found semantic commit type ${type} - enabling semantic commits` + ); + return { ...config, semanticCommits: true }; +} + +module.exports = { + detectSemanticCommits, +}; diff --git a/lib/workers/repository/onboarding.js b/lib/workers/repository/onboarding.js deleted file mode 100644 index 4f18caf37ae7f655b2ace85560b68c5e1c59b228..0000000000000000000000000000000000000000 --- a/lib/workers/repository/onboarding.js +++ /dev/null @@ -1,64 +0,0 @@ -const apis = require('./apis'); -const manager = require('../../manager'); - -module.exports = { - createOnboardingBranch, - getOnboardingStatus, -}; - -async function createOnboardingBranch(inputConfig) { - const config = { ...inputConfig }; - const { logger } = config; - logger.debug('Creating onboarding branch'); - config.packageFiles = await manager.detectPackageFiles(config); - if (config.packageFiles.length === 0) { - throw new Error('no package files'); - } - const renovateJson = { - extends: ['config:base'], - }; - logger.info({ renovateJson }, 'Creating onboarding branch'); - await config.api.commitFilesToBranch( - config.onboardingBranch, - [ - { - name: 'renovate.json', - contents: `${JSON.stringify(renovateJson, null, 2)}\n`, - }, - ], - 'Add renovate.json' - ); - return config; -} - -async function getOnboardingStatus(inputConfig) { - let config = { ...inputConfig }; - const { logger } = config; - logger.debug('Checking if repo is onboarded'); - // Check if repository is configured - if (config.onboarding === false) { - logger.debug('Repo onboarding is disabled'); - return { ...config, repoIsOnboarded: true }; - } - if (config.renovateJsonPresent) { - logger.debug('Repo has renovate.json'); - return { ...config, repoIsOnboarded: true }; - } - config.onboardingBranch = `${config.branchPrefix}configure`; - const pr = await config.api.findPr( - config.onboardingBranch, - 'Configure Renovate' - ); - if (pr && pr.isClosed) { - logger.debug('Found closed Configure Renovate PR'); - return { ...config, repoIsOnboarded: true }; - } - if (pr) { - logger.debug(`Found existing onboarding PR #${pr.number}`); - } else { - config = await module.exports.createOnboardingBranch(config); - } - logger.debug('Merging renovate.json from onboarding branch'); - config = await apis.mergeRenovateJson(config, config.onboardingBranch); - return { ...config, repoIsOnboarded: false }; -} diff --git a/lib/workers/repository/onboarding/branch/check.js b/lib/workers/repository/onboarding/branch/check.js new file mode 100644 index 0000000000000000000000000000000000000000..15165500f1c65ce138c66e4a44e3b14938b347f9 --- /dev/null +++ b/lib/workers/repository/onboarding/branch/check.js @@ -0,0 +1,44 @@ +const findFile = async (config, fileName) => { + const { logger } = config; + logger.debug('findFile()'); + logger.trace({ config }); + const fileList = await config.api.getFileList(); + return fileList.includes(fileName); +}; + +const renovateJsonExists = config => findFile(config, 'renovate.json'); + +const closedPrExists = config => + config.api.findPr( + `${config.branchPrefix}configure`, + 'Configure Renovate', + 'closed' + ); + +const isOnboarded = async config => { + const { logger } = config; + logger.debug('isOnboarded()'); + if (await renovateJsonExists(config)) { + logger.debug('renovate.json exists'); + return true; + } + logger.debug('renovate.json not found'); + if (await closedPrExists(config)) { + logger.debug('Found closed onboarding PR'); + return true; + } + logger.debug('Found no closed onboarding PR'); + return false; +}; + +const onboardingPrExists = config => + config.api.findPr( + `${config.branchPrefix}configure`, + 'Configure Renovate', + 'open' + ); + +module.exports = { + isOnboarded, + onboardingPrExists, +}; diff --git a/lib/workers/repository/onboarding/branch/create.js b/lib/workers/repository/onboarding/branch/create.js new file mode 100644 index 0000000000000000000000000000000000000000..d957d5965832cfd5e33b00033c8f5df36c945def --- /dev/null +++ b/lib/workers/repository/onboarding/branch/create.js @@ -0,0 +1,22 @@ +async function createOnboardingBranch(config) { + const { logger } = config; + logger.debug('Creating onboarding branch'); + const renovateJson = { + extends: ['config:base'], + }; + logger.info({ renovateJson }, 'Creating onboarding branch'); + await config.api.commitFilesToBranch( + `${config.branchPrefix}configure`, + [ + { + name: 'renovate.json', + contents: `${JSON.stringify(renovateJson, null, 2)}\n`, + }, + ], + 'Add renovate.json' + ); +} + +module.exports = { + createOnboardingBranch, +}; diff --git a/lib/workers/repository/onboarding/branch/index.js b/lib/workers/repository/onboarding/branch/index.js new file mode 100644 index 0000000000000000000000000000000000000000..a0c842e5f4e9472ca6f4a8fc4fc90d1ec54f81de --- /dev/null +++ b/lib/workers/repository/onboarding/branch/index.js @@ -0,0 +1,32 @@ +const { detectPackageFiles } = require('../../../../manager'); +const { createOnboardingBranch } = require('./create'); +const { isOnboarded, onboardingPrExists } = require('./check'); + +async function checkOnboardingBranch(config) { + const { logger } = config; + logger.debug('checkOnboarding()'); + logger.trace({ config }); + const repoIsOnboarded = await isOnboarded(config); + if (repoIsOnboarded) { + logger.debug('Repo is onboarded'); + return { ...config, repoIsOnboarded }; + } + if (config.isFork) { + throw new Error('fork'); + } + logger.info('Repo is not onboarded'); + if (!await onboardingPrExists(config)) { + if ((await detectPackageFiles(config)).length === 0) { + throw new Error('no-package-files'); + } + logger.info('Need to create onboarding PR'); + await createOnboardingBranch(config); + } + await config.api.setBaseBranch(`${config.branchPrefix}configure`); + const branchList = [`${config.branchPrefix}configure`]; + return { ...config, repoIsOnboarded, branchList }; +} + +module.exports = { + checkOnboardingBranch, +}; diff --git a/lib/workers/repository/updates/branchify.js b/lib/workers/repository/updates/branchify.js new file mode 100644 index 0000000000000000000000000000000000000000..fcaa73d4496999d10a8d9142767bc9c2b8bacc97 --- /dev/null +++ b/lib/workers/repository/updates/branchify.js @@ -0,0 +1,65 @@ +const handlebars = require('handlebars'); + +const { generateBranchConfig } = require('./generate'); + +function branchifyUpgrades(config) { + const { logger } = config; + logger.debug('branchifyUpgrades'); + logger.trace({ config }); + const errors = []; + const warnings = []; + const branchUpgrades = {}; + const branches = []; + for (const upg of config.upgrades) { + const upgrade = { ...upg }; + // Split out errors and wrnings first + if (upgrade.type === 'error') { + errors.push(upgrade); + } else if (upgrade.type === 'warning') { + warnings.push(upgrade); + } else { + // Check whether to use a group name + let branchName; + if (upgrade.groupName) { + logger.debug('Using group branchName template'); + logger.debug( + `Dependency ${upgrade.depName} is part of group ${upgrade.groupName}` + ); + upgrade.groupSlug = + upgrade.groupSlug || + upgrade.groupName + .toString() + .toLowerCase() + .replace(/[^a-z0-9+]+/g, '-'); + branchName = handlebars.compile(upgrade.group.branchName)(upgrade); + } else { + logger.debug('Using regular branchName template'); + branchName = handlebars.compile(upgrade.branchName)(upgrade); + } + branchUpgrades[branchName] = branchUpgrades[branchName] || []; + branchUpgrades[branchName] = [upgrade].concat(branchUpgrades[branchName]); + } + } + logger.debug(`Returning ${Object.keys(branchUpgrades).length} branch(es)`); + for (const branchName of Object.keys(branchUpgrades)) { + const branch = generateBranchConfig(branchUpgrades[branchName], logger); + branch.branchName = branchName; + branch.logger = logger; + branches.push(branch); + } + const branchList = config.repoIsOnboarded + ? branches.map(upgrade => upgrade.branchName) + : config.branchList; + return { + ...config, + errors: config.errors.concat(errors), + warnings: config.warnings.concat(warnings), + branches, + branchList, + upgrades: null, + }; +} + +module.exports = { + branchifyUpgrades, +}; diff --git a/lib/workers/repository/updates/determine.js b/lib/workers/repository/updates/determine.js new file mode 100644 index 0000000000000000000000000000000000000000..d78d22977b0e882eadc24623e5e57695fce1a221 --- /dev/null +++ b/lib/workers/repository/updates/determine.js @@ -0,0 +1,52 @@ +const packageFileWorker = require('../../package-file'); +const { mergeChildConfig, filterConfig } = require('../../../config'); + +async function determineRepoUpgrades(config) { + const { logger } = config; + logger.debug('determineRepoUpgrades()'); + logger.trace({ config }); + let upgrades = []; + logger.debug(`Found ${config.packageFiles.length} package files`); + // Iterate through repositories sequentially + for (const packageFile of config.packageFiles) { + logger.debug({ packageFile }, 'Getting packageFile config'); + let packageFileConfig = mergeChildConfig(config, packageFile); + packageFileConfig = filterConfig(packageFileConfig, 'packageFile'); + packageFileConfig.logger = packageFileConfig.logger.child({ + repository: packageFileConfig.repository, + packageFile: packageFileConfig.packageFile, + }); + if (packageFileConfig.packageFile.endsWith('package.json')) { + logger.info( + { packageFile: packageFileConfig.packageFile }, + 'Renovating package.json dependencies' + ); + upgrades = upgrades.concat( + await packageFileWorker.renovatePackageFile(packageFileConfig) + ); + } else if (packageFileConfig.packageFile.endsWith('package.js')) { + logger.info('Renovating package.js (meteor) dependencies'); + upgrades = upgrades.concat( + await packageFileWorker.renovateMeteorPackageFile(packageFileConfig) + ); + } else if (packageFileConfig.packageFile.endsWith('Dockerfile')) { + logger.info('Renovating Dockerfile FROM'); + upgrades = upgrades.concat( + await packageFileWorker.renovateDockerfile(packageFileConfig) + ); + } + } + // Sanitize depNames + upgrades = upgrades.map(upgrade => ({ + ...upgrade, + depNameSanitized: upgrade.depName + ? upgrade.depName + .replace('@', '') + .replace('/', '-') + .toLowerCase() + : undefined, + })); + return { ...config, upgrades }; +} + +module.exports = { determineRepoUpgrades }; diff --git a/lib/workers/repository/updates/generate.js b/lib/workers/repository/updates/generate.js new file mode 100644 index 0000000000000000000000000000000000000000..13cba0e0d42122250735f64e14321610f8d70117 --- /dev/null +++ b/lib/workers/repository/updates/generate.js @@ -0,0 +1,52 @@ +const handlebars = require('handlebars'); + +function generateBranchConfig(branchUpgrades, logger) { + const config = { + upgrades: [], + }; + const hasGroupName = branchUpgrades[0].groupName !== null; + logger.debug(`hasGroupName: ${hasGroupName}`); + // Use group settings only if multiple upgrades or lazy grouping is disabled + const depNames = []; + branchUpgrades.forEach(upg => { + if (!depNames.includes(upg.depName)) { + depNames.push(upg.depName); + } + }); + const groupEligible = + depNames.length > 1 || branchUpgrades[0].lazyGrouping === false; + logger.debug(`groupEligible: ${groupEligible}`); + const useGroupSettings = hasGroupName && groupEligible; + logger.debug(`useGroupSettings: ${useGroupSettings}`); + for (const branchUpgrade of branchUpgrades) { + const upgrade = { ...branchUpgrade }; + if (useGroupSettings) { + // Now overwrite original config with group config + Object.assign(upgrade, upgrade.group); + } else { + delete upgrade.groupName; + } + // Delete group config regardless of whether it was applied + delete upgrade.group; + delete upgrade.lazyGrouping; + // Use templates to generate strings + logger.debug( + { branchName: upgrade.branchName, prTitle: upgrade.prTitle }, + 'Compiling branchName and prTitle' + ); + upgrade.branchName = handlebars.compile(upgrade.branchName)(upgrade); + upgrade.prTitle = handlebars.compile(upgrade.prTitle)(upgrade); + if (upgrade.semanticCommits) { + logger.debug('Upgrade has semantic commits enabled'); + upgrade.prTitle = `${upgrade.semanticPrefix} ${upgrade.prTitle.toLowerCase()}`; + } + logger.debug(`${upgrade.branchName}, ${upgrade.prTitle}`); + config.upgrades.push(upgrade); + } + // Now assign first upgrade's config as branch config + return { ...config, ...config.upgrades[0] }; +} + +module.exports = { + generateBranchConfig, +}; diff --git a/lib/workers/repository/updates/index.js b/lib/workers/repository/updates/index.js new file mode 100644 index 0000000000000000000000000000000000000000..8572ea739575c64e77ddbbbbd41d4cb9b5bf0e27 --- /dev/null +++ b/lib/workers/repository/updates/index.js @@ -0,0 +1,16 @@ +const { determineRepoUpgrades } = require('./determine'); +const { branchifyUpgrades } = require('./branchify'); + +module.exports = { + determineUpdates, +}; + +async function determineUpdates(input) { + let config = { ...input }; + const { logger } = config; + logger.debug('determineUpdates()'); + logger.trace({ config }); + config = await determineRepoUpgrades(config); + config = branchifyUpgrades(config); + return config; +} diff --git a/lib/workers/repository/upgrades.js b/lib/workers/repository/upgrades.js deleted file mode 100644 index b7280de06d18574f4a47edf83f98c0497b21b286..0000000000000000000000000000000000000000 --- a/lib/workers/repository/upgrades.js +++ /dev/null @@ -1,201 +0,0 @@ -const convertHrTime = require('convert-hrtime'); -const handlebars = require('handlebars'); -const configParser = require('../../config'); -const packageFileWorker = require('../package-file'); - -let logger = require('../../logger'); - -module.exports = { - determineRepoUpgrades, - groupByBranch, - generateConfig, - branchifyUpgrades, - getPackageFileConfig, -}; - -async function determineRepoUpgrades(config) { - logger.trace({ config }, 'determineRepoUpgrades'); - const startTime = process.hrtime(); - if (config.packageFiles.length === 0) { - logger.info('No package files found'); - } - let upgrades = []; - // Iterate through repositories sequentially - let index = 0; - for (const packageFile of config.packageFiles) { - logger.trace({ packageFile }, 'Getting packageFile config'); - const packageFileConfig = module.exports.getPackageFileConfig( - config, - index - ); - if (packageFileConfig.packageFile.endsWith('package.json')) { - logger.info( - { packageFile: packageFileConfig.packageFile }, - 'Renovating package.json dependencies' - ); - upgrades = upgrades.concat( - await packageFileWorker.renovatePackageFile(packageFileConfig) - ); - } else if (packageFileConfig.packageFile.endsWith('package.js')) { - logger.info('Renovating package.js (meteor) dependencies'); - upgrades = upgrades.concat( - await packageFileWorker.renovateMeteorPackageFile(packageFileConfig) - ); - } else if (packageFileConfig.packageFile.endsWith('Dockerfile')) { - logger.info('Renovating Dockerfile FROM'); - upgrades = upgrades.concat( - await packageFileWorker.renovateDockerfile(packageFileConfig) - ); - } - index += 1; - } - logger.info( - { seconds: convertHrTime(process.hrtime(startTime)).seconds }, - 'Finished determining repo upgrades' - ); - // Sanitize depNames - return upgrades.map(upgrade => ({ - ...upgrade, - depNameSanitized: upgrade.depName - ? upgrade.depName - .replace('@', '') - .replace('/', '-') - .toLowerCase() - : undefined, - })); -} - -function generateConfig(branchUpgrades) { - const config = { - upgrades: [], - }; - const hasGroupName = branchUpgrades[0].groupName !== null; - logger.debug(`hasGroupName: ${hasGroupName}`); - // Use group settings only if multiple upgrades or lazy grouping is disabled - const depNames = []; - branchUpgrades.forEach(upg => { - if (!depNames.includes(upg.depName)) { - depNames.push(upg.depName); - } - }); - const groupEligible = - depNames.length > 1 || branchUpgrades[0].lazyGrouping === false; - logger.debug(`groupEligible: ${groupEligible}`); - const useGroupSettings = hasGroupName && groupEligible; - logger.debug(`useGroupSettings: ${useGroupSettings}`); - for (const branchUpgrade of branchUpgrades) { - const upgrade = { ...branchUpgrade }; - if (useGroupSettings) { - // Now overwrite original config with group config - Object.assign(upgrade, upgrade.group); - } else { - delete upgrade.groupName; - } - // Delete group config regardless of whether it was applied - delete upgrade.group; - delete upgrade.lazyGrouping; - // Use templates to generate strings - logger.debug( - { branchName: upgrade.branchName, prTitle: upgrade.prTitle }, - 'Compiling branchName and prTitle' - ); - upgrade.branchName = handlebars.compile(upgrade.branchName)(upgrade); - upgrade.prTitle = handlebars.compile(upgrade.prTitle)(upgrade); - if (upgrade.semanticCommits) { - logger.debug('Upgrade has semantic commits enabled'); - upgrade.prTitle = `${upgrade.semanticPrefix} ${upgrade.prTitle.toLowerCase()}`; - } - logger.debug(`${upgrade.branchName}, ${upgrade.prTitle}`); - config.upgrades.push(upgrade); - } - // Now assign first upgrade's config as branch config - return { ...config, ...config.upgrades[0] }; -} - -function groupByBranch(upgrades) { - logger.trace({ config: upgrades }, 'groupByBranch'); - logger.info(`Processing ${upgrades.length} dependency upgrade(s)`); - const result = { - errors: [], - warnings: [], - branchUpgrades: {}, - }; - for (const upg of upgrades) { - const upgrade = { ...upg }; - // Split out errors and wrnings first - if (upgrade.type === 'error') { - result.errors.push(upgrade); - } else if (upgrade.type === 'warning') { - result.warnings.push(upgrade); - } else { - // Check whether to use a group name - let branchName; - if (upgrade.groupName) { - logger.debug('Using group branchName template'); - logger.debug( - `Dependency ${upgrade.depName} is part of group ${upgrade.groupName}` - ); - upgrade.groupSlug = - upgrade.groupSlug || - upgrade.groupName - .toString() - .toLowerCase() - .replace(/[^a-z0-9+]+/g, '-'); - branchName = handlebars.compile(upgrade.group.branchName)(upgrade); - } else { - logger.debug('Using regular branchName template'); - branchName = handlebars.compile(upgrade.branchName)(upgrade); - } - result.branchUpgrades[branchName] = - result.branchUpgrades[branchName] || []; - result.branchUpgrades[branchName] = [upgrade].concat( - result.branchUpgrades[branchName] - ); - } - } - logger.debug( - `Returning ${Object.keys(result.branchUpgrades).length} branch(es)` - ); - return result; -} - -function branchifyUpgrades(upgrades, parentLogger) { - logger = parentLogger || logger; - logger.debug('branchifyUpgrades'); - logger.trace({ config: upgrades }, 'branchifyUpgrades'); - const branchConfigs = []; - const res = module.exports.groupByBranch(upgrades); - for (const branchName of Object.keys(res.branchUpgrades)) { - logger = logger.child({ branch: branchName }); - const branchUpgrades = res.branchUpgrades[branchName]; - const branchConfig = module.exports.generateConfig(branchUpgrades); - branchConfig.branchName = branchName; - branchConfig.logger = logger; - branchConfigs.push(branchConfig); - } - return { - errors: res.errors, - warnings: res.warnings, - upgrades: branchConfigs, - }; -} - -function getPackageFileConfig(repoConfig, index) { - let packageFile = repoConfig.packageFiles[index]; - if (typeof packageFile === 'string') { - packageFile = { packageFile }; - } - const packageFileConfig = configParser.mergeChildConfig( - repoConfig, - packageFile - ); - packageFileConfig.logger = packageFileConfig.logger.child({ - repository: packageFileConfig.repository, - packageFile: packageFileConfig.packageFile, - }); - packageFileConfig.logger.trace( - { config: packageFileConfig }, - 'packageFileConfig' - ); - return configParser.filterConfig(packageFileConfig, 'packageFile'); -} diff --git a/lib/workers/repository/write.js b/lib/workers/repository/write.js new file mode 100644 index 0000000000000000000000000000000000000000..6c6f902f8497248012304eca1e7d5da7cb277582 --- /dev/null +++ b/lib/workers/repository/write.js @@ -0,0 +1,30 @@ +const tmp = require('tmp-promise'); + +const branchWorker = require('../branch'); + +module.exports = { + writeUpdates, +}; + +async function writeUpdates(config) { + const { logger } = config; + let { branches } = config; + logger.info(`Processing ${branches.length} branch(es)`); + if (branches.some(upg => upg.isPin)) { + branches = branches.filter(upg => upg.isPin); + logger.info(`Processing ${branches.length} "pin" PRs first`); + } + const tmpDir = await tmp.dir({ unsafeCleanup: true }); + try { + for (const branch of branches) { + const res = await branchWorker.processBranch({ ...branch, tmpDir }); + if (res === 'automerged') { + // Stop procesing other branches because base branch has been changed by an automerge + return 'automerged'; + } + } + return 'done'; + } finally { + tmpDir.cleanup(); + } +} diff --git a/test/config/decrypt.spec.js b/test/config/decrypt.spec.js index 62543105a9ef3ac00ccdde699be01f43b870237a..48078be5442ca24b12f2ac01190aae9ce0398a19 100644 --- a/test/config/decrypt.spec.js +++ b/test/config/decrypt.spec.js @@ -48,6 +48,7 @@ describe('config/decrypt', () => { }, }, }, + 'backend/package.json', ]; const res = decryptConfig(config, logger, privateKey); expect(res.encrypted).not.toBeDefined(); diff --git a/test/manager/__snapshots__/resolve.spec.js.snap b/test/manager/__snapshots__/resolve.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..b2bbf155e6bd7e9d9a2b5b4f8711da57f91f30f0 --- /dev/null +++ b/test/manager/__snapshots__/resolve.spec.js.snap @@ -0,0 +1,3477 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`manager/resolve resolvePackageFiles() deetect package.json and warns if cannot parse 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [ + Object { + "depName": "package.json", + "message": "Cannot parse package.json (invalid JSON)", + }, + ], + "workspaceDir": undefined, + "yarnrc": null, +} +`; + +exports[`manager/resolve resolvePackageFiles() detects meteor and docker 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [ + Object { + "enabled": true, + "packageFile": "package.js", + }, + Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "content": "# comment +FROM node:8 +", + "currentFrom": "node:8", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "packageFile": "Dockerfile", + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + ], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [], + "workspaceDir": undefined, + "yarnrc": null, +} +`; + +exports[`manager/resolve resolvePackageFiles() detects package.json and parses json with renovate config 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [ + Object { + "automerge": true, + "content": Object {}, + "errors": Array [], + "packageFile": "package.json", + "packageLock": undefined, + "warnings": Array [], + "yarnLock": undefined, + }, + ], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [], + "workspaceDir": undefined, + "yarnrc": null, +} +`; + +exports[`manager/resolve resolvePackageFiles() downloads accompanying files 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [ + Object { + "content": Object { + "name": "package.json", + }, + "npmrc": "npmrc", + "packageFile": "package.json", + "packageLock": "{\\"name\\": \\"packge-lock.json\\"}", + "yarnLock": "# yarn.lock", + "yarnrc": "yarnrc", + }, + ], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [], + "workspaceDir": undefined, + "yarnrc": null, +} +`; + +exports[`manager/resolve resolvePackageFiles() skips docker if no content or no match 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [], + "workspaceDir": undefined, + "yarnrc": null, +} +`; + +exports[`manager/resolve resolvePackageFiles() uses packageFiles if already configured and raises error if not found 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [ + Object { + "depName": "package.json", + "message": "Cannot find package.json", + }, + Object { + "depName": "backend/package.json", + "message": "Cannot find package.json", + }, + ], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "monorepoPackages": Array [], + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "warnings": Array [], + "workspaceDir": undefined, + "yarnrc": null, +} +`; diff --git a/test/manager/resolve.spec.js b/test/manager/resolve.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..9356237316fbd198af7c7248eceeba3bf4cc1c8b --- /dev/null +++ b/test/manager/resolve.spec.js @@ -0,0 +1,74 @@ +const { resolvePackageFiles } = require('../../lib/manager/resolve'); +const manager = require('../../lib/manager'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = { ...require('../_fixtures/config') }; + config.errors = []; + config.warnings = []; +}); + +describe('manager/resolve', () => { + describe('resolvePackageFiles()', () => { + it('uses packageFiles if already configured and raises error if not found', async () => { + config.packageFiles = [ + 'package.json', + { packageFile: 'backend/package.json' }, + ]; + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + expect(res.errors).toHaveLength(2); + }); + it('deetect package.json and warns if cannot parse', async () => { + manager.detectPackageFiles = jest.fn(() => [ + { packageFile: 'package.json' }, + ]); + config.api.getFileContent.mockReturnValueOnce('not json'); + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + expect(res.warnings).toHaveLength(1); + }); + it('detects package.json and parses json with renovate config', async () => { + manager.detectPackageFiles = jest.fn(() => [ + { packageFile: 'package.json' }, + ]); + const pJson = { + renovate: { + automerge: true, + }, + }; + config.api.getFileContent.mockReturnValueOnce(JSON.stringify(pJson)); + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + expect(res.warnings).toHaveLength(0); + }); + it('downloads accompanying files', async () => { + manager.detectPackageFiles = jest.fn(() => [ + { packageFile: 'package.json' }, + ]); + config.api.getFileContent.mockReturnValueOnce('{"name": "package.json"}'); + config.api.getFileContent.mockReturnValueOnce('npmrc'); + config.api.getFileContent.mockReturnValueOnce('yarnrc'); + config.api.getFileContent.mockReturnValueOnce('# yarn.lock'); + config.api.getFileContent.mockReturnValueOnce( + '{"name": "packge-lock.json"}' + ); + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + expect(res.warnings).toHaveLength(0); + }); + it('detects meteor and docker', async () => { + config.packageFiles = ['package.js', 'Dockerfile']; + config.api.getFileContent.mockReturnValueOnce('# comment\nFROM node:8\n'); // Dockerfile + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + }); + it('skips docker if no content or no match', async () => { + config.packageFiles = ['Dockerfile', 'other/Dockerfile']; + config.api.getFileContent.mockReturnValueOnce('# comment\n'); // Dockerfile + const res = await resolvePackageFiles(config); + expect(res).toMatchSnapshot(); + }); + }); +}); diff --git a/test/workers/repository/__snapshots__/apis.spec.js.snap b/test/workers/repository/__snapshots__/apis.spec.js.snap deleted file mode 100644 index e1fd6165dd9ff00e8cc137143079a4a7c6a47b87..0000000000000000000000000000000000000000 --- a/test/workers/repository/__snapshots__/apis.spec.js.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`workers/repository/apis initApis(config) throws if unknown platform 1`] = `"Unknown platform: foo"`; - -exports[`workers/repository/apis mergeRenovateJson(config) returns error in config if renovate.json cannot be parsed 1`] = ` -Array [ - Object { - "depName": "renovate.json", - "message": "Syntax error: expecting String near { enabled:", - }, -] -`; - -exports[`workers/repository/apis mergeRenovateJson(config) returns error plus extended config if duplicate keys 1`] = ` -Array [ - Object { - "depName": "renovate.json", - "message": "Syntax error: duplicated keys \\"enabled\\" near \\": false }", - }, -] -`; - -exports[`workers/repository/apis mergeRenovateJson(config) returns warning + error plus extended config if unknown keys 1`] = `Array []`; - -exports[`workers/repository/apis resolvePackageFiles includes files with content 1`] = ` -Array [ - Object { - "content": Object { - "workspaces": Array [], - }, - "npmrc": "npmrc-1", - "packageFile": "package.json", - "packageLock": "packageLock-1", - "yarnLock": "yarnLock-1", - "yarnrc": "yarnrc-1", - }, - Object { - "content": Object {}, - "packageFile": "a/package.json", - "packageLock": undefined, - "yarnLock": undefined, - }, -] -`; diff --git a/test/workers/repository/__snapshots__/index.spec.js.snap b/test/workers/repository/__snapshots__/index.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..2b844f24c33cb85a0ac463b522d0488e9b301fbb --- /dev/null +++ b/test/workers/repository/__snapshots__/index.spec.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workers/repository renovateRepository() ensures onboarding pr 1`] = `"onboarding"`; + +exports[`workers/repository renovateRepository() exits after 6 loops 1`] = `"loops>5"`; + +exports[`workers/repository renovateRepository() writes 1`] = `"onboarded"`; diff --git a/test/workers/repository/__snapshots__/onboarding.spec.js.snap b/test/workers/repository/__snapshots__/onboarding.spec.js.snap deleted file mode 100644 index a4a877009340171ac7620d996cd3cd2b86a0ea4b..0000000000000000000000000000000000000000 --- a/test/workers/repository/__snapshots__/onboarding.spec.js.snap +++ /dev/null @@ -1,21 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`lib/workers/repository/onboarding getOnboardingStatus(config) commits files and returns false if no pr 1`] = ` -Array [ - "renovate/configure", - Array [ - Object { - "contents": "{ - \\"extends\\": [ - \\"config:base\\" - ] -} -", - "name": "renovate.json", - }, - ], - "Add renovate.json", -] -`; - -exports[`lib/workers/repository/onboarding getOnboardingStatus(config) throws if no packageFiles 1`] = `[Error: no package files]`; diff --git a/test/workers/repository/__snapshots__/upgrades.spec.js.snap b/test/workers/repository/__snapshots__/upgrades.spec.js.snap deleted file mode 100644 index 08154511a58ae457b3e60058c1cfc31abfc288a9..0000000000000000000000000000000000000000 --- a/test/workers/repository/__snapshots__/upgrades.spec.js.snap +++ /dev/null @@ -1,231 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`workers/repository/upgrades generateConfig(branchUpgrades) does not group single upgrade 1`] = ` -Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 1, - "prTitle": "some-prefix: some-title", - "semanticCommits": true, - "semanticPrefix": "some-prefix:", - "upgrades": Array [ - Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 1, - "prTitle": "some-prefix: some-title", - "semanticCommits": true, - "semanticPrefix": "some-prefix:", - }, - ], -} -`; - -exports[`workers/repository/upgrades generateConfig(branchUpgrades) groups multiple upgrades 1`] = ` -Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 2, - "groupName": "some-group", - "prTitle": "some-title", - "upgrades": Array [ - Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 2, - "groupName": "some-group", - "prTitle": "some-title", - }, - Object { - "branchName": "some-branch", - "depName": "some-other-dep", - "foo": 2, - "groupName": "some-group", - "prTitle": "some-title", - }, - ], -} -`; - -exports[`workers/repository/upgrades generateConfig(branchUpgrades) groups single upgrade if not lazyGrouping 1`] = ` -Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 2, - "groupName": "some-group", - "prTitle": "some-title", - "upgrades": Array [ - Object { - "branchName": "some-branch", - "depName": "some-dep", - "foo": 2, - "groupName": "some-group", - "prTitle": "some-title", - }, - ], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) does not group if different compiled branch names 1`] = ` -Object { - "branchUpgrades": Object { - "bar-1.1.0": Array [ - Object { - "branchName": "bar-{{version}}", - "depName": "bar", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - "foo-1.1.0": Array [ - Object { - "branchName": "foo-{{version}}", - "depName": "foo", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - "foo-2.0.0": Array [ - Object { - "branchName": "foo-{{version}}", - "depName": "foo", - "prTitle": "some-title", - "version": "2.0.0", - }, - ], - }, - "errors": Array [], - "warnings": Array [], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) groups if same compiled branch names 1`] = ` -Object { - "branchUpgrades": Object { - "bar-1.1.0": Array [ - Object { - "branchName": "bar-{{version}}", - "depName": "bar", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - "foo": Array [ - Object { - "branchName": "foo", - "depName": "foo", - "prTitle": "some-title", - "version": "2.0.0", - }, - Object { - "branchName": "foo", - "depName": "foo", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - }, - "errors": Array [], - "warnings": Array [], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) groups if same compiled group name 1`] = ` -Object { - "branchUpgrades": Object { - "foo": Array [ - Object { - "branchName": "foo", - "depName": "foo", - "prTitle": "some-title", - "version": "2.0.0", - }, - ], - "renovate/my-group": Array [ - Object { - "branchName": "bar-{{version}}", - "depName": "bar", - "group": Object { - "branchName": "renovate/my-group", - }, - "groupName": "My Group", - "groupSlug": "my-group", - "prTitle": "some-title", - "version": "1.1.0", - }, - Object { - "branchName": "foo", - "depName": "foo", - "group": Object { - "branchName": "renovate/{{groupSlug}}", - }, - "groupName": "My Group", - "groupSlug": "my-group", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - }, - "errors": Array [], - "warnings": Array [], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) mixes errors and warnings 1`] = ` -Object { - "branchUpgrades": Object { - "bar-1.1.0": Array [ - Object { - "branchName": "bar-{{version}}", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - "foo-1.1.0": Array [ - Object { - "branchName": "foo-{{version}}", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - }, - "errors": Array [ - Object { - "type": "error", - }, - ], - "warnings": Array [ - Object { - "branchName": "foo-{{version}}", - "prTitle": "some-title", - "type": "warning", - "version": "2.0.0", - }, - ], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) returns empty object if no input array 1`] = ` -Object { - "branchUpgrades": Object {}, - "errors": Array [], - "warnings": Array [], -} -`; - -exports[`workers/repository/upgrades groupByBranch(upgrades) returns one branch if one input 1`] = ` -Object { - "branchUpgrades": Object { - "foo-1.1.0": Array [ - Object { - "branchName": "foo-{{version}}", - "depName": "foo", - "prTitle": "some-title", - "version": "1.1.0", - }, - ], - }, - "errors": Array [], - "warnings": Array [], -} -`; diff --git a/test/workers/repository/apis.spec.js b/test/workers/repository/apis.spec.js deleted file mode 100644 index 5006d051c0c9d57e0813cdebcdb1d2f70460a069..0000000000000000000000000000000000000000 --- a/test/workers/repository/apis.spec.js +++ /dev/null @@ -1,241 +0,0 @@ -const jsonValidator = require('json-dup-key-validator'); - -const apis = require('../../../lib/workers/repository/apis'); -const logger = require('../../_fixtures/logger'); - -const githubApi = require('../../../lib/platform/github'); -const gitlabApi = require('../../../lib/platform/gitlab'); -const npmApi = require('../../../lib/manager/npm/registry'); - -jest.mock('../../../lib/platform/github'); -jest.mock('../../../lib/platform/gitlab'); -jest.mock('../../../lib/manager/npm/registry'); - -describe('workers/repository/apis', () => { - describe('getNpmrc', () => { - it('Skips if ignoring npmrc', async () => { - const config = { - foo: 1, - ignoreNpmrcFile: true, - }; - expect(await apis.getNpmrc(config)).toMatchObject(config); - }); - it('Skips if npmrc not found', async () => { - const config = { - api: { - getFileContent: jest.fn(), - }, - }; - expect(await apis.getNpmrc(config)).toMatchObject(config); - }); - it('Parses if npmrc found', async () => { - const config = { - api: { - getFileContent: jest.fn(() => 'a = b'), - }, - logger, - }; - const res = await apis.getNpmrc(config); - expect(res.npmrc).toEqual('a = b'); - }); - it('Catches errors', async () => { - const config = { - api: { - getFileContent: jest.fn(() => { - throw new Error('file error'); - }), - }, - logger, - }; - expect(await apis.getNpmrc(config)).toMatchObject(config); - }); - }); - describe('detectSemanticCommits', () => { - it('disables semantic commits', async () => { - const config = { - api: { - getCommitMessages: jest.fn(() => []), - }, - logger, - }; - const res = await apis.detectSemanticCommits(config); - expect(res).toEqual(false); - }); - it('enables semantic commits', async () => { - const config = { - api: { - getCommitMessages: jest.fn(() => []), - }, - logger, - }; - config.api.getCommitMessages.mockReturnValueOnce(['fix: something']); - const res = await apis.detectSemanticCommits(config); - expect(res).toEqual(true); - }); - }); - describe('initApis(config)', () => { - beforeEach(() => { - jest.resetAllMocks(); - }); - it('returns github api', async () => { - const config = { logger, platform: 'github', semanticCommits: null }; - const res = await apis.initApis(config); - expect(res.platform).toEqual('github'); - expect(githubApi.initRepo.mock.calls.length).toBe(1); - expect(gitlabApi.initRepo.mock.calls.length).toBe(0); - expect(npmApi.setNpmrc.mock.calls.length).toBe(0); - }); - it('returns gitlab api', async () => { - const config = { logger, platform: 'gitlab' }; - const res = await apis.initApis(config); - expect(res.platform).toEqual('gitlab'); - expect(githubApi.initRepo.mock.calls.length).toBe(0); - expect(gitlabApi.initRepo.mock.calls.length).toBe(1); - expect(npmApi.setNpmrc.mock.calls.length).toBe(0); - }); - it('throws if unknown platform', async () => { - const config = { platform: 'foo' }; - let e; - try { - await apis.initApis(config); - } catch (err) { - e = err; - } - expect(e.message).toMatchSnapshot(); - expect(githubApi.initRepo.mock.calls.length).toBe(0); - expect(gitlabApi.initRepo.mock.calls.length).toBe(0); - expect(npmApi.setNpmrc.mock.calls.length).toBe(0); - }); - }); - describe('mergeRenovateJson(config)', () => { - let config; - beforeEach(() => { - config = { - errors: [], - warnings: [], - api: { - getFileContent: jest.fn(), - }, - logger, - }; - }); - it('returns same config if no renovate.json found', async () => { - expect(await apis.mergeRenovateJson(config)).toEqual(config); - }); - it('returns extended config if renovate.json found', async () => { - config.api.getFileContent.mockReturnValueOnce('{ "enabled": true }'); - const returnConfig = await apis.mergeRenovateJson(config); - expect(returnConfig.enabled).toBe(true); - expect(returnConfig.renovateJsonPresent).toBe(true); - expect(returnConfig.errors).toHaveLength(0); - }); - it('returns warning + error plus extended config if unknown keys', async () => { - config.repoIsOnboarded = true; - config.api.getFileContent.mockReturnValueOnce( - '{ "enabled": true, "foo": false, "maintainYarnLock": true, "schedule": "before 5am", "minor": {} }' - ); - const returnConfig = await apis.mergeRenovateJson(config); - expect(returnConfig.enabled).toBe(true); - expect(returnConfig.renovateJsonPresent).toBe(true); - expect(returnConfig.errors).toHaveLength(0); // TODO: Update to 1 later - expect(returnConfig.errors).toMatchSnapshot(); - }); - it('returns error plus extended config if duplicate keys', async () => { - config.repoIsOnboarded = true; - config.api.getFileContent.mockReturnValueOnce( - '{ "enabled": true, "enabled": false }' - ); - const returnConfig = await apis.mergeRenovateJson(config); - expect(returnConfig.enabled).toBe(false); - expect(returnConfig.renovateJsonPresent).toBe(true); - expect(returnConfig.errors).toHaveLength(1); - expect(returnConfig.errors).toMatchSnapshot(); - }); - it('returns error in config if renovate.json cannot be parsed', async () => { - config.api.getFileContent.mockReturnValueOnce('{ enabled: true }'); - const returnConfig = await apis.mergeRenovateJson(config); - expect(returnConfig.enabled).toBeUndefined(); - expect(returnConfig.renovateJsonPresent).toBeUndefined(); - expect(returnConfig.errors).toMatchSnapshot(); - }); - it('returns error in JSON.parse', async () => { - config.api.getFileContent.mockReturnValueOnce('{ enabled: true }'); - jsonValidator.validate = jest.fn(); - jsonValidator.validate.mockReturnValueOnce(false); - jsonValidator.validate.mockReturnValueOnce(false); - let e; - try { - await apis.mergeRenovateJson(config); - } catch (err) { - e = err; - } - expect(e).toBeDefined(); - }); - }); - describe('resolvePackageFiles', () => { - let config; - beforeEach(() => { - config = { - errors: [], - warnings: [], - packageFiles: ['package.json', { packageFile: 'a/package.json' }], - api: { - getFileContent: jest.fn(() => null), - }, - logger, - }; - }); - it('skips files with no content', async () => { - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toEqual([]); - }); - it('skips files with invalid JSON', async () => { - config.api.getFileContent.mockReturnValueOnce('not json'); - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toEqual([]); - }); - it('includes files with content', async () => { - config.repoIsOnboarded = true; - config.api.getFileContent.mockReturnValueOnce( - JSON.stringify({ - renovate: {}, - workspaces: [], - }) - ); - config.api.getFileContent.mockReturnValueOnce('npmrc-1'); - config.api.getFileContent.mockReturnValueOnce('yarnrc-1'); - config.api.getFileContent.mockReturnValueOnce('yarnLock-1'); - config.api.getFileContent.mockReturnValueOnce('packageLock-1'); - config.api.getFileContent.mockReturnValueOnce('{}'); - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toHaveLength(2); - expect(res.packageFiles).toMatchSnapshot(); - }); - it('handles meteor', async () => { - config.packageFiles = [{ packageFile: 'package.js' }]; - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toHaveLength(1); - }); - it('handles dockerfile', async () => { - config.packageFiles = [{ packageFile: 'Dockerfile' }]; - config.api.getFileContent.mockReturnValueOnce( - '# some content\nFROM node:8\nRUN something' - ); - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toHaveLength(1); - }); - it('handles dockerfile with no content', async () => { - config.packageFiles = [{ packageFile: 'Dockerfile' }]; - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toHaveLength(0); - }); - it('handles dockerfile with no FROM', async () => { - config.packageFiles = [{ packageFile: 'Dockerfile' }]; - config.api.getFileContent.mockReturnValueOnce( - '# some content\n# FROM node:8\nRUN something' - ); - const res = await apis.resolvePackageFiles(config); - expect(res.packageFiles).toHaveLength(0); - }); - }); -}); diff --git a/test/workers/repository/cleanup.spec.js b/test/workers/repository/cleanup.spec.js index 5164214118c649f332fa0ef18f9a0cbdff8ab65c..0d8f2f96b68191d87da502ae3b6c86205cac2491 100644 --- a/test/workers/repository/cleanup.spec.js +++ b/test/workers/repository/cleanup.spec.js @@ -1,59 +1,47 @@ -const defaultConfig = require('../../../lib/config/defaults').getConfig(); const cleanup = require('../../../lib/workers/repository/cleanup'); -const logger = require('../../_fixtures/logger'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../_fixtures/config'); + config.platform = 'github'; + config.errors = []; + config.warnings = []; +}); describe('workers/repository/cleanup', () => { - describe('pruneStaleBranches(config, branchUpgradeNames)', () => { - let branchNames; - let config; - beforeEach(() => { - branchNames = []; - config = { ...defaultConfig }; - config.api = { - getAllRenovateBranches: jest.fn(), - getPr: jest.fn(), - deleteBranch: jest.fn(), - findPr: jest.fn(), - updatePr: jest.fn(), - }; - config.logger = logger; + describe('pruneStaleBranches()', () => { + it('returns if no branchList', async () => { + delete config.branchList; + await cleanup.pruneStaleBranches(config, config.branchList); + expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(0); }); it('returns if config is not github', async () => { + config.branchList = []; config.platform = 'gitlab'; - await cleanup.pruneStaleBranches(config, branchNames); + await cleanup.pruneStaleBranches(config, config.branchList); expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(0); }); it('returns if no remaining branches', async () => { - branchNames = ['renovate/a', 'renovate/b']; - config.api.getAllRenovateBranches.mockReturnValueOnce(branchNames); - await cleanup.pruneStaleBranches(config, branchNames); + config.branchList = ['renovate/a', 'renovate/b']; + config.api.getAllRenovateBranches.mockReturnValueOnce(config.branchList); + await cleanup.pruneStaleBranches(config, config.branchList); expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); + expect(config.api.deleteBranch.mock.calls).toHaveLength(0); }); it('renames deletes remaining branch', async () => { - branchNames = ['renovate/a', 'renovate/b']; + config.branchList = ['renovate/a', 'renovate/b']; config.api.getAllRenovateBranches.mockReturnValueOnce( - branchNames.concat(['renovate/c']) + config.branchList.concat(['renovate/c']) ); config.api.findPr.mockReturnValueOnce({}); - await cleanup.pruneStaleBranches(config, branchNames); + await cleanup.pruneStaleBranches(config, config.branchList); expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); expect(config.api.deleteBranch.mock.calls).toHaveLength(1); expect(config.api.updatePr.mock.calls).toHaveLength(1); }); - it('deletes lock file maintenance if pr is closed', async () => { - branchNames = ['renovate/lock-file-maintenance']; - config.api.getAllRenovateBranches.mockReturnValueOnce([ - 'renovate/lock-file-maintenance', - ]); - config.api.getBranchPr = jest.fn(() => ({ isClosed: true })); - await cleanup.pruneStaleBranches(config, [ - 'renovate/lock-file-maintenance', - ]); - expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); - expect(config.api.deleteBranch.mock.calls).toHaveLength(1); - }); it('deletes lock file maintenance if pr is unmergeable', async () => { - branchNames = ['renovate/lock-file-maintenance']; + config.branchList = ['renovate/lock-file-maintenance']; config.api.getAllRenovateBranches.mockReturnValueOnce([ 'renovate/lock-file-maintenance', ]); @@ -64,24 +52,12 @@ describe('workers/repository/cleanup', () => { expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); expect(config.api.deleteBranch.mock.calls).toHaveLength(1); }); - it('deletes lock file maintenance if no changed files', async () => { - branchNames = ['renovate/lock-file-maintenance']; - config.api.getAllRenovateBranches.mockReturnValueOnce([ - 'renovate/lock-file-maintenance', - ]); - config.api.getBranchPr = jest.fn(() => ({ changed_files: 0 })); - await cleanup.pruneStaleBranches(config, [ - 'renovate/lock-file-maintenance', - ]); - expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); - expect(config.api.deleteBranch.mock.calls).toHaveLength(1); - }); it('calls delete only once', async () => { - branchNames = ['renovate/lock-file-maintenance']; + config.branchList = ['renovate/lock-file-maintenance']; config.api.getAllRenovateBranches.mockReturnValueOnce([ 'renovate/lock-file-maintenance', ]); - config.api.getBranchPr = jest.fn(() => ({ isClosed: true })); + config.api.getBranchPr = jest.fn(() => ({ isUnmergeable: true })); await cleanup.pruneStaleBranches(config, []); expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1); expect(config.api.deleteBranch.mock.calls).toHaveLength(1); diff --git a/test/workers/repository/configured.spec.js b/test/workers/repository/configured.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..badb6cd75aadb4823a2e958e7e3e3edcbc561e73 --- /dev/null +++ b/test/workers/repository/configured.spec.js @@ -0,0 +1,39 @@ +const { + checkIfConfigured, +} = require('../../../lib/workers/repository/configured'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = { ...require('../../_fixtures/config') }; +}); + +describe('workers/repository/configured', () => { + describe('checkIfConfigured()', () => { + it('returns', () => { + checkIfConfigured(config); + }); + it('throws if disabled', () => { + config.enabled = false; + let e; + try { + checkIfConfigured(config); + } catch (err) { + e = err; + } + expect(e).toBeDefined(); + }); + it('throws if unconfigured fork', () => { + config.enabled = true; + config.isFork = true; + config.renovateJsonPresent = false; + let e; + try { + checkIfConfigured(config); + } catch (err) { + e = err; + } + expect(e).toBeDefined(); + }); + }); +}); diff --git a/test/workers/repository/error.spec.js b/test/workers/repository/error.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..1846e76a6f332efbef195bf39a06fcd334516437 --- /dev/null +++ b/test/workers/repository/error.spec.js @@ -0,0 +1,29 @@ +const { handleError } = require('../../../lib/workers/repository/error'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../_fixtures/config'); +}); + +describe('workers/repository/error', () => { + describe('handleError()', () => { + const errors = [ + 'uninitiated', + 'disabled', + 'fork', + 'no-package-files', + 'loops>5', + ]; + errors.forEach(err => { + it(`errors ${err}`, () => { + const res = handleError(config, new Error(err)); + expect(res).toEqual(err); + }); + }); + it('handles unknown error', () => { + const res = handleError(config, new Error('abcdefg')); + expect(res).toEqual('unknown-error'); + }); + }); +}); diff --git a/test/workers/repository/index.spec.js b/test/workers/repository/index.spec.js index 2d612bf17f41d9d74460792f7dec4c20f4c05785..2c39859c8c292a94a9854b4f87c6e383173cd899 100644 --- a/test/workers/repository/index.spec.js +++ b/test/workers/repository/index.spec.js @@ -1,223 +1,42 @@ -const repositoryWorker = require('../../../lib/workers/repository/index'); -const branchWorker = require('../../../lib/workers/branch'); - -const apis = require('../../../lib/workers/repository/apis'); -const manager = require('../../../lib/manager'); -const onboarding = require('../../../lib/workers/repository/onboarding'); -const upgrades = require('../../../lib/workers/repository/upgrades'); - -const logger = require('../../_fixtures/logger'); -const onboardingPr = require('../../../lib/workers/repository/onboarding/pr'); +const { determineUpdates } = require('../../../lib/workers/repository/updates'); +const { writeUpdates } = require('../../../lib/workers/repository/write'); +const { + ensureOnboardingPr, +} = require('../../../lib/workers/repository/onboarding/pr'); +const { renovateRepository } = require('../../../lib/workers/repository/index'); +jest.mock('../../../lib/workers/repository/init'); +jest.mock('../../../lib/workers/repository/init/apis'); +jest.mock('../../../lib/workers/repository/updates'); jest.mock('../../../lib/workers/repository/onboarding/pr'); +jest.mock('../../../lib/workers/repository/write'); +jest.mock('../../../lib/workers/repository/cleanup'); +jest.mock('../../../lib/manager/resolve'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../_fixtures/config'); +}); describe('workers/repository', () => { - describe('renovateRepository', () => { - let config; - beforeEach(() => { - jest.resetAllMocks(); - apis.initApis = jest.fn(input => input); - apis.mergeRenovateJson = jest.fn(input => input); - manager.detectPackageFiles = jest.fn(); - apis.resolvePackageFiles = jest.fn(input => input); - apis.checkMonorepos = jest.fn(input => input); - onboarding.getOnboardingStatus = jest.fn(input => input); - upgrades.determineRepoUpgrades = jest.fn(() => []); - upgrades.branchifyUpgrades = jest.fn(() => ({ branchUpgrades: {} })); - branchWorker.processBranch = jest.fn(() => 'done'); - config = { - lockFileMaintenance: true, - api: { - getFileJson: jest.fn(), - setBaseBranch: jest.fn(), - branchExists: jest.fn(), - }, - logger, - packageFiles: [], - }; - }); - it('skips repository if config is disabled', async () => { - config.enabled = false; - await repositoryWorker.renovateRepository(config); - expect(manager.detectPackageFiles.mock.calls.length).toBe(0); - }); - it('skips repository if its unconfigured fork', async () => { - config.isFork = true; - config.renovateJsonPresent = false; - await repositoryWorker.renovateRepository(config); - expect(manager.detectPackageFiles.mock.calls.length).toBe(0); - }); - it('does not skip repository if its a configured fork', async () => { - config.isFork = true; - config.renovateFork = true; - manager.detectPackageFiles.mockReturnValueOnce([]); - await repositoryWorker.renovateRepository(config); - }); - it('sets custom base branch', async () => { - config.baseBranch = 'some-branch'; - config.api.branchExists.mockReturnValueOnce(true); - manager.detectPackageFiles.mockReturnValueOnce([]); - await repositoryWorker.renovateRepository(config); - expect(config.api.setBaseBranch.mock.calls).toHaveLength(1); - }); - it('errors when missing custom base branch', async () => { - config.baseBranch = 'some-branch'; - config.api.branchExists.mockReturnValueOnce(false); - manager.detectPackageFiles.mockReturnValueOnce([]); - await repositoryWorker.renovateRepository(config); - expect(config.api.setBaseBranch.mock.calls).toHaveLength(0); - }); - it('skips repository if no package.json', async () => { - manager.detectPackageFiles.mockReturnValueOnce([]); - await repositoryWorker.renovateRepository(config); - expect(apis.resolvePackageFiles.mock.calls.length).toBe(0); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('does not skip repository if package.json', async () => { - manager.detectPackageFiles.mockReturnValueOnce(['package.json']); - config.api.getFileJson = jest.fn(() => ({ a: 1 })); - apis.mergeRenovateJson.mockImplementationOnce(input => ({ - ...input, - ...{ packageFiles: ['package.json'] }, - })); - apis.mergeRenovateJson.mockImplementationOnce(input => ({ - ...input, - ...{ packageFiles: ['package.json'] }, - })); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}, {}], - }); - await repositoryWorker.renovateRepository(config); - expect(onboarding.getOnboardingStatus.mock.calls.length).toBe(1); - expect(branchWorker.processBranch.mock.calls.length).toBe(0); - expect(onboardingPr.ensureOnboardingPr.mock.calls.length).toBe(1); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('uses onboarding custom baseBranch', async () => { - manager.detectPackageFiles.mockReturnValueOnce(['package.json']); - config.api.getFileJson = jest.fn(() => ({ a: 1 })); - manager.detectPackageFiles.mockReturnValueOnce(['package.json']); - apis.mergeRenovateJson.mockImplementationOnce(input => ({ - ...input, - ...{ packageFiles: ['package.json'], baseBranch: 'next' }, - })); - config.api.branchExists.mockReturnValueOnce(true); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}, {}], - }); - await repositoryWorker.renovateRepository(config); - expect(onboarding.getOnboardingStatus.mock.calls.length).toBe(1); - expect(branchWorker.processBranch.mock.calls.length).toBe(0); - expect(onboardingPr.ensureOnboardingPr.mock.calls.length).toBe(1); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('errors onboarding custom baseBranch', async () => { - manager.detectPackageFiles.mockReturnValueOnce(['package.json']); - config.api.getFileJson = jest.fn(() => ({ a: 1 })); - apis.mergeRenovateJson.mockImplementationOnce(input => ({ - ...input, - ...{ packageFiles: [] }, - })); - apis.mergeRenovateJson.mockImplementationOnce(input => ({ - ...input, - ...{ packageFiles: [], baseBranch: 'next' }, - })); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}, {}], - }); - await repositoryWorker.renovateRepository(config); - expect(onboarding.getOnboardingStatus.mock.calls.length).toBe(1); - expect(branchWorker.processBranch.mock.calls.length).toBe(0); - expect(onboardingPr.ensureOnboardingPr.mock.calls.length).toBe(1); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('calls branchWorker', async () => { - config.packageFiles = ['package.json']; - config.hasRenovateJson = true; - onboarding.getOnboardingStatus.mockImplementation(input => ({ - ...input, - repoIsOnboarded: true, - })); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}, {}], - }); - await repositoryWorker.renovateRepository(config); - expect(branchWorker.processBranch.mock.calls.length).toBe(3); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('skips branchWorker after automerging', async () => { - config.packageFiles = ['package.json']; - config.hasRenovateJson = true; - onboarding.getOnboardingStatus.mockImplementation(input => ({ - ...input, - repoIsOnboarded: true, - })); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}, {}], - }); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}, {}], - }); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{}], - }); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [], - }); - branchWorker.processBranch.mockReturnValue('automerged'); - await repositoryWorker.renovateRepository(config); - expect(upgrades.branchifyUpgrades.mock.calls).toHaveLength(4); - expect(branchWorker.processBranch.mock.calls).toHaveLength(3); - expect(config.logger.error.mock.calls).toHaveLength(0); - }); - it('only processes pins first', async () => { - config.packageFiles = ['package.json']; - config.hasRenovateJson = true; - onboarding.getOnboardingStatus.mockImplementation(input => ({ - ...input, - repoIsOnboarded: true, - })); - upgrades.branchifyUpgrades.mockReturnValueOnce({ - upgrades: [{ isPin: true }, {}, {}], - }); - branchWorker.processBranch.mockReturnValue('done'); - await repositoryWorker.renovateRepository(config); - expect(upgrades.branchifyUpgrades.mock.calls).toHaveLength(1); - expect(branchWorker.processBranch.mock.calls).toHaveLength(1); - expect(config.logger.error.mock.calls).toHaveLength(0); - }); - it('swallows errors', async () => { - apis.initApis.mockImplementationOnce(() => { - throw new Error('bad init'); - }); - await repositoryWorker.renovateRepository(config); - expect(config.logger.error.mock.calls.length).toBe(1); - }); - it('handles special uninitiated error', async () => { - apis.initApis.mockImplementationOnce(() => { - // Create a new object, that prototypically inherits from the Error constructor - function MyError() { - this.message = 'uninitiated'; - } - MyError.prototype = Object.create(Error.prototype); - MyError.prototype.constructor = MyError; - throw new MyError(); - }); - await repositoryWorker.renovateRepository(config); - expect(config.logger.error.mock.calls.length).toBe(0); - }); - it('handles special no package files error', async () => { - apis.initApis.mockImplementationOnce(() => { - // Create a new object, that prototypically inherits from the Error constructor - function MyError() { - this.message = 'no package files'; - } - MyError.prototype = Object.create(Error.prototype); - MyError.prototype.constructor = MyError; - throw new MyError(); - }); - await repositoryWorker.renovateRepository(config); - expect(config.logger.error.mock.calls.length).toBe(0); + describe('renovateRepository()', () => { + it('exits after 6 loops', async () => { + const res = await renovateRepository(config, 'some-token', 6); + expect(res).toMatchSnapshot(); + }); + it('writes', async () => { + determineUpdates.mockReturnValue({ repoIsOnboarded: true }); + writeUpdates.mockReturnValueOnce('automerged'); + writeUpdates.mockReturnValueOnce('onboarded'); + const res = await renovateRepository(config, 'some-token'); + expect(res).toMatchSnapshot(); + }); + it('ensures onboarding pr', async () => { + determineUpdates.mockReturnValue({ repoIsOnboarded: false }); + ensureOnboardingPr.mockReturnValue('onboarding'); + const res = await renovateRepository(config, 'some-token'); + expect(res).toMatchSnapshot(); }); }); }); diff --git a/test/workers/repository/init/__snapshots__/config.spec.js.snap b/test/workers/repository/init/__snapshots__/config.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..17c4c467fad6681626eda9e4f724442aa9fc25e3 --- /dev/null +++ b/test/workers/repository/init/__snapshots__/config.spec.js.snap @@ -0,0 +1,15 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workers/repository/init/config mergeRenovateJson() returns error if cannot parse 1`] = ` +Object { + "depName": "renovate.json", + "message": "Syntax error near cannot par", +} +`; + +exports[`workers/repository/init/config mergeRenovateJson() returns error if duplicate keys 1`] = ` +Object { + "depName": "renovate.json", + "message": "Syntax error: duplicated keys \\"enabled\\" near \\": false }", +} +`; diff --git a/test/workers/repository/init/apis.spec.js b/test/workers/repository/init/apis.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..682fbfa2f3e4c5b7a73755640915e542ea5917e3 --- /dev/null +++ b/test/workers/repository/init/apis.spec.js @@ -0,0 +1,19 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); + config.errors = []; + config.warnings = []; +}); + +const { initApis } = require('../../../../lib/workers/repository/init/apis'); + +jest.mock('../../../../lib/platform/github'); + +describe('workers/repository/init/apis', () => { + describe('initApis', () => { + it('runs', async () => { + await initApis(config, 'some-token'); + }); + }); +}); diff --git a/test/workers/repository/init/base.spec.js b/test/workers/repository/init/base.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..601ade331d5265f6e38a2efac0623d4a5be93ddf --- /dev/null +++ b/test/workers/repository/init/base.spec.js @@ -0,0 +1,28 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); + config.errors = []; + config.warnings = []; +}); + +const { + checkBaseBranch, +} = require('../../../../lib/workers/repository/init/base'); + +describe('workers/repository/init/base', () => { + describe('checkBaseBranch()', () => { + it('errors', async () => { + config.baseBranch = 'some-base'; + const res = await checkBaseBranch(config); + expect(res.errors).toHaveLength(1); + }); + it('sets baseBranch', async () => { + config.baseBranch = 'ssome-base'; + config.api.branchExists.mockReturnValue(true); + const res = await checkBaseBranch(config); + expect(res.errors).toHaveLength(0); + expect(config.api.setBaseBranch.mock.calls).toHaveLength(1); + }); + }); +}); diff --git a/test/workers/repository/init/config.spec.js b/test/workers/repository/init/config.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..8a97de5210ac24e698f9c38189bb18293169cb59 --- /dev/null +++ b/test/workers/repository/init/config.spec.js @@ -0,0 +1,34 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); + config.errors = []; + config.warnings = []; +}); + +const { + mergeRenovateJson, +} = require('../../../../lib/workers/repository/init/config'); + +describe('workers/repository/init/config', () => { + describe('mergeRenovateJson()', () => { + it('returns config if not found', async () => { + const res = await mergeRenovateJson(config); + expect(res).toMatchObject(config); + }); + it('returns error if cannot parse', async () => { + config.api.getFileContent.mockReturnValue('cannot parse'); + const res = await mergeRenovateJson(config); + expect(res.errors).toHaveLength(1); + expect(res.errors[0]).toMatchSnapshot(); + }); + it('returns error if duplicate keys', async () => { + config.api.getFileContent.mockReturnValue( + '{ "enabled": true, "enabled": false }' + ); + const res = await mergeRenovateJson(config); + expect(res.errors).toHaveLength(1); + expect(res.errors[0]).toMatchSnapshot(); + }); + }); +}); diff --git a/test/workers/repository/init/index.spec.js b/test/workers/repository/init/index.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..2b68c1607bb57829fe425d080d03d65deb1fd415 --- /dev/null +++ b/test/workers/repository/init/index.spec.js @@ -0,0 +1,14 @@ +jest + .enableAutomock() + .dontMock('chalk') + .dontMock('../../../../lib/workers/repository/init'); + +const { initRepo } = require('../../../../lib/workers/repository/init'); + +describe('workers/repository/init', () => { + describe('initRepo', () => { + it('runs', async () => { + await initRepo({}, null); + }); + }); +}); diff --git a/test/workers/repository/init/semantic.spec.js b/test/workers/repository/init/semantic.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..944103753d194769073320a112c6a024001a08ba --- /dev/null +++ b/test/workers/repository/init/semantic.spec.js @@ -0,0 +1,36 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); + config.errors = []; + config.warnings = []; +}); + +const { + detectSemanticCommits, +} = require('../../../../lib/workers/repository/init/semantic'); + +describe('workers/repository/init/semantic', () => { + describe('detectSemanticCommits()', () => { + it('returns config if already set', async () => { + config.semanticCommits = true; + const res = await detectSemanticCommits(config); + expect(res).toBe(config); + }); + it('detects false if unknown', async () => { + config.semanticCommits = null; + config.api.getCommitMessages.mockReturnValue(['foo', 'bar']); + const res = await detectSemanticCommits(config); + expect(res.semanticCommits).toBe(false); + }); + it('detects true if known', async () => { + config.semanticCommits = null; + config.api.getCommitMessages.mockReturnValue([ + 'fix: foo', + 'refactor: bar', + ]); + const res = await detectSemanticCommits(config); + expect(res.semanticCommits).toBe(true); + }); + }); +}); diff --git a/test/workers/repository/onboarding.spec.js b/test/workers/repository/onboarding.spec.js deleted file mode 100644 index d3f610634a33188c48c2f657564ff0a386ba8408..0000000000000000000000000000000000000000 --- a/test/workers/repository/onboarding.spec.js +++ /dev/null @@ -1,73 +0,0 @@ -const onboarding = require('../../../lib/workers/repository/onboarding'); -const manager = require('../../../lib/manager'); -const logger = require('../../_fixtures/logger'); -const defaultConfig = require('../../../lib/config/defaults').getConfig(); - -describe('lib/workers/repository/onboarding', () => { - describe('getOnboardingStatus(config)', () => { - let config; - beforeEach(() => { - config = { ...defaultConfig }; - jest.resetAllMocks(); - config.api = { - commitFilesToBranch: jest.fn(), - createPr: jest.fn(() => ({ displayNumber: 1 })), - getFileList: jest.fn(() => []), - findPr: jest.fn(), - getFileContent: jest.fn(), - getFileJson: jest.fn(() => ({})), - getPr: jest.fn(() => {}), - getCommitMessages: jest.fn(), - }; - config.foundIgnoredPaths = true; - config.logger = logger; - config.detectedPackageFiles = true; - }); - it('returns true if onboarding is false', async () => { - config.onboarding = false; - const res = await onboarding.getOnboardingStatus(config); - expect(res.repoIsOnboarded).toEqual(true); - expect(config.api.findPr.mock.calls.length).toBe(0); - expect(config.api.commitFilesToBranch.mock.calls.length).toBe(0); - }); - it('returns true if renovate config present', async () => { - config.renovateJsonPresent = true; - const res = await onboarding.getOnboardingStatus(config); - expect(res.repoIsOnboarded).toEqual(true); - expect(config.api.findPr.mock.calls.length).toBe(0); - expect(config.api.commitFilesToBranch.mock.calls.length).toBe(0); - }); - it('returns true if pr and pr is closed', async () => { - config.api.findPr.mockReturnValueOnce({ isClosed: true }); - const res = await onboarding.getOnboardingStatus(config); - expect(res.repoIsOnboarded).toEqual(true); - expect(config.api.findPr.mock.calls.length).toBe(1); - expect(config.api.commitFilesToBranch.mock.calls.length).toBe(0); - }); - it('skips commit files and returns false if open pr', async () => { - config.api.findPr.mockReturnValueOnce({ isClosed: false }); - const res = await onboarding.getOnboardingStatus(config); - expect(res.repoIsOnboarded).toEqual(false); - expect(config.api.findPr.mock.calls.length).toBe(1); - expect(config.api.commitFilesToBranch.mock.calls.length).toBe(0); - }); - it('commits files and returns false if no pr', async () => { - config.api.getFileList.mockReturnValueOnce(['package.json']); - const res = await onboarding.getOnboardingStatus(config); - expect(res.repoIsOnboarded).toEqual(false); - expect(config.api.findPr.mock.calls.length).toBe(1); - expect(config.api.commitFilesToBranch.mock.calls.length).toBe(1); - expect(config.api.commitFilesToBranch.mock.calls[0]).toMatchSnapshot(); - }); - it('throws if no packageFiles', async () => { - manager.detectPackageFiles = jest.fn(() => []); - let e; - try { - await onboarding.getOnboardingStatus(config); - } catch (err) { - e = err; - } - expect(e).toMatchSnapshot(); - }); - }); -}); diff --git a/test/workers/repository/onboarding/branch/index.spec.js b/test/workers/repository/onboarding/branch/index.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..7efcef64417f46963f4412780fd92b1b7be4b228 --- /dev/null +++ b/test/workers/repository/onboarding/branch/index.spec.js @@ -0,0 +1,61 @@ +const logger = require('../../../../_fixtures/logger'); +const defaultConfig = require('../../../../../lib/config/defaults').getConfig(); +const { + checkOnboardingBranch, +} = require('../../../../../lib/workers/repository/onboarding/branch'); + +describe('workers/repository/onboarding/branch', () => { + describe('checkOnboardingBranch', () => { + let config; + beforeEach(() => { + jest.resetAllMocks(); + config = { + ...defaultConfig, + logger, + api: { + commitFilesToBranch: jest.fn(), + findPr: jest.fn(), + getFileList: jest.fn(() => []), + setBaseBranch: jest.fn(), + }, + }; + }); + it('throws if no package files', async () => { + let e; + try { + await checkOnboardingBranch(config); + } catch (err) { + e = err; + } + expect(e).toBeDefined(); + }); + it('throws if fork', async () => { + config.isFork = true; + let e; + try { + await checkOnboardingBranch(config); + } catch (err) { + e = err; + } + expect(e).toBeDefined(); + }); + it('detects repo is onboarded via file', async () => { + config.api.getFileList.mockReturnValueOnce(['renovate.json']); + const res = await checkOnboardingBranch(config); + expect(res.repoIsOnboarded).toBe(true); + }); + it('detects repo is onboarded via PR', async () => { + config.api.findPr.mockReturnValue(true); + const res = await checkOnboardingBranch(config); + expect(res.repoIsOnboarded).toBe(true); + }); + it('creates onboaring branch', async () => { + config.api.getFileList.mockReturnValue(['package.json']); + config.api.commitFilesToBranch = jest.fn(); + const res = await checkOnboardingBranch(config); + expect(res.repoIsOnboarded).toBe(false); + expect(res.branchList).toEqual(['renovate/configure']); + expect(config.api.setBaseBranch.mock.calls).toHaveLength(1); + }); + }); +}); diff --git a/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap b/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..1c0fc16ff3cc144f956926d4a10f7d8175ff92de --- /dev/null +++ b/test/workers/repository/updates/__snapshots__/branchify.spec.js.snap @@ -0,0 +1,2949 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workers/repository/updates/branchify branchifyUpgrades() does not group if different compiled branch names 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchList": undefined, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "branches": Array [ + Object { + "branchName": "foo-1.1.0", + "depName": "foo", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo-1.1.0", + "depName": "foo", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + Object { + "branchName": "foo-2.0.0", + "depName": "foo", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo-2.0.0", + "depName": "foo", + "prTitle": "some-title", + "version": "2.0.0", + }, + ], + "version": "2.0.0", + }, + Object { + "branchName": "bar-1.1.0", + "depName": "bar", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "bar-1.1.0", + "depName": "bar", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + ], + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "upgrades": null, + "warnings": Array [], + "yarnrc": null, +} +`; + +exports[`workers/repository/updates/branchify branchifyUpgrades() groups if same compiled branch names 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchList": undefined, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "branches": Array [ + Object { + "branchName": "foo", + "depName": "foo", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo", + "depName": "foo", + "prTitle": "some-title", + "version": "2.0.0", + }, + Object { + "branchName": "foo", + "depName": "foo", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "2.0.0", + }, + Object { + "branchName": "bar-1.1.0", + "depName": "bar", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "bar-1.1.0", + "depName": "bar", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + ], + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "upgrades": null, + "warnings": Array [], + "yarnrc": null, +} +`; + +exports[`workers/repository/updates/branchify branchifyUpgrades() groups if same compiled group name 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchList": undefined, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "branches": Array [ + Object { + "branchName": "renovate/my-group", + "depName": "bar", + "groupName": "My Group", + "groupSlug": "my-group", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "renovate/my-group", + "depName": "bar", + "groupName": "My Group", + "groupSlug": "my-group", + "prTitle": "some-title", + "version": "1.1.0", + }, + Object { + "branchName": "renovate/my-group", + "depName": "foo", + "groupName": "My Group", + "groupSlug": "my-group", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + Object { + "branchName": "foo", + "depName": "foo", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo", + "depName": "foo", + "prTitle": "some-title", + "version": "2.0.0", + }, + ], + "version": "2.0.0", + }, + ], + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "upgrades": null, + "warnings": Array [], + "yarnrc": null, +} +`; + +exports[`workers/repository/updates/branchify branchifyUpgrades() mixes errors and warnings 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchList": undefined, + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "branches": Array [ + Object { + "branchName": "foo-1.1.0", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo-1.1.0", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + Object { + "branchName": "bar-1.1.0", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "bar-1.1.0", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + ], + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [ + Object { + "type": "error", + }, + ], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "upgrades": null, + "warnings": Array [ + Object { + "branchName": "foo-{{version}}", + "prTitle": "some-title", + "type": "warning", + "version": "2.0.0", + }, + ], + "yarnrc": null, +} +`; + +exports[`workers/repository/updates/branchify branchifyUpgrades() returns one branch if one input 1`] = ` +Object { + "api": Object { + "addAssignees": [Function], + "addComment": [Function], + "addReviewers": [Function], + "branchExists": [Function], + "commitFilesToBranch": [Function], + "createPr": [Function], + "deleteBranch": [Function], + "deleteComment": [Function], + "editComment": [Function], + "ensureComment": [Function], + "ensureCommentRemoval": [Function], + "findPr": [Function], + "getAllRenovateBranches": [Function], + "getBranchCommit": [Function], + "getBranchLastCommitTime": [Function], + "getBranchPr": [Function], + "getBranchStatus": [Function], + "getBranchStatusCheck": [Function], + "getComments": [Function], + "getCommitDetails": [Function], + "getCommitMessages": [Function], + "getFile": [Function], + "getFileContent": [Function], + "getFileJson": [Function], + "getFileList": [Function], + "getPr": [Function], + "getPrList": [Function], + "getRepos": [Function], + "getSubDirectories": [Function], + "initRepo": [Function], + "isBranchStale": [Function], + "mergeBranch": [Function], + "mergePr": [Function], + "setBaseBranch": [Function], + "setBranchStatus": [Function], + "updatePr": [Function], + }, + "assignees": Array [], + "autodiscover": false, + "automerge": false, + "automergeType": "pr", + "baseBranch": null, + "branchList": Array [ + "foo-1.1.0", + ], + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.x", + "branchPrefix": "renovate/", + "branches": Array [ + Object { + "branchName": "foo-1.1.0", + "depName": "foo", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "foo-1.1.0", + "depName": "foo", + "prTitle": "some-title", + "version": "1.1.0", + }, + ], + "version": "1.1.0", + }, + ], + "commitMessage": "Update dependency {{depName}} to v{{newVersion}}", + "dependencies": Object { + "semanticPrefix": "fix(deps):", + }, + "description": Array [], + "devDependencies": Object { + "pin": Object { + "group": Object { + "commitMessage": "Pin devDependencies", + "prTitle": "Pin devDependencies", + }, + }, + }, + "digest": Object { + "semanticPrefix": "refactor(deps):", + }, + "docker": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{newVersionMajor}}.x", + "commitMessage": "Update {{depName}} to tag {{newTag}}", + "digest": Object { + "branchName": "{{branchPrefix}}docker-{{depNameSanitized}}-{{currentTag}}", + "commitMessage": "Update {{depName}}:{{currentTag}} digest", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}@{{currentTag}}\` to the latest digest (\`{{newDigest}}\`). + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Dockerfile {{depName}} image {{currentTag}} digest ({{newDigestShort}})", + }, + "enabled": true, + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update Docker {{groupName}} digests", + }, + "major": Object { + "enabled": false, + }, + "minor": Object { + "enabled": false, + }, + "patch": Object { + "enabled": false, + }, + "pin": Object { + "branchName": "{{branchPrefix}}docker-pin-{{depNameSanitized}}-{{currentTag}}", + "group": Object { + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Dockerfiles to use image digests. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: \`{{upgrade.newDigest}}\` +{{/each}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Docker digests", + }, + "groupName": "Pin Docker Digests", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request pins Docker base image \`{{depName}}@{{currentTag}}\` to use a digest (\`{{newDigest}}\`). +This digest will then be kept updated via Pull Requests whenever the image is updated on the Docker registry. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Pin Dockerfile {{depName}}@{{currentTag}} image digest", + }, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates Docker base image \`{{depName}}\` from tag \`{{currentTag}}\` to new tag \`{{newTag}}\`. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Update {{depName}} Dockerfile tag to {{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newTag}}{{/if}}", + }, + "enabled": true, + "encrypted": null, + "endpoint": null, + "errors": Array [], + "excludePackageNames": Array [], + "excludePackagePatterns": Array [], + "extends": Array [], + "group": Object { + "branchName": "{{branchPrefix}}{{groupSlug}}", + "commitMessage": "Renovate {{groupName}} packages", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request renovates the package group \\"{{groupName}}\\". + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#each upgrades as |upgrade|}} +- {{#if repositoryUrl}}[{{upgrade.depName}}]({{upgrade.repositoryUrl}}){{else}}\`{{depName}}\`{{/if}}: from \`{{upgrade.currentVersion}}\` to \`{{upgrade.newVersion}}\` +{{/each}} + +{{#unless isPin}} +### Commits + +{{#each upgrades as |upgrade|}} +{{#if upgrade.releases.length}} +<details> +<summary>{{upgrade.githubName}}</summary> +{{#each upgrade.releases as |release|}} + +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}){{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} +{{/each}} +{{/unless}} +<br /> + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Renovate {{groupName}} packages", + "recreateClosed": true, + }, + "groupName": null, + "groupSlug": null, + "ignoreDeps": Array [], + "ignoreFuture": true, + "ignoreNpmrcFile": false, + "ignorePaths": Array [ + "**/node_modules/**", + ], + "ignoreUnstable": true, + "labels": Array [], + "lazyGrouping": true, + "lockFileMaintenance": Object { + "branchName": "{{branchPrefix}}lock-file-maintenance", + "commitMessage": "Update lock file", + "enabled": false, + "groupName": null, + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request updates \`package.json\` lock files to use the latest dependency versions. + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prTitle": "Lock file maintenance", + "recreateClosed": true, + "schedule": Array [ + "before 5am on monday", + ], + }, + "logFile": null, + "logFileLevel": "debug", + "logLevel": "info", + "logger": Object { + "child": [Function], + "debug": [Function], + "error": [Function], + "fatal": [Function], + "info": [Function], + "trace": [Function], + "warn": [Function], + }, + "major": Object {}, + "meteor": Object { + "enabled": true, + }, + "minor": Object {}, + "npm": Object { + "enabled": true, + "pin": Object { + "automerge": true, + }, + }, + "npmrc": null, + "onboarding": true, + "optionalDependencies": Object {}, + "packageFiles": Array [], + "packageNames": Array [], + "packagePatterns": Array [], + "packageRules": Array [], + "patch": Object { + "branchName": "{{branchPrefix}}{{depNameSanitized}}-{{newVersionMajor}}.{{newVersionMinor}}.x", + }, + "peerDependencies": Object { + "enabled": false, + }, + "pin": Object { + "group": Object { + "commitMessage": "Pin Dependencies", + "prTitle": "{{groupName}}", + "semanticPrefix": "refactor(deps):", + }, + "groupName": "Pin Dependencies", + "rebaseStalePrs": true, + "recreateClosed": true, + "unpublishSafe": false, + }, + "pinDigests": true, + "pinVersions": null, + "platform": "github", + "prBody": "This {{#if isGitHub}}Pull{{else}}Merge{{/if}} Request {{#if isRollback}}rolls back{{else}}updates{{/if}} dependency {{#if repositoryUrl}}[{{depName}}]({{repositoryUrl}}){{else}}\`{{depName}}\`{{/if}} from \`{{#unless isRange}}{{#unless isPin}}v{{/unless}}{{/unless}}{{currentVersion}}\` to \`{{#unless isRange}}v{{/unless}}{{newVersion}}\`{{#if isRollback}}. This is necessary and important because \`v{{currentVersion}}\` cannot be found in the npm registry - probably because of it being unpublished.{{/if}} +{{#if releases.length}} + +{{#if schedule}} +**Note**: This PR was created on a configured schedule (\\"{{schedule}}\\"{{#if timezone}} in timezone \`{{timezone}}\`{{/if}}) and will not receive updates outside those times. +{{/if}} + +### Commits + +<details> +<summary>{{githubName}}</summary> + +{{#each releases as |release|}} +#### {{release.version}} +{{#each release.commits as |commit|}} +- [\`{{commit.shortSha}}\`]({{commit.url}}) {{commit.message}} +{{/each}} +{{/each}} + +</details> +{{/if}} + +{{#if hasErrors}} + +--- + +### Errors + +Renovate encountered some errors when processing your repository, so you are being notified here even if they do not directly apply to this PR. + +{{#each errors as |error|}} +- \`{{error.depName}}\`: {{error.message}} +{{/each}} +{{/if}} + +{{#if hasWarnings}} + +--- + +### Warnings + +Please make sure the following warnings are safe to ignore: + +{{#each warnings as |warning|}} +- \`{{warning.depName}}\`: {{warning.message}} +{{/each}} +{{/if}} + +--- + +This {{#if isGitHub}}PR{{else}}MR{{/if}} has been generated by [Renovate Bot](https://renovateapp.com).", + "prCreation": "immediate", + "prNotPendingHours": 12, + "prTitle": "{{#if isPin}}Pin{{else}}{{#if isRollback}}Roll back{{else}}Update{{/if}}{{/if}} dependency {{depName}} to {{#if isRange}}{{newVersion}}{{else}}{{#if isMajor}}v{{newVersionMajor}}{{else}}v{{newVersion}}{{/if}}{{/if}}", + "privateKey": null, + "rebaseStalePrs": false, + "recreateClosed": false, + "renovateFork": false, + "repoIsOnboarded": true, + "repositories": Array [], + "requiredStatusChecks": Array [], + "respectLatest": true, + "reviewers": Array [], + "schedule": Array [], + "semanticCommits": null, + "semanticPrefix": "chore(deps):", + "separateMajorReleases": true, + "separatePatchReleases": false, + "timezone": null, + "token": null, + "unpublishSafe": false, + "updateNotScheduled": true, + "upgrades": null, + "warnings": Array [], + "yarnrc": null, +} +`; diff --git a/test/workers/repository/updates/__snapshots__/generate.spec.js.snap b/test/workers/repository/updates/__snapshots__/generate.spec.js.snap new file mode 100644 index 0000000000000000000000000000000000000000..f9dddb3d209ebd243e2b8edbf7baab6e4d06eb57 --- /dev/null +++ b/test/workers/repository/updates/__snapshots__/generate.spec.js.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workers/repository/updates/generate generateBranchConfig() does not group single upgrade 1`] = ` +Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 1, + "prTitle": "some-prefix: some-title", + "semanticCommits": true, + "semanticPrefix": "some-prefix:", + "upgrades": Array [ + Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 1, + "prTitle": "some-prefix: some-title", + "semanticCommits": true, + "semanticPrefix": "some-prefix:", + }, + ], +} +`; + +exports[`workers/repository/updates/generate generateBranchConfig() groups multiple upgrades 1`] = ` +Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 2, + "groupName": "some-group", + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 2, + "groupName": "some-group", + "prTitle": "some-title", + }, + Object { + "branchName": "some-branch", + "depName": "some-other-dep", + "foo": 2, + "groupName": "some-group", + "prTitle": "some-title", + }, + ], +} +`; + +exports[`workers/repository/updates/generate generateBranchConfig() groups single upgrade if not lazyGrouping 1`] = ` +Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 2, + "groupName": "some-group", + "prTitle": "some-title", + "upgrades": Array [ + Object { + "branchName": "some-branch", + "depName": "some-dep", + "foo": 2, + "groupName": "some-group", + "prTitle": "some-title", + }, + ], +} +`; diff --git a/test/workers/repository/updates/branchify.spec.js b/test/workers/repository/updates/branchify.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..5cedad618cda955ddb14a617b7595c0cf6999e5e --- /dev/null +++ b/test/workers/repository/updates/branchify.spec.js @@ -0,0 +1,142 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = { ...require('../../../_fixtures/config') }; + config.errors = []; + config.warnings = []; +}); + +const { + branchifyUpgrades, +} = require('../../../../lib/workers/repository/updates/branchify'); + +describe('workers/repository/updates/branchify', () => { + describe('branchifyUpgrades()', () => { + it('returns empty', async () => { + config.upgrades = []; + const res = await branchifyUpgrades(config); + expect(res.branches).toEqual([]); + }); + it('returns one branch if one input', async () => { + config.upgrades = [ + { + depName: 'foo', + branchName: 'foo-{{version}}', + version: '1.1.0', + prTitle: 'some-title', + }, + ]; + config.repoIsOnboarded = true; + const res = await branchifyUpgrades(config); + expect(Object.keys(res.branches).length).toBe(1); + expect(res).toMatchSnapshot(); + }); + it('does not group if different compiled branch names', async () => { + config.upgrades = [ + { + depName: 'foo', + branchName: 'foo-{{version}}', + version: '1.1.0', + prTitle: 'some-title', + }, + { + depName: 'foo', + branchName: 'foo-{{version}}', + version: '2.0.0', + prTitle: 'some-title', + }, + { + depName: 'bar', + branchName: 'bar-{{version}}', + version: '1.1.0', + prTitle: 'some-title', + }, + ]; + const res = await branchifyUpgrades(config); + expect(Object.keys(res.branches).length).toBe(3); + expect(res).toMatchSnapshot(); + }); + it('groups if same compiled branch names', async () => { + config.upgrades = [ + { + depName: 'foo', + branchName: 'foo', + version: '1.1.0', + prTitle: 'some-title', + }, + { + depName: 'foo', + branchName: 'foo', + version: '2.0.0', + prTitle: 'some-title', + }, + { + depName: 'bar', + branchName: 'bar-{{version}}', + version: '1.1.0', + prTitle: 'some-title', + }, + ]; + const res = await branchifyUpgrades(config); + expect(Object.keys(res.branches).length).toBe(2); + expect(res).toMatchSnapshot(); + }); + it('groups if same compiled group name', async () => { + config.upgrades = [ + { + depName: 'foo', + branchName: 'foo', + prTitle: 'some-title', + version: '1.1.0', + groupName: 'My Group', + group: { branchName: 'renovate/{{groupSlug}}' }, + }, + { + depName: 'foo', + branchName: 'foo', + prTitle: 'some-title', + version: '2.0.0', + }, + { + depName: 'bar', + branchName: 'bar-{{version}}', + prTitle: 'some-title', + version: '1.1.0', + groupName: 'My Group', + group: { branchName: 'renovate/my-group' }, + }, + ]; + const res = await branchifyUpgrades(config); + expect(Object.keys(res.branches).length).toBe(2); + expect(res).toMatchSnapshot(); + }); + it('mixes errors and warnings', async () => { + config.upgrades = [ + { + type: 'error', + }, + { + branchName: 'foo-{{version}}', + prTitle: 'some-title', + version: '1.1.0', + }, + { + type: 'warning', + branchName: 'foo-{{version}}', + prTitle: 'some-title', + version: '2.0.0', + }, + { + branchName: 'bar-{{version}}', + prTitle: 'some-title', + version: '1.1.0', + }, + ]; + const res = await branchifyUpgrades(config); + expect(Object.keys(res.branches).length).toBe(2); + expect(res.errors).toHaveLength(1); + expect(res.warnings).toHaveLength(1); + expect(res).toMatchSnapshot(); + }); + }); +}); diff --git a/test/workers/repository/updates/determine.spec.js b/test/workers/repository/updates/determine.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..6311d37432c49d010e6fc72175b9452faaa7242e --- /dev/null +++ b/test/workers/repository/updates/determine.spec.js @@ -0,0 +1,56 @@ +jest.mock('../../../../lib/workers/package-file'); + +const packageFileWorker = require('../../../../lib/workers/package-file'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); +}); + +const { + determineRepoUpgrades, +} = require('../../../../lib/workers/repository/updates/determine'); + +describe('workers/repository/updates/determine', () => { + describe('determineRepoUpgrades(config)', () => { + it('returns empty array if none found', async () => { + config.packageFiles = [ + { + packageFile: 'package.json', + }, + { + packageFile: 'backend/package.json', + }, + ]; + packageFileWorker.renovatePackageFile.mockReturnValue([]); + const res = await determineRepoUpgrades(config); + expect(res.upgrades).toHaveLength(0); + }); + it('returns array if upgrades found', async () => { + config.packageFiles = [ + { + packageFile: 'Dockerfile', + }, + { + packageFile: 'backend/package.json', + }, + { + packageFile: 'frontend/package.js', + }, + ]; + packageFileWorker.renovateDockerfile.mockReturnValueOnce([ + { depName: 'a' }, + ]); + packageFileWorker.renovatePackageFile.mockReturnValueOnce([ + { depName: 'b' }, + { depName: 'c' }, + ]); + packageFileWorker.renovateMeteorPackageFile.mockReturnValueOnce([ + { foo: 'd' }, + ]); + const res = await determineRepoUpgrades(config); + expect(res.upgrades).toHaveLength(4); + }); + }); +}); diff --git a/test/workers/repository/updates/generate.spec.js b/test/workers/repository/updates/generate.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..28b0d8aa8f2a4ee7b3d3abd62450ea7e50e10492 --- /dev/null +++ b/test/workers/repository/updates/generate.spec.js @@ -0,0 +1,113 @@ +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); +}); + +const { + generateBranchConfig, +} = require('../../../../lib/workers/repository/updates/generate'); + +describe('workers/repository/updates/generate', () => { + describe('generateBranchConfig()', () => { + it('does not group single upgrade', () => { + const branch = [ + { + depName: 'some-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + semanticCommits: true, + semanticPrefix: 'some-prefix:', + lazyGrouping: true, + foo: 1, + group: { + foo: 2, + }, + }, + ]; + const res = generateBranchConfig(branch, config.logger); + expect(res.foo).toBe(1); + expect(res.groupName).toBeUndefined(); + expect(res).toMatchSnapshot(); + }); + it('groups single upgrade if not lazyGrouping', () => { + const branch = [ + { + depName: 'some-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + lazyGrouping: false, + foo: 1, + group: { + foo: 2, + }, + }, + ]; + const res = generateBranchConfig(branch, config.logger); + expect(res.foo).toBe(2); + expect(res.groupName).toBeDefined(); + expect(res).toMatchSnapshot(); + }); + it('does not group same upgrades', () => { + const branch = [ + { + depName: 'some-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + lazyGrouping: true, + foo: 1, + group: { + foo: 2, + }, + }, + { + depName: 'some-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + lazyGrouping: true, + foo: 1, + group: { + foo: 2, + }, + }, + ]; + const res = generateBranchConfig(branch, config.logger); + expect(res.foo).toBe(1); + expect(res.groupName).toBeUndefined(); + }); + it('groups multiple upgrades', () => { + const branch = [ + { + depName: 'some-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + lazyGrouping: true, + foo: 1, + group: { + foo: 2, + }, + }, + { + depName: 'some-other-dep', + groupName: 'some-group', + branchName: 'some-branch', + prTitle: 'some-title', + lazyGrouping: true, + foo: 1, + group: { + foo: 2, + }, + }, + ]; + const res = generateBranchConfig(branch, config.logger); + expect(res.foo).toBe(2); + expect(res.groupName).toBeDefined(); + expect(res).toMatchSnapshot(); + }); + }); +}); diff --git a/test/workers/repository/updates/index.spec.js b/test/workers/repository/updates/index.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..f8c3a784296741cd1fd6b65eb85efebe44f7f5b8 --- /dev/null +++ b/test/workers/repository/updates/index.spec.js @@ -0,0 +1,20 @@ +jest.mock('../../../../lib/workers/repository/updates/determine'); +jest.mock('../../../../lib/workers/repository/updates/branchify'); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = require('../../../_fixtures/config'); +}); + +const { + determineUpdates, +} = require('../../../../lib/workers/repository/updates'); + +describe('workers/repository/updates', () => { + describe('determineUpdates()', () => { + it('runs', async () => { + await determineUpdates(config, 'some-token'); + }); + }); +}); diff --git a/test/workers/repository/upgrades.spec.js b/test/workers/repository/upgrades.spec.js deleted file mode 100644 index 90af11b79b1490cc460191482743766e6c22be72..0000000000000000000000000000000000000000 --- a/test/workers/repository/upgrades.spec.js +++ /dev/null @@ -1,306 +0,0 @@ -const upgrades = require('../../../lib/workers/repository/upgrades'); -const packageFileWorker = require('../../../lib/workers/package-file'); -const logger = require('../../_fixtures/logger'); - -jest.mock('../../../lib/workers/package-file'); - -describe('workers/repository/upgrades', () => { - describe('determineRepoUpgrades(config)', () => { - let config; - beforeEach(() => { - config = { - logger, - }; - }); - it('returns empty array if no packageFiles', async () => { - config.packageFiles = []; - const res = await upgrades.determineRepoUpgrades(config); - expect(res.length).toBe(0); - }); - it('returns empty array if none found', async () => { - config.packageFiles = [ - 'package.json', - { - packageFile: 'backend/package.json', - }, - ]; - packageFileWorker.renovatePackageFile.mockReturnValue([]); - const res = await upgrades.determineRepoUpgrades(config); - expect(res.length).toBe(0); - }); - it('returns array if upgrades found', async () => { - config.packageFiles = [ - 'Dockerfile', - { - packageFile: 'backend/package.json', - }, - { - packageFile: 'frontend/package.js', - }, - ]; - packageFileWorker.renovateDockerfile.mockReturnValueOnce([ - { depName: 'a' }, - ]); - packageFileWorker.renovatePackageFile.mockReturnValueOnce([ - { depName: 'b' }, - { depName: 'c' }, - ]); - packageFileWorker.renovateMeteorPackageFile.mockReturnValueOnce([ - { foo: 'd' }, - ]); - const res = await upgrades.determineRepoUpgrades(config); - expect(res).toHaveLength(4); - }); - }); - describe('generateConfig(branchUpgrades)', () => { - it('does not group single upgrade', () => { - const branchUpgrades = [ - { - depName: 'some-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - semanticCommits: true, - semanticPrefix: 'some-prefix:', - lazyGrouping: true, - foo: 1, - group: { - foo: 2, - }, - }, - ]; - const res = upgrades.generateConfig(branchUpgrades); - expect(res.foo).toBe(1); - expect(res.groupName).toBeUndefined(); - expect(res).toMatchSnapshot(); - }); - it('groups single upgrade if not lazyGrouping', () => { - const branchUpgrades = [ - { - depName: 'some-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - lazyGrouping: false, - foo: 1, - group: { - foo: 2, - }, - }, - ]; - const res = upgrades.generateConfig(branchUpgrades); - expect(res.foo).toBe(2); - expect(res.groupName).toBeDefined(); - expect(res).toMatchSnapshot(); - }); - it('does not group same upgrades', () => { - const branchUpgrades = [ - { - depName: 'some-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - lazyGrouping: true, - foo: 1, - group: { - foo: 2, - }, - }, - { - depName: 'some-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - lazyGrouping: true, - foo: 1, - group: { - foo: 2, - }, - }, - ]; - const res = upgrades.generateConfig(branchUpgrades); - expect(res.foo).toBe(1); - expect(res.groupName).toBeUndefined(); - }); - it('groups multiple upgrades', () => { - const branchUpgrades = [ - { - depName: 'some-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - lazyGrouping: true, - foo: 1, - group: { - foo: 2, - }, - }, - { - depName: 'some-other-dep', - groupName: 'some-group', - branchName: 'some-branch', - prTitle: 'some-title', - lazyGrouping: true, - foo: 1, - group: { - foo: 2, - }, - }, - ]; - const res = upgrades.generateConfig(branchUpgrades); - expect(res.foo).toBe(2); - expect(res.groupName).toBeDefined(); - expect(res).toMatchSnapshot(); - }); - }); - describe('groupByBranch(upgrades)', () => { - it('returns empty object if no input array', async () => { - const res = await upgrades.groupByBranch([]); - expect(res).toMatchSnapshot(); - }); - it('returns one branch if one input', async () => { - const input = [ - { - depName: 'foo', - branchName: 'foo-{{version}}', - version: '1.1.0', - prTitle: 'some-title', - }, - ]; - const res = await upgrades.groupByBranch(input); - expect(Object.keys(res.branchUpgrades).length).toBe(1); - expect(res).toMatchSnapshot(); - }); - it('does not group if different compiled branch names', async () => { - const input = [ - { - depName: 'foo', - branchName: 'foo-{{version}}', - version: '1.1.0', - prTitle: 'some-title', - }, - { - depName: 'foo', - branchName: 'foo-{{version}}', - version: '2.0.0', - prTitle: 'some-title', - }, - { - depName: 'bar', - branchName: 'bar-{{version}}', - version: '1.1.0', - prTitle: 'some-title', - }, - ]; - const res = await upgrades.groupByBranch(input); - expect(Object.keys(res.branchUpgrades).length).toBe(3); - expect(res).toMatchSnapshot(); - }); - it('groups if same compiled branch names', async () => { - const input = [ - { - depName: 'foo', - branchName: 'foo', - version: '1.1.0', - prTitle: 'some-title', - }, - { - depName: 'foo', - branchName: 'foo', - version: '2.0.0', - prTitle: 'some-title', - }, - { - depName: 'bar', - branchName: 'bar-{{version}}', - version: '1.1.0', - prTitle: 'some-title', - }, - ]; - const res = await upgrades.groupByBranch(input); - expect(Object.keys(res.branchUpgrades).length).toBe(2); - expect(res).toMatchSnapshot(); - }); - it('groups if same compiled group name', async () => { - const input = [ - { - depName: 'foo', - branchName: 'foo', - prTitle: 'some-title', - version: '1.1.0', - groupName: 'My Group', - group: { branchName: 'renovate/{{groupSlug}}' }, - }, - { - depName: 'foo', - branchName: 'foo', - prTitle: 'some-title', - version: '2.0.0', - }, - { - depName: 'bar', - branchName: 'bar-{{version}}', - prTitle: 'some-title', - version: '1.1.0', - groupName: 'My Group', - group: { branchName: 'renovate/my-group' }, - }, - ]; - const res = await upgrades.groupByBranch(input); - expect(Object.keys(res.branchUpgrades).length).toBe(2); - expect(res).toMatchSnapshot(); - }); - it('mixes errors and warnings', async () => { - const input = [ - { - type: 'error', - }, - { - branchName: 'foo-{{version}}', - prTitle: 'some-title', - version: '1.1.0', - }, - { - type: 'warning', - branchName: 'foo-{{version}}', - prTitle: 'some-title', - version: '2.0.0', - }, - { - branchName: 'bar-{{version}}', - prTitle: 'some-title', - version: '1.1.0', - }, - ]; - const res = await upgrades.groupByBranch(input); - expect(Object.keys(res.branchUpgrades).length).toBe(2); - expect(res.errors).toHaveLength(1); - expect(res.warnings).toHaveLength(1); - expect(res).toMatchSnapshot(); - }); - }); - describe('branchifyUpgrades(upgrades, parentLogger)', () => { - it('returns empty', async () => { - upgrades.groupByBranch = jest.fn(() => ({ - branchUpgrades: {}, - errors: [], - warnings: [], - })); - const res = await upgrades.branchifyUpgrades({}); - expect(res.upgrades).toEqual([]); - }); - it('processes multiple branches', async () => { - upgrades.groupByBranch = jest.fn(() => ({ - branchUpgrades: { - a: [], - b: [], - }, - errors: [], - warnings: [], - })); - upgrades.generateConfig = jest.fn(() => ({})); - const res = await upgrades.branchifyUpgrades({}); - expect(res.upgrades).toHaveLength(2); - }); - }); -}); diff --git a/test/workers/repository/write.spec.js b/test/workers/repository/write.spec.js new file mode 100644 index 0000000000000000000000000000000000000000..6f8e3358118ff5e300845b932511bb45e846e567 --- /dev/null +++ b/test/workers/repository/write.spec.js @@ -0,0 +1,29 @@ +const { writeUpdates } = require('../../../lib/workers/repository/write'); +const branchWorker = require('../../../lib/workers/branch'); + +branchWorker.processBranch = jest.fn(); + +let config; +beforeEach(() => { + jest.resetAllMocks(); + config = { ...require('../../_fixtures/config') }; +}); + +describe('workers/repository/write', () => { + describe('writeUpdates()', () => { + it('runs pins first', async () => { + config.branches = [{ isPin: true }, {}, {}]; + const res = await writeUpdates(config); + expect(res).toEqual('done'); + expect(branchWorker.processBranch.mock.calls).toHaveLength(1); + }); + it('stops after automerge', async () => { + config.branches = [{}, {}, {}]; + branchWorker.processBranch.mockReturnValueOnce('created'); + branchWorker.processBranch.mockReturnValueOnce('automerged'); + const res = await writeUpdates(config); + expect(res).toEqual('automerged'); + expect(branchWorker.processBranch.mock.calls).toHaveLength(2); + }); + }); +});