diff --git a/lib/api/github.js b/lib/api/github.js index 04528826b563806379a9a9bfddff8547f4133432..533c81f0daa5f5e0884afb8f738f63bae5b8cb63 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 7cb5cf2f4f6ecf5c1e3b62e196ebecedffa3f6e4..5a8384ed9bc3ef1c83b7c8cb095fcefe1f921679 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 4bb2d7ed7f1f74607df524c07d8f913d234a7bc2..429e56cab2f875b1387dc9c90ce1c18f46239045 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 0000000000000000000000000000000000000000..bd78486b4e53d3fb5c3d304b5282e31728522290 --- /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 bc05c60b714c70ebbc3bd858f97dd00e6bd0e587..82f738cbf232f6d9cc61a4cd91dd7bf35c796375 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 2083da6d94fb1c9471c56e32f08cf6f9d95e22e9..1ae2bf9f1327990317f613ec823e10b6cb32825e 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 38e4261f54e368545ceca32ed15edf7b864c2aa8..25b35cc3d86705613c0197f145bb0a245f39a21a 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 00c4200ef826bcff4d1f58df448b8c9c390029e7..534765778917aa41cd1271f001fc67cb5cfd6bf0 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 02b8db1c0689d391515f9560af7492c6f50c3b10..7c59e8722c64d4d77a064c39d302c5ddecdc7552 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 4ee3deb1a0b9af19ffc0d9f4501aad6bcfa1d820..7c59280a1b18e899632418b719146c9f027a5901 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 9b8365b50629b4655b30dabd3042282cd25e89a0..1e4ad2bd007f21c5a99618b9b69ca3524df1db8e 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 0000000000000000000000000000000000000000..492e58b7ba0f87101ff65b1547afea56a64209f3 --- /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 76ccad2ff4b70d9a0d039372a6b81b6761cf9dd8..f053f01a7833393643a2218d52a93451d5c02435 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 5369374062595e99504fecf0f8b2882254684281..28ba2a1ea60854283cd4a0816a90a16c11aa34c6 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', }, ], };