diff --git a/lib/workers/branch/index.js b/lib/workers/branch/index.js index fce07cf9b4c8aa60df1e96c35744c35893c596fb..ef803acd49971cbffd6393de115414425f294bdd 100644 --- a/lib/workers/branch/index.js +++ b/lib/workers/branch/index.js @@ -52,7 +52,7 @@ async function processBranch(branchConfig) { } Object.assign(config, await getUpdatedLockFiles(config)); if (config.lockFileError) { - throw new Error('lockFileError'); + return 'lockFileError'; } if (config.updatedLockFiles.length) { logger.debug( @@ -81,11 +81,7 @@ async function processBranch(branchConfig) { return 'automerged'; } } catch (err) { - if (err.message !== 'lockFileError') { - logger.error({ err }, `Error updating branch: ${err.message}`); - } else { - logger.info('Error updating branch'); - } + logger.error({ err }, `Error updating branch: ${err.message}`); // Don't throw here - we don't want to stop the other renovations return 'error'; } diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js index 61f8c6899b186bc3fdfae6bcdf0b8e4a9bb35193..709a6ba7bdc8849aec04e2817a11d15f877a6c98 100644 --- a/lib/workers/repository/index.js +++ b/lib/workers/repository/index.js @@ -10,9 +10,20 @@ const cleanup = require('./cleanup'); const { decryptConfig } = require('../../config/decrypt'); module.exports = { + pinDependenciesFirst, renovateRepository, }; +function pinDependenciesFirst(a, b) { + if (a.type === 'pin') { + return false; + } + if (b.type === 'pin') { + return true; + } + return a.branchName > b.branchName; +} + async function renovateRepository(repoConfig, token) { let config = { ...repoConfig }; const { logger } = config; @@ -111,22 +122,28 @@ async function renovateRepository(repoConfig, token) { logger.debug(`Updating ${branchUpgrades.length} branch(es)`); logger.trace({ config: branchUpgrades }, 'branchUpgrades'); if (config.repoIsOnboarded) { + logger.info(`Processing ${branchUpgrades.length} branch(es)`); + // eslint-disable-next-line no-loop-function + branchUpgrades.sort(pinDependenciesFirst); for (const branchUpgrade of branchUpgrades) { - if (!baseBranchUpdated) { - 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'); - baseBranchUpdated = true; - } - } else { - logger.debug( - `Skipping branchUpgrade as base branch has been modified` + 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'); + baseBranchUpdated = true; + break; + } else if (branchResult === 'lockFileError') { + logger.info('Lock file error - stopping branch updates'); + break; + } else if (branchUpgrade.type === 'pin') { + logger.info( + 'Stopping branch processing until Pin Dependencies is merged' ); + break; } } branchList = branchUpgrades.map(upgrade => upgrade.branchName); 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..d73bfc6c3d56693342a9983c6a5cfcf586e487c3 --- /dev/null +++ b/test/workers/repository/__snapshots__/index.spec.js.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`workers/repository pinDependenciesFirst returns pin first 1`] = ` +Array [ + Object { + "branchName": "d", + "type": "pin", + }, + Object { + "branchName": "a", + }, + Object { + "branchName": "b", + }, + Object { + "branchName": "c", + }, +] +`; + +exports[`workers/repository pinDependenciesFirst returns pin first 2`] = ` +Array [ + Object { + "branchName": "d", + "type": "pin", + }, + Object { + "branchName": "a", + }, + Object { + "branchName": "b", + }, + Object { + "branchName": "c", + }, +] +`; + +exports[`workers/repository pinDependenciesFirst returns sorted if no pin 1`] = ` +Array [ + Object { + "branchName": "a", + }, + Object { + "branchName": "b", + }, + Object { + "branchName": "c", + }, +] +`; diff --git a/test/workers/repository/index.spec.js b/test/workers/repository/index.spec.js index eeeb26b1300362d0b9b7fcceccb42c8ff4756da9..f6b87e2af86b496516a7271f9a557b86b968ce5b 100644 --- a/test/workers/repository/index.spec.js +++ b/test/workers/repository/index.spec.js @@ -8,6 +8,37 @@ const upgrades = require('../../../lib/workers/repository/upgrades'); const logger = require('../../_fixtures/logger'); describe('workers/repository', () => { + describe('pinDependenciesFirst', () => { + it('returns sorted if no pin', () => { + const arr = [ + { branchName: 'a' }, + { branchName: 'c' }, + { branchName: 'b' }, + ]; + arr.sort(repositoryWorker.pinDependenciesFirst); + expect(arr).toMatchSnapshot(); + }); + it('returns pin first', () => { + const arr = [ + { branchName: 'a' }, + { branchName: 'c' }, + { branchName: 'd', type: 'pin' }, + { branchName: 'b' }, + ]; + arr.sort(repositoryWorker.pinDependenciesFirst); + expect(arr).toMatchSnapshot(); + }); + it('returns pin first', () => { + const arr = [ + { branchName: 'd', type: 'pin' }, + { branchName: 'a' }, + { branchName: 'c' }, + { branchName: 'b' }, + ]; + arr.sort(repositoryWorker.pinDependenciesFirst); + expect(arr).toMatchSnapshot(); + }); + }); describe('renovateRepository', () => { let config; beforeEach(() => { @@ -175,6 +206,32 @@ describe('workers/repository', () => { expect(branchWorker.processBranch.mock.calls).toHaveLength(3); expect(config.logger.error.mock.calls).toHaveLength(0); }); + it('stops branchWorker after lockFileError', async () => { + config.packageFiles = ['package.json']; + config.hasRenovateJson = true; + onboarding.getOnboardingStatus.mockReturnValue(true); + upgrades.branchifyUpgrades.mockReturnValueOnce({ + upgrades: [{}, {}, {}], + }); + branchWorker.processBranch.mockReturnValue('lockFileError'); + 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('stops branchWorker after pin', async () => { + config.packageFiles = ['package.json']; + config.hasRenovateJson = true; + onboarding.getOnboardingStatus.mockReturnValue(true); + upgrades.branchifyUpgrades.mockReturnValueOnce({ + upgrades: [{ type: 'pin' }, {}, {}], + }); + 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');