mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 10:09:50 +00:00
feat: Prune all orphan branches (#461)
Schedule logic has been refactored to enable the pruning of all orphan branches. Now, schedules aren't checked at package-time, instead package upgrades are queued regardless of schedule. At branch time, it is checked whether the *branch* is scheduled and then the branch is not created/updated if it's off-schedule. This enables the repository worker to know all possible branches and hence be able to determine which remaining branches in the repository are "orphans" to be deleted. Closes #428, Closes #426
This commit is contained in:
+13
-15
@@ -2,6 +2,7 @@ const handlebars = require('handlebars');
|
||||
const packageJsonHelper = require('./package-json');
|
||||
const npm = require('./npm');
|
||||
const yarn = require('./yarn');
|
||||
const schedule = require('./schedule');
|
||||
const prWorker = require('../pr');
|
||||
let logger = require('../../logger');
|
||||
|
||||
@@ -191,23 +192,22 @@ async function ensureBranch(config) {
|
||||
}
|
||||
|
||||
async function processBranchUpgrades(branchUpgrades, errors, warnings) {
|
||||
logger = branchUpgrades.logger || logger;
|
||||
logger.trace({ config: branchUpgrades }, 'processBranchUpgrades');
|
||||
let createdBranch;
|
||||
const config = Object.assign({}, branchUpgrades);
|
||||
// Delete the semanticPrefix for this branch if feature is not enabled
|
||||
if (config.semanticCommits) {
|
||||
logger.debug('Branch has semantic commits enabled');
|
||||
} else {
|
||||
logger.debug('Branch has semantic commits disabled');
|
||||
delete config.semanticPrefix;
|
||||
// Check schedule
|
||||
if (
|
||||
config.schedule &&
|
||||
config.schedule.length &&
|
||||
schedule.isScheduledNow(config) === false
|
||||
) {
|
||||
logger.info('Skipping branch as it is not scheduled');
|
||||
return;
|
||||
}
|
||||
// Use templates to generate strings
|
||||
const branchName = handlebars.compile(config.branchName)(config);
|
||||
const prTitle = handlebars.compile(config.prTitle)(config);
|
||||
|
||||
logger = logger.child({
|
||||
repository: config.repository,
|
||||
branch: branchName,
|
||||
branch: config.branchName,
|
||||
});
|
||||
config.logger = logger;
|
||||
|
||||
@@ -218,14 +218,13 @@ async function processBranchUpgrades(branchUpgrades, errors, warnings) {
|
||||
if (
|
||||
// Groups and lock file maintenance should set this to true
|
||||
config.recreateClosed === false &&
|
||||
(await config.api.checkForClosedPr(branchName, prTitle))
|
||||
(await config.api.checkForClosedPr(config.branchName, config.prTitle))
|
||||
) {
|
||||
logger.info(`Skipping branch as matching closed PR already existed`);
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
const branchCreated = await module.exports.ensureBranch(config);
|
||||
if (branchCreated) {
|
||||
createdBranch = branchName;
|
||||
const pr = await prWorker.ensurePr(
|
||||
config.upgrades,
|
||||
logger,
|
||||
@@ -241,5 +240,4 @@ async function processBranchUpgrades(branchUpgrades, errors, warnings) {
|
||||
logger.debug(JSON.stringify(err));
|
||||
// Don't throw here - we don't want to stop the other renovations
|
||||
}
|
||||
return createdBranch;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const path = require('path');
|
||||
const configParser = require('../../config');
|
||||
const depTypeWorker = require('../dep-type');
|
||||
const schedule = require('../package/schedule');
|
||||
|
||||
let logger = require('../../logger');
|
||||
|
||||
@@ -55,16 +55,22 @@ async function findUpgrades(packageFileConfig) {
|
||||
);
|
||||
}
|
||||
|
||||
// Maintain lock files
|
||||
const lockFileMaintenanceConf = Object.assign(
|
||||
{},
|
||||
config,
|
||||
config.lockFileMaintenance
|
||||
// Detect if a yarn.lock file is in use
|
||||
const yarnLockFileName = path.join(
|
||||
path.dirname(config.packageFile),
|
||||
'yarn.lock'
|
||||
);
|
||||
if (lockFileMaintenanceConf.enabled) {
|
||||
logger.debug('lockFileMaintenance enabled');
|
||||
lockFileMaintenanceConf.type = 'lockFileMaintenance';
|
||||
if (schedule.isScheduledNow(lockFileMaintenanceConf)) {
|
||||
if (await config.api.getFileContent(yarnLockFileName)) {
|
||||
config.hasYarnLock = true;
|
||||
// Maintain lock files
|
||||
const lockFileMaintenanceConf = Object.assign(
|
||||
{},
|
||||
config,
|
||||
config.lockFileMaintenance
|
||||
);
|
||||
if (lockFileMaintenanceConf.enabled) {
|
||||
logger.debug('lockFileMaintenance enabled');
|
||||
lockFileMaintenanceConf.type = 'lockFileMaintenance';
|
||||
logger.debug(`lock config=${JSON.stringify(lockFileMaintenanceConf)}`);
|
||||
upgrades.push(lockFileMaintenanceConf);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const npmApi = require('../../api/npm');
|
||||
const versions = require('./versions');
|
||||
const schedule = require('./schedule');
|
||||
const configParser = require('../../config');
|
||||
|
||||
let logger = require('../../logger');
|
||||
@@ -16,16 +15,6 @@ async function findUpgrades(config) {
|
||||
logger.debug('package is disabled');
|
||||
return [];
|
||||
}
|
||||
// Check schedule
|
||||
if (
|
||||
config.repoIsOnboarded &&
|
||||
config.schedule &&
|
||||
config.schedule.length &&
|
||||
schedule.isScheduledNow(config) === false
|
||||
) {
|
||||
logger.debug('Skipping package as it is not scheduled');
|
||||
return [];
|
||||
}
|
||||
let results = [];
|
||||
const npmDep = await npmApi.getDependency(config.depName, logger);
|
||||
if (npmDep) {
|
||||
|
||||
@@ -2,64 +2,29 @@ module.exports = {
|
||||
pruneStaleBranches,
|
||||
};
|
||||
|
||||
async function pruneStaleBranches(config, branchUpgradeNames) {
|
||||
async function pruneStaleBranches(config, branchList) {
|
||||
const logger = config.logger;
|
||||
logger.debug('Removing any stale branches');
|
||||
logger.trace(
|
||||
{ config },
|
||||
`pruneStaleBranches:\n${JSON.stringify(branchUpgradeNames)}`
|
||||
`pruneStaleBranches:\n${JSON.stringify(branchList)}`
|
||||
);
|
||||
if (config.platform !== 'github') {
|
||||
logger.debug('Platform is not GitHub - returning');
|
||||
return;
|
||||
}
|
||||
if (branchUpgradeNames.length === 0) {
|
||||
logger.debug('No branchUpgradeNames - returning');
|
||||
return;
|
||||
}
|
||||
const renovateBranches = await config.api.getAllRenovateBranches();
|
||||
logger.debug(`renovateBranches=${renovateBranches}`);
|
||||
const remainingBranches = renovateBranches.filter(
|
||||
branch => branchUpgradeNames.indexOf(branch) === -1
|
||||
branch => branchList.indexOf(branch) === -1
|
||||
);
|
||||
logger.debug(`remainingBranches=${remainingBranches}`);
|
||||
if (remainingBranches.length === 0) {
|
||||
logger.debug('No branches to clean up');
|
||||
return;
|
||||
}
|
||||
const allPrs = await config.api.getAllPrs();
|
||||
for (const branchName of remainingBranches) {
|
||||
logger.debug({ branch: branchName }, `Checking orphan branch for deletion`);
|
||||
// Default to deleting the branch if we don't find a PR
|
||||
let deleteBranch = true;
|
||||
let foundPr = false;
|
||||
for (const pr of allPrs) {
|
||||
if (pr.state === 'open' && pr.branchName === branchName) {
|
||||
// We have a matching PR
|
||||
foundPr = true;
|
||||
logger.debug({ branch: branchName }, `Found matching PR#${pr.number}`);
|
||||
const prDetails = config.api.getPr(pr.number);
|
||||
if (prDetails.mergeable) {
|
||||
// Don't delete the branch if we found a mergeable PR
|
||||
logger.debug(
|
||||
{ branch: branchName },
|
||||
'PR is mergeable, so do not delete'
|
||||
);
|
||||
deleteBranch = false;
|
||||
} else {
|
||||
logger.debug(
|
||||
{ branch: branchName },
|
||||
'PR is not mergeable, we will delete'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (deleteBranch) {
|
||||
if (!foundPr) {
|
||||
logger.debug({ branch: branchName }, 'Orphan branch has no PR');
|
||||
}
|
||||
logger.info({ branch: branchName }, `Deleting orphan branch`);
|
||||
await config.api.deleteBranch(branchName);
|
||||
}
|
||||
logger.debug({ branch: branchName }, `Deleting orphan branch`);
|
||||
await config.api.deleteBranch(branchName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,17 +78,15 @@ async function renovateRepository(packageFileConfig) {
|
||||
config.logger.debug(`Updating ${branchUpgrades.length} branch(es)`);
|
||||
config.logger.trace({ config: branchUpgrades }, 'branchUpgrades');
|
||||
if (config.repoIsOnboarded) {
|
||||
const branchList = [];
|
||||
for (const branchUpgrade of branchUpgrades) {
|
||||
const createdBranchName = await branchWorker.processBranchUpgrades(
|
||||
await branchWorker.processBranchUpgrades(
|
||||
branchUpgrade,
|
||||
config.errors,
|
||||
config.warnings
|
||||
);
|
||||
if (createdBranchName) {
|
||||
branchList.push(createdBranchName);
|
||||
}
|
||||
}
|
||||
const branchList = branchUpgrades.map(upgrade => upgrade.branchName);
|
||||
config.logger.debug(`branchList=${branchList}`);
|
||||
await cleanup.pruneStaleBranches(config, branchList);
|
||||
} else {
|
||||
await onboarding.ensurePr(config, branchUpgrades);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
const handlebars = require('handlebars');
|
||||
const stringify = require('json-stringify-pretty-compact');
|
||||
|
||||
const configParser = require('../../config');
|
||||
@@ -95,21 +94,24 @@ With your current configuration, renovate will initially create the following Pu
|
||||
| ------ |
|
||||
`;
|
||||
branchUpgrades.forEach(branch => {
|
||||
const branchName = handlebars.compile(branch.branchName)(branch);
|
||||
const prTitle = handlebars.compile(branch.prTitle)(branch);
|
||||
prDesc += `| **${prTitle}**<ul>`;
|
||||
prDesc += `| **${branch.prTitle}**<ul>`;
|
||||
if (branch.schedule && branch.schedule.length) {
|
||||
prDesc += `<li>Schedule: ${JSON.stringify(branch.schedule)}</li>`;
|
||||
}
|
||||
prDesc += `<li>Branch name: \`${branchName}\`</li>`;
|
||||
prDesc += `<li>Branch name: \`${branch.branchName}\`</li>`;
|
||||
branch.upgrades.forEach(upgrade => {
|
||||
if (upgrade.isPin) {
|
||||
prDesc += '<li>Pins ';
|
||||
if (upgrade.type === 'lockFileMaintenance') {
|
||||
prDesc +=
|
||||
'<li>Regenerates `yarn.lock` file to use latest dependency versions</li>';
|
||||
} else {
|
||||
prDesc += '<li>Upgrades ';
|
||||
if (upgrade.isPin) {
|
||||
prDesc += '<li>Pins ';
|
||||
} else {
|
||||
prDesc += '<li>Upgrades ';
|
||||
}
|
||||
prDesc += `[${upgrade.depName}](${upgrade.repositoryUrl}) in \`${upgrade.depType}\` from \`${upgrade.currentVersion}\` to \`${upgrade.newVersion}\``;
|
||||
prDesc += '</li>';
|
||||
}
|
||||
prDesc += `[${upgrade.depName}](${upgrade.repositoryUrl}) in \`${upgrade.depType}\` from \`${upgrade.currentVersion}\` to \`${upgrade.newVersion}\``;
|
||||
prDesc += '</li>';
|
||||
});
|
||||
prDesc += '</ul> |\n';
|
||||
});
|
||||
|
||||
@@ -54,6 +54,18 @@ function generateConfig(branchUpgrades) {
|
||||
// Delete group config regardless of whether it was applied
|
||||
delete upgrade.group;
|
||||
delete upgrade.lazyGrouping;
|
||||
// Delete the semanticPrefix for this upgrade if not enabled
|
||||
if (upgrade.semanticCommits) {
|
||||
logger.debug('Upgrade has semantic commits enabled');
|
||||
} else {
|
||||
logger.debug('Upgrade has semantic commits disabled');
|
||||
delete upgrade.semanticPrefix;
|
||||
}
|
||||
// Use templates to generate strings
|
||||
logger.debug('Compiling branchName and prTitle');
|
||||
upgrade.branchName = handlebars.compile(upgrade.branchName)(upgrade);
|
||||
upgrade.prTitle = handlebars.compile(upgrade.prTitle)(upgrade);
|
||||
logger.debug(`${upgrade.branchName}, ${upgrade.prTitle}`);
|
||||
config.upgrades.push(upgrade);
|
||||
}
|
||||
// Now assign first upgrade's config as branch config
|
||||
@@ -61,7 +73,7 @@ function generateConfig(branchUpgrades) {
|
||||
}
|
||||
|
||||
function groupByBranch(upgrades) {
|
||||
logger.trace({ config: upgrades }, 'groupUpgrades');
|
||||
logger.trace({ config: upgrades }, 'groupByBranch');
|
||||
logger.info(`Processing ${upgrades.length} dependency upgrade(s)`);
|
||||
const result = {
|
||||
errors: [],
|
||||
@@ -115,6 +127,7 @@ async function branchifyUpgrades(upgrades, parentLogger) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const branchWorker = require('../../../lib/workers/branch');
|
||||
const prWorker = require('../../../lib/workers/pr');
|
||||
const schedule = require('../../../lib/workers/branch/schedule');
|
||||
const npm = require('../../../lib/workers/branch/npm');
|
||||
const yarn = require('../../../lib/workers/branch/yarn');
|
||||
const defaultConfig = require('../../../lib/config/defaults').getConfig();
|
||||
@@ -15,6 +16,7 @@ describe('workers/branch', () => {
|
||||
let config;
|
||||
const branchName = 'foo';
|
||||
beforeEach(() => {
|
||||
schedule.isScheduledNow = jest.fn();
|
||||
config = {
|
||||
api: {
|
||||
branchExists: jest.fn(() => true),
|
||||
@@ -333,6 +335,12 @@ describe('workers/branch', () => {
|
||||
prWorker.ensurePr = jest.fn(() => true);
|
||||
config.upgrades = [{ depName: 'a' }];
|
||||
});
|
||||
it('skips branch if not scheduled', async () => {
|
||||
config.schedule = ['some-schedule'];
|
||||
schedule.isScheduledNow.mockReturnValueOnce(false);
|
||||
await branchWorker.processBranchUpgrades(config);
|
||||
expect(branchWorker.ensureBranch.mock.calls.length).toBe(0);
|
||||
});
|
||||
it('returns immediately if closed PR found', async () => {
|
||||
config.api.checkForClosedPr.mockReturnValue(true);
|
||||
await branchWorker.processBranchUpgrades(config);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const mockDate = require('mockdate');
|
||||
const schedule = require('../../../lib/workers/package/schedule');
|
||||
const schedule = require('../../../lib/workers/branch/schedule');
|
||||
const logger = require('../../_fixtures/logger');
|
||||
|
||||
describe('workers/package/schedule', () => {
|
||||
describe('workers/branch/schedule', () => {
|
||||
describe('hasValidSchedule(schedule)', () => {
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks();
|
||||
@@ -1,20 +1,21 @@
|
||||
const packageFileWorker = require('../../../lib/workers/package-file');
|
||||
const depTypeWorker = require('../../../lib/workers/dep-type');
|
||||
const schedule = require('../../../lib/workers/package/schedule');
|
||||
const defaultConfig = require('../../../lib/config/defaults').getConfig();
|
||||
|
||||
const logger = require('../../_fixtures/logger');
|
||||
|
||||
jest.mock('../../../lib/workers/dep-type');
|
||||
jest.mock('../../../lib/workers/package/schedule');
|
||||
jest.mock('../../../lib/workers/branch/schedule');
|
||||
|
||||
describe('packageFileWorker', () => {
|
||||
describe('findUpgrades(config)', () => {
|
||||
let config;
|
||||
beforeEach(() => {
|
||||
config = Object.assign({}, defaultConfig, {
|
||||
packageFile: 'package.json',
|
||||
repoIsOnboarded: true,
|
||||
api: {
|
||||
getFileContent: jest.fn(),
|
||||
getFileJson: jest.fn(),
|
||||
},
|
||||
depTypes: ['dependencies', 'devDependencies'],
|
||||
@@ -62,17 +63,11 @@ describe('packageFileWorker', () => {
|
||||
});
|
||||
it('maintains yarn.lock', async () => {
|
||||
config.api.getFileJson.mockReturnValueOnce({});
|
||||
depTypeWorker.findUpgrades.mockReturnValue([]);
|
||||
schedule.isScheduledNow.mockReturnValueOnce(true);
|
||||
config.api.getFileContent.mockReturnValueOnce('some-content');
|
||||
depTypeWorker.findUpgrades.mockReturnValueOnce([]);
|
||||
depTypeWorker.findUpgrades.mockReturnValueOnce([]);
|
||||
const res = await packageFileWorker.findUpgrades(config);
|
||||
expect(res).toHaveLength(1);
|
||||
});
|
||||
it('skips yarn.lock', async () => {
|
||||
config.api.getFileJson.mockReturnValueOnce({});
|
||||
depTypeWorker.findUpgrades.mockReturnValue([]);
|
||||
schedule.isScheduledNow.mockReturnValueOnce(false);
|
||||
const res = await packageFileWorker.findUpgrades(config);
|
||||
expect(res).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
const npmApi = require('../../../lib/api/npm');
|
||||
const schedule = require('../../../lib/workers/package/schedule');
|
||||
const versions = require('../../../lib/workers/package/versions');
|
||||
const pkgWorker = require('../../../lib/workers/package/index');
|
||||
const defaultConfig = require('../../../lib/config/defaults').getConfig();
|
||||
const configParser = require('../../../lib/config');
|
||||
|
||||
jest.mock('../../../lib/workers/package/schedule');
|
||||
jest.mock('../../../lib/workers/branch/schedule');
|
||||
jest.mock('../../../lib/workers/package/versions');
|
||||
jest.mock('../../../lib/api/npm');
|
||||
|
||||
@@ -21,18 +20,9 @@ describe('lib/workers/package/index', () => {
|
||||
const res = await pkgWorker.findUpgrades(config);
|
||||
expect(res).toMatchObject([]);
|
||||
});
|
||||
it('returns empty if package is not scheduled', async () => {
|
||||
config.repoIsOnboarded = true;
|
||||
config.schedule = 'some schedule';
|
||||
schedule.isScheduledNow.mockReturnValueOnce(false);
|
||||
const res = await pkgWorker.findUpgrades(config);
|
||||
expect(res).toMatchObject([]);
|
||||
expect(npmApi.getDependency.mock.calls.length).toBe(0);
|
||||
});
|
||||
it('returns error if no npm dep found', async () => {
|
||||
config.repoIsOnboarded = true;
|
||||
config.schedule = 'some schedule';
|
||||
schedule.isScheduledNow.mockReturnValueOnce(true);
|
||||
const res = await pkgWorker.findUpgrades(config);
|
||||
expect(res).toHaveLength(1);
|
||||
expect(res[0].type).toEqual('error');
|
||||
|
||||
@@ -149,6 +149,44 @@ With your current configuration, renovate will initially create the following Pu
|
||||
| **Pin a**<ul><li>Branch name: \`branch-a\`</li><li>Pins [a](https://a) in \`undefined\` from \`^1.0.0\` to \`1.1.0\`</li><li>Upgrades [b](https://b) in \`undefined\` from \`1.0.0\` to \`2.0.0\`</li></ul> |
|
||||
|
||||
|
||||
Would you like to change this? Simply edit the \`renovate.json\` in this branch and Renovate will update this Pull Request description the next time it runs.
|
||||
|
||||
The [Configuration](https://github.com/singapore/renovate/blob/master/docs/configuration.md) and [Configuration FAQ](https://github.com/singapore/renovate/blob/master/docs/faq.md) documents should be helpful if you wish to modify this behaviour.
|
||||
|
||||
---
|
||||
|
||||
#### Important!
|
||||
|
||||
You do not need to *merge* this Pull Request - renovate will begin even if it's closed *unmerged*.
|
||||
In fact, you only need to add a \`renovate.json\` file to your repository if you wish to override any default settings. The file is included as part of this PR only in case you wish to change default settings before you start.
|
||||
|
||||
Alternatively, you can add the same configuration settings into a \\"renovate\\" section of \`package.json\`, which might be more convenient if you have only one.
|
||||
|
||||
If the default settings are all suitable for you, simply close this Pull Request unmerged and your first renovation will begin the next time the program is run.
|
||||
",
|
||||
],
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`lib/workers/repository/onboarding ensurePr(config, branchUpgrades) maintains yarn.lock 1`] = `
|
||||
Array [
|
||||
Array [
|
||||
"renovate/configure",
|
||||
"Configure Renovate",
|
||||
"Welcome to [Renovate](https://keylocation.sg/our-tech/renovate)!
|
||||
|
||||
This is an onboarding PR to help you understand and configure Renovate before any changes are made to any \`package.json\` files. Once you close this Pull Request, we will begin keeping your dependencies up-to-date via automated Pull Requests.
|
||||
|
||||
---
|
||||
|
||||
|
||||
With your current configuration, renovate will initially create the following Pull Requests:
|
||||
|
||||
| Pull Requests (1) |
|
||||
| ------ |
|
||||
| **Lock File Maintenance**<ul><li>Schedule: \\"before 5am on monday\\"</li><li>Branch name: \`renovate/lock-files\`</li><li>Regenerates \`yarn.lock\` file to use latest dependency versions</li></ul> |
|
||||
|
||||
|
||||
Would you like to change this? Simply edit the \`renovate.json\` in this branch and Renovate will update this Pull Request description the next time it runs.
|
||||
|
||||
The [Configuration](https://github.com/singapore/renovate/blob/master/docs/configuration.md) and [Configuration FAQ](https://github.com/singapore/renovate/blob/master/docs/faq.md) documents should be helpful if you wish to modify this behaviour.
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
|
||||
exports[`workers/repository/upgrades generateConfig(branchUpgrades) does not group single upgrade 1`] = `
|
||||
Object {
|
||||
"branchName": "some-branch",
|
||||
"depName": "some-dep",
|
||||
"foo": 1,
|
||||
"prTitle": "some-title",
|
||||
"semanticCommits": true,
|
||||
"upgrades": Array [
|
||||
Object {
|
||||
"branchName": "some-branch",
|
||||
"depName": "some-dep",
|
||||
"foo": 1,
|
||||
"prTitle": "some-title",
|
||||
"semanticCommits": true,
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -15,14 +21,18 @@ Object {
|
||||
|
||||
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",
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -34,18 +44,21 @@ 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",
|
||||
},
|
||||
],
|
||||
"foo-2.0.0": Array [
|
||||
Object {
|
||||
"branchName": "foo-{{version}}",
|
||||
"prTitle": "some-title",
|
||||
"version": "2.0.0",
|
||||
},
|
||||
],
|
||||
@@ -61,16 +74,19 @@ Object {
|
||||
"bar-1.1.0": Array [
|
||||
Object {
|
||||
"branchName": "bar-{{version}}",
|
||||
"prTitle": "some-title",
|
||||
"version": "1.1.0",
|
||||
},
|
||||
],
|
||||
"foo": Array [
|
||||
Object {
|
||||
"branchName": "foo",
|
||||
"prTitle": "some-title",
|
||||
"version": "2.0.0",
|
||||
},
|
||||
Object {
|
||||
"branchName": "foo",
|
||||
"prTitle": "some-title",
|
||||
"version": "1.1.0",
|
||||
},
|
||||
],
|
||||
@@ -86,6 +102,7 @@ Object {
|
||||
"foo": Array [
|
||||
Object {
|
||||
"branchName": "foo",
|
||||
"prTitle": "some-title",
|
||||
"version": "2.0.0",
|
||||
},
|
||||
],
|
||||
@@ -97,6 +114,7 @@ Object {
|
||||
},
|
||||
"groupName": "My Group",
|
||||
"groupSlug": "my-group",
|
||||
"prTitle": "some-title",
|
||||
"version": "1.1.0",
|
||||
},
|
||||
Object {
|
||||
@@ -106,6 +124,7 @@ Object {
|
||||
},
|
||||
"groupName": "My Group",
|
||||
"groupSlug": "my-group",
|
||||
"prTitle": "some-title",
|
||||
"version": "1.1.0",
|
||||
},
|
||||
],
|
||||
@@ -121,12 +140,14 @@ 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",
|
||||
},
|
||||
],
|
||||
@@ -139,6 +160,7 @@ Object {
|
||||
"warnings": Array [
|
||||
Object {
|
||||
"branchName": "foo-{{version}}",
|
||||
"prTitle": "some-title",
|
||||
"type": "warning",
|
||||
"version": "2.0.0",
|
||||
},
|
||||
@@ -160,6 +182,7 @@ Object {
|
||||
"foo-1.1.0": Array [
|
||||
Object {
|
||||
"branchName": "foo-{{version}}",
|
||||
"prTitle": "some-title",
|
||||
"version": "1.1.0",
|
||||
},
|
||||
],
|
||||
@@ -171,19 +194,25 @@ Object {
|
||||
|
||||
exports[`workers/repository/upgrades 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",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -22,10 +22,6 @@ describe('workers/repository/cleanup', () => {
|
||||
await cleanup.pruneStaleBranches(config, branchNames);
|
||||
expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(0);
|
||||
});
|
||||
it('returns if no branch names', async () => {
|
||||
await cleanup.pruneStaleBranches(config, branchNames);
|
||||
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);
|
||||
@@ -33,52 +29,13 @@ describe('workers/repository/cleanup', () => {
|
||||
expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getAllPrs.mock.calls).toHaveLength(0);
|
||||
});
|
||||
it('returns if remaining branch has mergeable PR', async () => {
|
||||
it('deletes remaining branch', async () => {
|
||||
branchNames = ['renovate/a', 'renovate/b'];
|
||||
config.api.getAllRenovateBranches.mockReturnValueOnce(
|
||||
branchNames.concat(['renovate/c'])
|
||||
);
|
||||
config.api.getAllPrs.mockReturnValueOnce([
|
||||
{ number: 4, state: 'open', branchName: 'test-a' },
|
||||
{ number: 5, state: 'open', branchName: 'renovate/c' },
|
||||
]);
|
||||
config.api.getPr.mockReturnValueOnce({ mergeable: true });
|
||||
await cleanup.pruneStaleBranches(config, branchNames);
|
||||
expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getAllPrs.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getPr.mock.calls).toHaveLength(1);
|
||||
expect(config.api.deleteBranch.mock.calls).toHaveLength(0);
|
||||
});
|
||||
it('deletes if remaining branch has non-mergeable PR', async () => {
|
||||
branchNames = ['renovate/a', 'renovate/b'];
|
||||
config.api.getAllRenovateBranches.mockReturnValueOnce(
|
||||
branchNames.concat(['renovate/c'])
|
||||
);
|
||||
config.api.getAllPrs.mockReturnValueOnce([
|
||||
{ number: 4, state: 'open', branchName: 'test-a' },
|
||||
{ number: 5, state: 'open', branchName: 'renovate/c' },
|
||||
]);
|
||||
config.api.getPr.mockReturnValueOnce({ mergeable: false });
|
||||
await cleanup.pruneStaleBranches(config, branchNames);
|
||||
expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getAllPrs.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getPr.mock.calls).toHaveLength(1);
|
||||
expect(config.api.deleteBranch.mock.calls).toHaveLength(1);
|
||||
});
|
||||
it('deletes if no matching PR', async () => {
|
||||
branchNames = ['renovate/a', 'renovate/b'];
|
||||
config.api.getAllRenovateBranches.mockReturnValueOnce(
|
||||
branchNames.concat(['renovate/c'])
|
||||
);
|
||||
config.api.getAllPrs.mockReturnValueOnce([
|
||||
{ number: 4, state: 'open', branchName: 'test-a' },
|
||||
{ number: 5, state: 'open', branchName: 'renovate/a' },
|
||||
]);
|
||||
config.api.getPr.mockReturnValueOnce({ mergeable: false });
|
||||
await cleanup.pruneStaleBranches(config, branchNames);
|
||||
expect(config.api.getAllRenovateBranches.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getAllPrs.mock.calls).toHaveLength(1);
|
||||
expect(config.api.getPr.mock.calls).toHaveLength(0);
|
||||
expect(config.api.deleteBranch.mock.calls).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -98,6 +98,24 @@ If the default settings are all suitable for you, simply close this Pull Request
|
||||
expect(config.api.updatePr.mock.calls.length).toBe(0);
|
||||
expect(config.api.createPr.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
it('maintains yarn.lock', async () => {
|
||||
branchUpgrades = [
|
||||
{
|
||||
branchName: 'renovate/lock-files',
|
||||
prTitle: 'Lock File Maintenance',
|
||||
schedule: 'before 5am on monday',
|
||||
upgrades: [
|
||||
{
|
||||
type: 'lockFileMaintenance',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
await onboarding.ensurePr(config, branchUpgrades);
|
||||
expect(config.api.createPr.mock.calls.length).toBe(1);
|
||||
expect(config.api.updatePr.mock.calls.length).toBe(0);
|
||||
expect(config.api.createPr.mock.calls).toMatchSnapshot();
|
||||
});
|
||||
it('handles groups', async () => {
|
||||
branchUpgrades = [
|
||||
{
|
||||
|
||||
@@ -50,6 +50,9 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
depName: 'some-dep',
|
||||
groupName: 'some-group',
|
||||
branchName: 'some-branch',
|
||||
prTitle: 'some-title',
|
||||
semanticCommits: true,
|
||||
lazyGrouping: true,
|
||||
foo: 1,
|
||||
group: {
|
||||
@@ -67,6 +70,8 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
depName: 'some-dep',
|
||||
groupName: 'some-group',
|
||||
branchName: 'some-branch',
|
||||
prTitle: 'some-title',
|
||||
lazyGrouping: false,
|
||||
foo: 1,
|
||||
group: {
|
||||
@@ -85,6 +90,8 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
depName: 'some-dep',
|
||||
groupName: 'some-group',
|
||||
branchName: 'some-branch',
|
||||
prTitle: 'some-title',
|
||||
lazyGrouping: true,
|
||||
foo: 1,
|
||||
group: {
|
||||
@@ -94,6 +101,8 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
depName: 'some-other-dep',
|
||||
groupName: 'some-group',
|
||||
branchName: 'some-branch',
|
||||
prTitle: 'some-title',
|
||||
lazyGrouping: true,
|
||||
foo: 1,
|
||||
group: {
|
||||
@@ -116,6 +125,7 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
branchName: 'foo-{{version}}',
|
||||
version: '1.1.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
];
|
||||
const res = await upgrades.groupByBranch(input);
|
||||
@@ -127,14 +137,17 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
branchName: 'foo-{{version}}',
|
||||
version: '1.1.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
{
|
||||
branchName: 'foo-{{version}}',
|
||||
version: '2.0.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
{
|
||||
branchName: 'bar-{{version}}',
|
||||
version: '1.1.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
];
|
||||
const res = await upgrades.groupByBranch(input);
|
||||
@@ -146,14 +159,17 @@ describe('workers/repository/upgrades', () => {
|
||||
{
|
||||
branchName: 'foo',
|
||||
version: '1.1.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
{
|
||||
branchName: 'foo',
|
||||
version: '2.0.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
{
|
||||
branchName: 'bar-{{version}}',
|
||||
version: '1.1.0',
|
||||
prTitle: 'some-title',
|
||||
},
|
||||
];
|
||||
const res = await upgrades.groupByBranch(input);
|
||||
@@ -164,16 +180,19 @@ describe('workers/repository/upgrades', () => {
|
||||
const input = [
|
||||
{
|
||||
branchName: 'foo',
|
||||
prTitle: 'some-title',
|
||||
version: '1.1.0',
|
||||
groupName: 'My Group',
|
||||
group: { branchName: 'renovate/{{groupSlug}}' },
|
||||
},
|
||||
{
|
||||
branchName: 'foo',
|
||||
prTitle: 'some-title',
|
||||
version: '2.0.0',
|
||||
},
|
||||
{
|
||||
branchName: 'bar-{{version}}',
|
||||
prTitle: 'some-title',
|
||||
version: '1.1.0',
|
||||
groupName: 'My Group',
|
||||
group: { branchName: 'renovate/my-group' },
|
||||
@@ -190,15 +209,18 @@ describe('workers/repository/upgrades', () => {
|
||||
},
|
||||
{
|
||||
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',
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user