From ea4e370d3fff8f0fab0b40d1ef9ffa4cd4242467 Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@keylocation.sg> Date: Wed, 5 Jul 2017 11:57:22 +0200 Subject: [PATCH] feat: Prune stale branches (#441) A separate routine is run after branch creation to detect any branches that should be deleted. A branch will be removed if: - It was not created by renovate in the last run, AND - It has no PR, or its corresponding PR is not mergeable Closes #426, Closes #428 --- lib/api/github.js | 22 +++++ lib/workers/branch/index.js | 15 +--- lib/workers/package/versions.js | 1 + lib/workers/repository/cleanup.js | 65 ++++++++++++++ lib/workers/repository/index.js | 9 +- lib/workers/repository/onboarding.js | 13 +++ lib/workers/repository/upgrades.js | 2 +- test/api/__snapshots__/github.spec.js.snap | 24 ++++++ test/api/github.spec.js | 52 ++++++++++++ .../__snapshots__/versions.spec.js.snap | 12 +++ .../__snapshots__/onboarding.spec.js.snap | 40 ++++++++- test/workers/repository/cleanup.spec.js | 85 +++++++++++++++++++ test/workers/repository/index.spec.js | 2 +- test/workers/repository/onboarding.spec.js | 31 +++++++ 14 files changed, 358 insertions(+), 15 deletions(-) create mode 100644 lib/workers/repository/cleanup.js create mode 100644 test/workers/repository/cleanup.spec.js diff --git a/lib/api/github.js b/lib/api/github.js index 04528826b5..533c81f0da 100644 --- a/lib/api/github.js +++ b/lib/api/github.js @@ -15,6 +15,7 @@ module.exports = { findFilePaths, // Branch branchExists, + getAllRenovateBranches, isBranchStale, getBranchPr, getBranchStatus, @@ -29,6 +30,7 @@ module.exports = { checkForClosedPr, createPr, getPr, + getAllPrs, updatePr, mergePr, // file @@ -213,6 +215,18 @@ async function branchExists(branchName) { } } +async function getAllRenovateBranches() { + logger.trace('getAllRenovateBranches'); + const allBranches = (await ghGot(`repos/${config.repoName}/git/refs/heads`)) + .body; + return allBranches.reduce((arr, branch) => { + if (branch.ref.indexOf('refs/heads/renovate/') === 0) { + arr.push(branch.ref.substring('refs/heads/'.length)); + } + return arr; + }, []); +} + async function isBranchStale(branchName) { // Check if branch's parent SHA = master SHA logger.debug(`isBranchStale(${branchName})`); @@ -435,6 +449,14 @@ async function getPr(prNo) { return pr; } +async function getAllPrs() { + const all = (await ghGot(`repos/${config.repoName}/pulls?state=open`)).body; + return all.map(pr => ({ + number: pr.number, + branchName: pr.head.ref, + })); +} + async function updatePr(prNo, title, body) { await ghGot.patch(`repos/${config.repoName}/pulls/${prNo}`, { body: { title, body }, diff --git a/lib/workers/branch/index.js b/lib/workers/branch/index.js index 7cb5cf2f4f..5a8384ed9b 100644 --- a/lib/workers/branch/index.js +++ b/lib/workers/branch/index.js @@ -206,16 +206,6 @@ async function generateConfig(branchUpgrades) { for (const branchUpgrade of branchUpgrades) { const upgrade = Object.assign({}, branchUpgrade); if (useGroupSettings) { - // Try deleting the upgrade's non-group branch name in case it exists from previous run - const singleName = handlebars.compile(upgrade.branchName)(upgrade); - upgrade.logger.debug( - `Try to delete upgrade's non-group branch ${singleName}` - ); - try { - await upgrade.api.deleteBranch(singleName); - } catch (err) { - upgrade.logger.debug(`Couldn't delete branch ${singleName}`); - } // Now overwrite original config with group config Object.assign(upgrade, upgrade.group); } @@ -229,6 +219,7 @@ async function generateConfig(branchUpgrades) { async function processBranchUpgrades(branchUpgrades, errors, warnings) { logger.trace({ config: branchUpgrades }, 'processBranchUpgrades'); + let createdBranch; const config = await module.exports.generateConfig(branchUpgrades); logger.trace({ config }, 'generateConfig'); // Delete the semanticPrefix for this branch if feature is not enabled @@ -258,10 +249,11 @@ async function processBranchUpgrades(branchUpgrades, errors, warnings) { (await config.api.checkForClosedPr(branchName, prTitle)) ) { logger.info(`Skipping branch as matching closed PR already existed`); - return; + return null; } const branchCreated = await module.exports.ensureBranch(config); if (branchCreated) { + createdBranch = branchName; const pr = await prWorker.ensurePr( config.upgrades, logger, @@ -277,4 +269,5 @@ 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; } diff --git a/lib/workers/package/versions.js b/lib/workers/package/versions.js index 4bb2d7ed7f..429e56cab2 100644 --- a/lib/workers/package/versions.js +++ b/lib/workers/package/versions.js @@ -45,6 +45,7 @@ function determineUpgrades(npmDep, config) { groupName: 'Pin Dependencies', group: { prTitle: '{{groupName}}', + semanticPrefix: 'refactor: ', }, }; changeLogFromVersion = maxSatisfying; diff --git a/lib/workers/repository/cleanup.js b/lib/workers/repository/cleanup.js new file mode 100644 index 0000000000..bd78486b4e --- /dev/null +++ b/lib/workers/repository/cleanup.js @@ -0,0 +1,65 @@ +module.exports = { + pruneStaleBranches, +}; + +async function pruneStaleBranches(config, branchUpgradeNames) { + const logger = config.logger; + logger.debug('Removing any stale branches'); + logger.trace( + { config }, + `pruneStaleBranches:\n${JSON.stringify(branchUpgradeNames)}` + ); + 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 + ); + 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); + } + } +} diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js index bc05c60b71..82f738cbf2 100644 --- a/lib/workers/repository/index.js +++ b/lib/workers/repository/index.js @@ -4,6 +4,7 @@ const branchWorker = require('../branch'); const apis = require('./apis'); const onboarding = require('./onboarding'); const upgrades = require('./upgrades'); +const cleanup = require('./cleanup'); module.exports = { renovateRepository, @@ -52,14 +53,20 @@ async function renovateRepository(packageFileConfig) { config.logger.debug( `Updating ${Object.keys(branchUpgrades).length} branch(es)` ); + config.logger.trace({ config: branchUpgrades }, 'branchUpgrades'); if (config.repoIsOnboarded) { + const branchList = []; for (const branchName of Object.keys(branchUpgrades)) { - await branchWorker.processBranchUpgrades( + const createdBranchName = await branchWorker.processBranchUpgrades( branchUpgrades[branchName], config.errors, config.warnings ); + if (createdBranchName) { + branchList.push(createdBranchName); + } } + await cleanup.pruneStaleBranches(config, branchList); } else { await onboarding.ensurePr(config, branchUpgrades); config.logger.info('"Configure Renovate" PR needs to be closed first'); diff --git a/lib/workers/repository/onboarding.js b/lib/workers/repository/onboarding.js index 2083da6d94..1ae2bf9f13 100644 --- a/lib/workers/repository/onboarding.js +++ b/lib/workers/repository/onboarding.js @@ -88,8 +88,21 @@ With your current configuration, renovate will initially create the following Pu onboardBranchNames.forEach(branchName => { const upgrades = branchUpgrades[branchName]; const upgrade0 = upgrades[0]; + if (!upgrade0.lazyGrouping || (upgrade0.groupName && upgrades.length > 1)) { + Object.assign(upgrade0, upgrade0.group); + } + // Delete the semanticPrefix for this branch if feature is not enabled + if (upgrade0.semanticCommits) { + config.logger.debug('Branch has semantic commits enabled'); + } else { + config.logger.debug('Branch has semantic commits disabled'); + delete upgrade0.semanticPrefix; + } const prTitle = handlebars.compile(upgrade0.prTitle)(upgrade0); prDesc += `| **${prTitle}**<ul>`; + if (upgrade0.schedule && upgrade0.schedule.length) { + prDesc += `<li>Schedule: ${JSON.stringify(upgrade0.schedule)}</li>`; + } prDesc += `<li>Branch name: \`${branchName}\`</li>`; upgrades.forEach(upgrade => { if (upgrade.isPin) { diff --git a/lib/workers/repository/upgrades.js b/lib/workers/repository/upgrades.js index 38e4261f54..25b35cc3d8 100644 --- a/lib/workers/repository/upgrades.js +++ b/lib/workers/repository/upgrades.js @@ -48,7 +48,7 @@ async function branchifyUpgrades(upgrades, logger) { if (upgrade.groupName) { // if groupName is defined then use group branchName template for combining logger.debug( - { branchName }, + { branch: branchName }, `Dependency ${upgrade.depName} is part of group '${upgrade.groupName}'` ); upgrade.groupSlug = diff --git a/test/api/__snapshots__/github.spec.js.snap b/test/api/__snapshots__/github.spec.js.snap index 00c4200ef8..5347657789 100644 --- a/test/api/__snapshots__/github.spec.js.snap +++ b/test/api/__snapshots__/github.spec.js.snap @@ -413,6 +413,30 @@ Object { } `; +exports[`api/github getAllPrs() maps results to simple array 1`] = ` +Array [ + Object { + "branchName": "renovate/a", + "number": 5, + }, + Object { + "branchName": "not-renovate", + "number": 6, + }, + Object { + "branchName": "renovate/b", + "number": 9, + }, +] +`; + +exports[`api/github getAllRenovateBranches() should return all renovate branches 1`] = ` +Array [ + "renovate/a", + "renovate/b", +] +`; + exports[`api/github getBranchPr(branchName) should return null if no PR exists 1`] = ` Array [ Array [ diff --git a/test/api/github.spec.js b/test/api/github.spec.js index 02b8db1c06..7c59e8722c 100644 --- a/test/api/github.spec.js +++ b/test/api/github.spec.js @@ -423,6 +423,26 @@ describe('api/github', () => { expect(err.message).toBe('Something went wrong'); }); }); + describe('getAllRenovateBranches()', () => { + it('should return all renovate branches', async () => { + await initRepo('some/repo', 'token'); + ghGot.mockImplementationOnce(() => ({ + body: [ + { + ref: 'refs/heads/renovate/a', + }, + { + ref: 'refs/heads/master', + }, + { + ref: 'refs/heads/renovate/b', + }, + ], + })); + const res = await github.getAllRenovateBranches(); + expect(res).toMatchSnapshot(); + }); + }); describe('isBranchStale(branchName)', () => { it('should return false if same SHA as master', async () => { await initRepo('some/repo', 'token'); @@ -813,6 +833,38 @@ describe('api/github', () => { expect(pr).toMatchSnapshot(); }); }); + describe('getAllPrs()', () => { + it('maps results to simple array', async () => { + await initRepo('some/repo', 'token'); + ghGot.mockImplementationOnce(() => ({ + body: [ + { + number: 5, + foo: 'bar', + head: { + ref: 'renovate/a', + }, + }, + { + number: 6, + foo: 'bar', + head: { + ref: 'not-renovate', + }, + }, + { + number: 9, + foo: 'baz', + head: { + ref: 'renovate/b', + }, + }, + ], + })); + const res = await github.getAllPrs(); + expect(res).toMatchSnapshot(); + }); + }); describe('updatePr(prNo, title, body)', () => { it('should update the PR', async () => { await initRepo('some/repo', 'token'); diff --git a/test/workers/package/__snapshots__/versions.spec.js.snap b/test/workers/package/__snapshots__/versions.spec.js.snap index 4ee3deb1a0..7c59280a1b 100644 --- a/test/workers/package/__snapshots__/versions.spec.js.snap +++ b/test/workers/package/__snapshots__/versions.spec.js.snap @@ -6,6 +6,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -61,6 +62,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -77,6 +79,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -148,6 +151,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -164,6 +168,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -189,6 +194,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -257,6 +263,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -305,6 +312,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -339,6 +347,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -379,6 +388,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -444,6 +454,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, @@ -549,6 +560,7 @@ Array [ "automergeEnabled": true, "group": Object { "prTitle": "{{groupName}}", + "semanticPrefix": "refactor: ", }, "groupName": "Pin Dependencies", "isPin": true, diff --git a/test/workers/repository/__snapshots__/onboarding.spec.js.snap b/test/workers/repository/__snapshots__/onboarding.spec.js.snap index 9b8365b506..1e4ad2bd00 100644 --- a/test/workers/repository/__snapshots__/onboarding.spec.js.snap +++ b/test/workers/repository/__snapshots__/onboarding.spec.js.snap @@ -17,7 +17,7 @@ With your current configuration, renovate will initially create the following Pu | Pull Requests (2) | | ------ | | **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></ul> | -| **Upgrade b**<ul><li>Branch name: \`branch-b\`</li><li>Upgrades [b](https://b) in \`undefined\` from \`1.0.0\` to \`2.0.0\`</li></ul> | +| **Upgrade b**<ul><li>Schedule: \\"on monday\\"</li><li>Branch name: \`branch-b\`</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. @@ -109,6 +109,44 @@ With your current configuration, renovate will initially create the following Pu | **Upgrade b**<ul><li>Branch name: \`branch-b\`</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) handles groups 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) | +| ------ | +| **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. diff --git a/test/workers/repository/cleanup.spec.js b/test/workers/repository/cleanup.spec.js new file mode 100644 index 0000000000..492e58b7ba --- /dev/null +++ b/test/workers/repository/cleanup.spec.js @@ -0,0 +1,85 @@ +const defaultConfig = require('../../../lib/config/defaults').getConfig(); +const cleanup = require('../../../lib/workers/repository/cleanup'); +const logger = require('../../_fixtures/logger'); + +describe('workers/repository/cleanup', () => { + describe('pruneStaleBranches(config, branchUpgradeNames)', () => { + let branchNames; + let config; + beforeEach(() => { + branchNames = []; + config = Object.assign({}, defaultConfig); + config.api = { + getAllRenovateBranches: jest.fn(), + getAllPrs: jest.fn(), + getPr: jest.fn(), + deleteBranch: jest.fn(), + }; + config.logger = logger; + }); + it('returns if config is not github', async () => { + config.platform = 'gitlab'; + 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); + await cleanup.pruneStaleBranches(config, branchNames); + 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 () => { + 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); + }); + }); +}); diff --git a/test/workers/repository/index.spec.js b/test/workers/repository/index.spec.js index 76ccad2ff4..f053f01a78 100644 --- a/test/workers/repository/index.spec.js +++ b/test/workers/repository/index.spec.js @@ -19,7 +19,7 @@ describe('workers/repository', () => { onboarding.ensurePr = jest.fn(); upgrades.determineRepoUpgrades = jest.fn(() => []); upgrades.branchifyUpgrades = jest.fn(() => ({ branchUpgrades: {} })); - branchWorker.processBranchUpgrades = jest.fn(); + branchWorker.processBranchUpgrades = jest.fn(() => 'some-branch'); config = { api: { getFileJson: jest.fn(), diff --git a/test/workers/repository/onboarding.spec.js b/test/workers/repository/onboarding.spec.js index 5369374062..28ba2a1ea6 100644 --- a/test/workers/repository/onboarding.spec.js +++ b/test/workers/repository/onboarding.spec.js @@ -73,6 +73,7 @@ If the default settings are all suitable for you, simply close this Pull Request repositoryUrl: 'https://a', currentVersion: '^1.0.0', newVersion: '1.1.0', + semanticCommits: true, }, ], 'branch-b': [ @@ -82,6 +83,36 @@ If the default settings are all suitable for you, simply close this Pull Request repositoryUrl: 'https://b', currentVersion: '1.0.0', newVersion: '2.0.0', + schedule: 'on monday', + }, + ], + }; + 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 = { + 'branch-a': [ + { + prTitle: 'Pin a', + isPin: true, + depName: 'a', + repositoryUrl: 'https://a', + currentVersion: '^1.0.0', + newVersion: '1.1.0', + semanticCommits: true, + lazyGrouping: true, + groupName: 'some-group', + }, + { + prTitle: 'Upgrade b', + depName: 'b', + repositoryUrl: 'https://b', + currentVersion: '1.0.0', + newVersion: '2.0.0', + schedule: 'on monday', }, ], }; -- GitLab