refactor: renovateRepository split (#1928)

This commit is contained in:
Rhys Arkins 2018-05-07 12:59:32 +02:00 committed by GitHub
parent eab997bf6e
commit 2517c9f1d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 248 additions and 135 deletions

View file

@ -1,12 +1,9 @@
const { initRepo } = require('./init'); const { initRepo } = require('./init');
const { determineUpdates } = require('./updates');
const { ensureOnboardingPr } = require('./onboarding/pr'); const { ensureOnboardingPr } = require('./onboarding/pr');
const { writeUpdates } = require('./write');
const { handleError } = require('./error'); const { handleError } = require('./error');
const { finaliseRepo } = require('./finalise');
const { processResult } = require('./result'); const { processResult } = require('./result');
const { resolvePackageFiles } = require('../../manager'); const { processRepo } = require('./process');
const { sortBranches } = require('./process/sort'); const { finaliseRepo } = require('./finalise');
module.exports = { module.exports = {
renovateRepository, renovateRepository,
@ -17,52 +14,21 @@ async function renovateRepository(repoConfig) {
logger.setMeta({ repository: config.repository }); logger.setMeta({ repository: config.repository });
logger.info('Renovating repository'); logger.info('Renovating repository');
logger.trace({ config }, 'renovateRepository()'); logger.trace({ config }, 'renovateRepository()');
let commonConfig;
let res;
try { try {
config = await initRepo(config); config = await initRepo(config);
if (config.baseBranches && config.baseBranches.length) { let res;
// At this point we know if we have multiple branches let branches;
// Do the following for every branch let branchList;
commonConfig = JSON.parse(JSON.stringify(config)); let packageFiles;
const configs = []; ({ res, branches, branchList, packageFiles } = await processRepo(config)); // eslint-disable-line prefer-const
logger.info({ baseBranches: config.baseBranches }, 'baseBranches'); if (!config.repoIsOnboarded) {
for (const [index, baseBranch] of commonConfig.baseBranches.entries()) { res = await ensureOnboardingPr(config, packageFiles, branches);
config = JSON.parse(JSON.stringify(commonConfig));
config.baseBranch = baseBranch;
config.branchPrefix +=
config.baseBranches.length > 1 ? `${baseBranch}-` : '';
platform.setBaseBranch(baseBranch);
config = await resolvePackageFiles(config);
config = await determineUpdates(config);
configs[index] = config;
}
// Combine all the results into one
for (const [index, entry] of configs.entries()) {
if (index === 0) {
config = entry;
} else {
config.branches = config.branches.concat(entry.branches);
}
}
// istanbul ignore next
config.branchList = config.branches.map(branch => branch.branchName);
} else {
config = await resolvePackageFiles(config);
config = await determineUpdates(config);
} }
sortBranches(config.branches); await finaliseRepo(config, branchList);
res = config.repoIsOnboarded return processResult(config, res);
? await writeUpdates(config)
: await ensureOnboardingPr(config, config.branches);
logger.setMeta({ repository: config.repository });
config.branchPrefix = commonConfig
? commonConfig.branchPrefix
: config.branchPrefix;
await finaliseRepo(commonConfig || config, config.branchList);
} catch (err) /* istanbul ignore next */ { } catch (err) /* istanbul ignore next */ {
res = await handleError(config, err); return processResult(config, await handleError(config, err));
} finally {
logger.info('Finished repository');
} }
logger.info('Finished repository');
return processResult(config, res);
} }

View file

@ -3,7 +3,7 @@ const { getErrors, getWarnings } = require('./errors-warnings');
const { getBaseBranchDesc } = require('./base-branch'); const { getBaseBranchDesc } = require('./base-branch');
const { getPrList } = require('./pr-list'); const { getPrList } = require('./pr-list');
async function ensureOnboardingPr(config, branches) { async function ensureOnboardingPr(config, packageFiles, branches) {
logger.debug('ensureOnboardingPr()'); logger.debug('ensureOnboardingPr()');
logger.trace({ config }); logger.trace({ config });
const onboardingBranch = `renovate/configure`; const onboardingBranch = `renovate/configure`;
@ -27,15 +27,17 @@ You can post questions in [our Config Help repository](https://github.com/renova
--- ---
`; `;
let prBody = prTemplate; let prBody = prTemplate;
if (config.packageFiles.length) { if (packageFiles && packageFiles.length) {
prBody = prBody =
prBody.replace( prBody.replace(
'{{PACKAGE FILES}}', '{{PACKAGE FILES}}',
'## Detected Package Files\n\n' + '## Detected Package Files\n\n' +
config.packageFiles packageFiles
.map(packageFile => ` * \`${packageFile.packageFile}\``) .map(packageFile => ` * \`${packageFile.packageFile}\``)
.join('\n') .join('\n')
) + '\n'; ) + '\n';
} else {
prBody = prBody.replace('{{PACKAGE FILES}}\n', '');
} }
prBody = prBody.replace('{{CONFIG}}\n', getConfigDesc(config)); prBody = prBody.replace('{{CONFIG}}\n', getConfigDesc(config));
prBody = prBody.replace('{{WARNINGS}}\n', getWarnings(config)); prBody = prBody.replace('{{WARNINGS}}\n', getWarnings(config));

View file

@ -20,7 +20,7 @@ function getPrList(config, branches) {
prDesc += ` - Schedule: ${JSON.stringify(branch.schedule)}\n`; prDesc += ` - Schedule: ${JSON.stringify(branch.schedule)}\n`;
} }
prDesc += ` - Branch name: \`${branch.branchName}\`\n`; prDesc += ` - Branch name: \`${branch.branchName}\`\n`;
prDesc += config.baseBranch prDesc += branch.baseBranch
? ` - Merge into: \`${branch.baseBranch}\`\n` ? ` - Merge into: \`${branch.baseBranch}\`\n`
: ''; : '';
for (const upgrade of branch.upgrades) { for (const upgrade of branch.upgrades) {

View file

@ -0,0 +1,21 @@
const { determineUpdates } = require('../updates');
const { writeUpdates } = require('./write');
const { sortBranches } = require('./sort');
const { resolvePackageFiles } = require('../../../manager');
module.exports = {
extractAndUpdate,
};
async function extractAndUpdate(input) {
let config = await resolvePackageFiles(input);
config = await determineUpdates(config);
const { branches, branchList, packageFiles } = config;
sortBranches(branches);
let res;
if (config.repoIsOnboarded) {
res = await writeUpdates(config);
}
logger.setMeta({ repository: config.repository });
return { res, branches, branchList, packageFiles };
}

View file

@ -0,0 +1,28 @@
const { mergeChildConfig } = require('../../../config');
const { extractAndUpdate } = require('./extract-update');
module.exports = {
processRepo,
};
async function processRepo(config) {
if (config.baseBranches && config.baseBranches.length) {
logger.info({ baseBranches: config.baseBranches }, 'baseBranches');
let res;
let branches = [];
let branchList = [];
for (const baseBranch of config.baseBranches) {
logger.debug(`baseBranch: ${baseBranch}`);
const baseBranchConfig = mergeChildConfig(config, { baseBranch });
baseBranchConfig.branchPrefix += `${baseBranch}-`;
baseBranchConfig.hasBaseBranches = true;
platform.setBaseBranch(baseBranch);
const baseBranchRes = await extractAndUpdate(baseBranchConfig);
({ res } = baseBranchRes);
branches = branches.concat(baseBranchRes.branches);
branchList = branchList.concat(baseBranchRes.branchList);
}
return { res, branches, branchList };
}
return extractAndUpdate(config);
}

View file

@ -1,7 +1,7 @@
const moment = require('moment'); const moment = require('moment');
const tmp = require('tmp-promise'); const tmp = require('tmp-promise');
const branchWorker = require('../branch'); const branchWorker = require('../../branch');
module.exports = { module.exports = {
writeUpdates, writeUpdates,

View file

@ -104,10 +104,7 @@ function generateBranchConfig(branchUpgrades) {
} else { } else {
[upgrade.prTitle] = upgrade.commitMessage.split('\n'); [upgrade.prTitle] = upgrade.commitMessage.split('\n');
} }
upgrade.prTitle += upgrade.prTitle += upgrade.hasBaseBranches ? ' ({{baseBranch}})' : '';
upgrade.baseBranches && upgrade.baseBranches.length > 1
? ' ({{baseBranch}})'
: '';
logger.debug(`prTitle: ` + JSON.stringify(upgrade.prTitle)); logger.debug(`prTitle: ` + JSON.stringify(upgrade.prTitle));
// Compile again to allow for nested handlebars templates // Compile again to allow for nested handlebars templates
upgrade.prTitle = handlebars.compile(upgrade.prTitle)(upgrade); upgrade.prTitle = handlebars.compile(upgrade.prTitle)(upgrade);

View file

@ -1,39 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/repository renovateRepository() ensures onboarding pr 1`] = `
Object {
"res": "done",
"status": "onboarding",
}
`;
exports[`workers/repository renovateRepository() ensures onboarding pr 2`] = `
Array [
Object {
"prTitle": "aaa",
"type": "pin",
},
Object {
"prTitle": "bbb",
"type": "pin",
},
Object {
"prTitle": "aaa",
"type": "minor",
},
]
`;
exports[`workers/repository renovateRepository() handles baseBranches 1`] = `
Object {
"res": "done",
"status": "enabled",
}
`;
exports[`workers/repository renovateRepository() writes 1`] = ` exports[`workers/repository renovateRepository() writes 1`] = `
Object { Object {
"res": "done", "res": undefined,
"status": "enabled", "status": "onboarding",
} }
`; `;

View file

@ -1,16 +1,15 @@
const { initRepo } = require('../../../lib/workers/repository/init'); const { initRepo } = require('../../../lib/workers/repository/init');
const { determineUpdates } = require('../../../lib/workers/repository/updates'); const { determineUpdates } = require('../../../lib/workers/repository/updates');
const { writeUpdates } = require('../../../lib/workers/repository/write');
const { const {
ensureOnboardingPr, writeUpdates,
} = require('../../../lib/workers/repository/onboarding/pr'); } = require('../../../lib/workers/repository/process/write');
const { renovateRepository } = require('../../../lib/workers/repository/index'); const { renovateRepository } = require('../../../lib/workers/repository/index');
jest.mock('../../../lib/workers/repository/init'); jest.mock('../../../lib/workers/repository/init');
jest.mock('../../../lib/workers/repository/init/apis'); jest.mock('../../../lib/workers/repository/init/apis');
jest.mock('../../../lib/workers/repository/updates'); jest.mock('../../../lib/workers/repository/updates');
jest.mock('../../../lib/workers/repository/onboarding/pr'); jest.mock('../../../lib/workers/repository/onboarding/pr');
jest.mock('../../../lib/workers/repository/write'); jest.mock('../../../lib/workers/repository/process/write');
jest.mock('../../../lib/workers/repository/finalise'); jest.mock('../../../lib/workers/repository/finalise');
jest.mock('../../../lib/manager'); jest.mock('../../../lib/manager');
jest.mock('delay'); jest.mock('delay');
@ -33,39 +32,5 @@ describe('workers/repository', () => {
const res = await renovateRepository(config, 'some-token'); const res = await renovateRepository(config, 'some-token');
expect(res).toMatchSnapshot(); expect(res).toMatchSnapshot();
}); });
it('ensures onboarding pr', async () => {
initRepo.mockReturnValue({});
determineUpdates.mockReturnValue({
repoIsOnboarded: false,
branches: [
{
type: 'pin',
prTitle: 'bbb',
},
{
type: 'pin',
prTitle: 'aaa',
},
{
type: 'minor',
prTitle: 'aaa',
},
],
});
ensureOnboardingPr.mockReturnValue('onboarding');
const res = await renovateRepository(config, 'some-token');
expect(res).toMatchSnapshot();
expect(ensureOnboardingPr.mock.calls[0][0].branches).toMatchSnapshot();
});
it('handles baseBranches', async () => {
initRepo.mockReturnValue({ baseBranches: ['master', 'next'] });
determineUpdates.mockReturnValue({
repoIsOnboarded: true,
branches: [],
});
writeUpdates.mockReturnValueOnce('done');
const res = await renovateRepository(config, 'some-token');
expect(res).toMatchSnapshot();
});
}); });
}); });

View file

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/repository/onboarding/pr/base-branch getBaseBranchDesc() describes baseBranch 1`] = `
"You have configured renovate to use branch \`some-branch\` as base branch.
"
`;

View file

@ -1,5 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/repository/onboarding/pr/pr-list getPrList() handles emptyu 1`] = `
"
### What to Expect
It looks like your repository dependencies are already up-to-date and no Pull Requests will be necessary right away.
"
`;
exports[`workers/repository/onboarding/pr/pr-list getPrList() handles multiple 1`] = ` exports[`workers/repository/onboarding/pr/pr-list getPrList() handles multiple 1`] = `
" "
### What to Expect ### What to Expect

View file

@ -0,0 +1,26 @@
const defaultConfig = require('../../../../../lib/config/defaults').getConfig();
const {
getBaseBranchDesc,
} = require('../../../../../lib/workers/repository/onboarding/pr/base-branch');
describe('workers/repository/onboarding/pr/base-branch', () => {
describe('getBaseBranchDesc()', () => {
let config;
beforeEach(() => {
jest.resetAllMocks();
config = {
...defaultConfig,
};
});
it('returns empty if no baseBranch', () => {
const res = getBaseBranchDesc(config);
expect(res).toEqual('');
});
it('describes baseBranch', () => {
config.baseBranch = 'some-branch';
const res = getBaseBranchDesc(config);
expect(res).toMatchSnapshot();
});
});
});

View file

@ -7,6 +7,8 @@ const {
describe('workers/repository/onboarding/pr', () => { describe('workers/repository/onboarding/pr', () => {
describe('ensureOnboardingPr()', () => { describe('ensureOnboardingPr()', () => {
let config; let config;
let packageFiles;
let branches;
beforeEach(() => { beforeEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
config = { config = {
@ -14,13 +16,14 @@ describe('workers/repository/onboarding/pr', () => {
errors: [], errors: [],
warnings: [], warnings: [],
description: [], description: [],
packageFiles: [{ packageFile: 'package.json' }],
}; };
packageFiles = [{ packageFile: 'package.json' }];
branches = [];
platform.createPr.mockReturnValue({}); platform.createPr.mockReturnValue({});
}); });
let createPrBody; let createPrBody;
it('creates PR', async () => { it('creates PR', async () => {
await ensureOnboardingPr(config, []); await ensureOnboardingPr(config, packageFiles, branches);
expect(platform.createPr.mock.calls).toHaveLength(1); expect(platform.createPr.mock.calls).toHaveLength(1);
createPrBody = platform.createPr.mock.calls[0][2]; createPrBody = platform.createPr.mock.calls[0][2];
}); });
@ -29,7 +32,7 @@ describe('workers/repository/onboarding/pr', () => {
title: 'Configure Renovate', title: 'Configure Renovate',
body: createPrBody, body: createPrBody,
}); });
await ensureOnboardingPr(config, []); await ensureOnboardingPr(config, packageFiles, branches);
expect(platform.createPr.mock.calls).toHaveLength(0); expect(platform.createPr.mock.calls).toHaveLength(0);
expect(platform.updatePr.mock.calls).toHaveLength(0); expect(platform.updatePr.mock.calls).toHaveLength(0);
}); });
@ -39,7 +42,7 @@ describe('workers/repository/onboarding/pr', () => {
title: 'Configure Renovate', title: 'Configure Renovate',
body: createPrBody, body: createPrBody,
}); });
await ensureOnboardingPr(config, []); await ensureOnboardingPr(config, [], branches);
expect(platform.createPr.mock.calls).toHaveLength(0); expect(platform.createPr.mock.calls).toHaveLength(0);
expect(platform.updatePr.mock.calls).toHaveLength(1); expect(platform.updatePr.mock.calls).toHaveLength(1);
}); });

View file

@ -13,6 +13,11 @@ describe('workers/repository/onboarding/pr/pr-list', () => {
...defaultConfig, ...defaultConfig,
}; };
}); });
it('handles emptyu', () => {
const branches = [];
const res = getPrList(config, branches);
expect(res).toMatchSnapshot();
});
it('has special lock file maintenance description', () => { it('has special lock file maintenance description', () => {
const branches = [ const branches = [
{ {

View file

@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/repository/process/index processRepo() processes baseBranches 1`] = `
Object {
"branchList": Array [
undefined,
undefined,
],
"branches": Array [
undefined,
undefined,
],
"res": undefined,
}
`;
exports[`workers/repository/process/index processRepo() processes single branches 1`] = `undefined`;

View file

@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`workers/repository/process/sort sortBranches() sorts based on type and prTitle 1`] = `
Array [
Object {
"prTitle": "some other pin",
"type": "pin",
},
Object {
"prTitle": "some pin",
"type": "pin",
},
Object {
"prTitle": "a minor update",
"type": "minor",
},
Object {
"prTitle": "some major update",
"type": "major",
},
]
`;

View file

@ -0,0 +1,18 @@
const {
extractAndUpdate,
} = require('../../../../lib/workers/repository/process/extract-update');
const updates = require('../../../../lib/workers/repository/updates');
jest.mock('../../../../lib/manager');
jest.mock('../../../../lib/workers/repository/updates');
jest.mock('../../../../lib/workers/repository/process/sort');
jest.mock('../../../../lib/workers/repository/process/write');
describe('workers/repository/process/extract-update', () => {
describe('extractAndUpdate()', () => {
it('runs', async () => {
updates.determineUpdates.mockReturnValue({ repoIsOnboarded: true });
await extractAndUpdate();
});
});
});

View file

@ -0,0 +1,27 @@
const {
processRepo,
} = require('../../../../lib/workers/repository/process/index');
const extractUpdate = require('../../../../lib/workers/repository/process/extract-update');
jest.mock('../../../../lib/workers/repository/process/extract-update');
let config;
beforeEach(() => {
jest.resetAllMocks();
config = require('../../../_fixtures/config');
});
describe('workers/repository/process/index', () => {
describe('processRepo()', () => {
it('processes single branches', async () => {
const res = await processRepo(config);
expect(res).toMatchSnapshot();
});
it('processes baseBranches', async () => {
extractUpdate.extractAndUpdate.mockReturnValue({});
config.baseBranches = ['branch1', 'branch2'];
const res = await processRepo(config);
expect(res).toMatchSnapshot();
});
});
});

View file

@ -0,0 +1,30 @@
const {
sortBranches,
} = require('../../../../lib/workers/repository/process/sort');
describe('workers/repository/process/sort', () => {
describe('sortBranches()', () => {
it('sorts based on type and prTitle', () => {
const branches = [
{
type: 'major',
prTitle: 'some major update',
},
{
type: 'pin',
prTitle: 'some pin',
},
{
type: 'pin',
prTitle: 'some other pin',
},
{
type: 'minor',
prTitle: 'a minor update',
},
];
sortBranches(branches);
expect(branches).toMatchSnapshot();
});
});
});

View file

@ -1,5 +1,7 @@
const { writeUpdates } = require('../../../lib/workers/repository/write'); const {
const branchWorker = require('../../../lib/workers/branch'); writeUpdates,
} = require('../../../../lib/workers/repository/process/write');
const branchWorker = require('../../../../lib/workers/branch');
const moment = require('moment'); const moment = require('moment');
branchWorker.processBranch = jest.fn(); branchWorker.processBranch = jest.fn();
@ -7,7 +9,7 @@ branchWorker.processBranch = jest.fn();
let config; let config;
beforeEach(() => { beforeEach(() => {
jest.resetAllMocks(); jest.resetAllMocks();
config = { ...require('../../_fixtures/config') }; config = { ...require('../../../_fixtures/config') };
}); });
describe('workers/repository/write', () => { describe('workers/repository/write', () => {