diff --git a/lib/workers/dep-type/index.js b/lib/workers/dep-type/index.js index a089b8221545c4d2e8e133dd07f5f1ee95297619..d19d0f600fde2564be5f3603633a927c77cb8263 100644 --- a/lib/workers/dep-type/index.js +++ b/lib/workers/dep-type/index.js @@ -26,14 +26,11 @@ async function renovateDepType(packageContent, config) { logger.debug(`currentDeps length is ${currentDeps.length}`); logger.debug({ currentDeps }, `currentDeps`); // Filter out ignored dependencies - let filteredDeps = currentDeps.filter( - dependency => config.ignoreDeps.indexOf(dependency.depName) === -1 + const filteredDeps = currentDeps.filter( + dependency => + config.ignoreDeps.indexOf(dependency.depName) === -1 && + config.monorepoPackages.indexOf(dependency.depName) === -1 ); - if (config.lernaPackages) { - filteredDeps = filteredDeps.filter( - dependency => config.lernaPackages.indexOf(dependency.depName) === -1 - ); - } logger.debug(`filteredDeps length is ${filteredDeps.length}`); logger.debug({ filteredDeps }, `filteredDeps`); // Obtain full config for each dependency diff --git a/lib/workers/repository/apis.js b/lib/workers/repository/apis.js index 4c915d7ff3b15a012a44a24d5cc60ebbe0e05949..f18eddbdd649395acdfb302b1a84aea956ac508e 100644 --- a/lib/workers/repository/apis.js +++ b/lib/workers/repository/apis.js @@ -1,3 +1,4 @@ +const minimatch = require('minimatch'); const conventionalCommitsDetector = require('conventional-commits-detector'); const path = require('path'); const jsonValidator = require('json-dup-key-validator'); @@ -12,10 +13,10 @@ const gitlabApi = require('../../api/gitlab'); module.exports = { detectSemanticCommits, + checkMonorepos, getNpmrc, initApis, mergeRenovateJson, - checkForLerna, detectPackageFiles, resolvePackageFiles, migrateAndValidate, @@ -35,6 +36,50 @@ async function detectSemanticCommits(config) { return true; } +async function checkMonorepos(input) { + const config = { ...input }; + const { logger } = config; + config.monorepoPackages = []; + // yarn workspaces + if (config.hasYarnWorkspaces) { + let workspaces = []; + for (const packageFile of config.packageFiles) { + if (packageFile.packageFile === 'package.json') { + workspaces = packageFile.content.workspaces; + } + } + logger.debug({ workspaces }, 'workspaces'); + for (const workspace of workspaces) { + for (const packageFile of config.packageFiles) { + if (minimatch(path.dirname(packageFile.packageFile), workspace)) { + const depName = packageFile.content.name; + config.monorepoPackages.push(depName); + } + } + } + } + // lerna + const lernaJson = await config.api.getFileJson('lerna.json'); + if (!lernaJson) { + return config; + } + config.logger.debug({ lernaJson }, 'Found lerna config'); + if (!lernaJson.packages) { + return config; + } + for (const packageGlob of lernaJson.packages) { + for (const packageFile of config.packageFiles) { + if (minimatch(path.dirname(packageFile.packageFile), packageGlob)) { + const depName = packageFile.content.name; + if (!config.monorepoPackages.includes(depName)) { + config.monorepoPackages.push(depName); + } + } + } + } + return config; +} + // Check for .npmrc in repository and pass it to npm api if found async function getNpmrc(config) { let npmrc; @@ -49,27 +94,6 @@ async function getNpmrc(config) { return { ...config, npmrc }; } -async function checkForLerna(config) { - const lernaJson = await config.api.getFileJson('lerna.json'); - if (!lernaJson) { - return {}; - } - config.logger.debug({ lernaJson }, 'Found lerna config'); - try { - const packagesPath = lernaJson.packages - ? lernaJson.packages[0].slice(0, -2) - : 'packages'; - const lernaPackages = await config.api.getSubDirectories(packagesPath); - if (lernaPackages.length === 0) { - return {}; - } - return { lernaPackages }; - } catch (err) { - config.logger.info('could not find any lerna subdirectories'); - return {}; - } -} - async function initApis(inputConfig, token) { function getPlatformApi(platform) { if (platform === 'github') { @@ -88,10 +112,7 @@ async function initApis(inputConfig, token) { config.endpoint, config.logger ); - // Check for presence of .npmrc in repository Object.assign(config, platformConfig); - const lernaConfig = await module.exports.checkForLerna(config); - Object.assign(config, lernaConfig); if (config.semanticCommits === null) { config.semanticCommits = await module.exports.detectSemanticCommits(config); } diff --git a/lib/workers/repository/index.js b/lib/workers/repository/index.js index 709a6ba7bdc8849aec04e2817a11d15f877a6c98..053f6588e09f2f39b211af41e05d67090292a4de 100644 --- a/lib/workers/repository/index.js +++ b/lib/workers/repository/index.js @@ -79,6 +79,7 @@ async function renovateRepository(repoConfig, token) { } logger.debug('Resolving package files and content'); config = await apis.resolvePackageFiles(config); + config = await apis.checkMonorepos(config); logger.trace({ config }, 'post-packageFiles config'); // TODO: why is this fix needed?! config.logger = logger; @@ -108,6 +109,7 @@ async function renovateRepository(repoConfig, token) { } } config = await apis.resolvePackageFiles(config); + config = await apis.checkMonorepos(config); config = await presets.resolveConfigPresets(config); config.logger = logger; logger.trace({ config }, 'onboarding config'); diff --git a/package.json b/package.json index 507c881fed258d4a940adda6f94d7d81170f1ce0..cb6afb01cbe35dcc5c3378857c30ff5a57ede35e 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "jsonwebtoken": "7.4.3", "later": "1.2.0", "lodash": "4.17.4", + "minimatch": "3.0.4", "moment": "2.18.1", "moment-timezone": "0.5.13", "registry-auth-token": "3.3.1", diff --git a/test/workers/dep-type/index.spec.js b/test/workers/dep-type/index.spec.js index d97e55e32897e410154ee2ceb2daf7cd744a4a0e..65860a0271c247dc170e16d1a6a83aa5c7469ea3 100644 --- a/test/workers/dep-type/index.spec.js +++ b/test/workers/dep-type/index.spec.js @@ -15,7 +15,7 @@ describe('lib/workers/dep-type/index', () => { beforeEach(() => { config = { ignoreDeps: ['a', 'b'], - lernaPackages: ['e'], + monorepoPackages: ['e'], }; }); it('returns empty if config is disabled', async () => { diff --git a/test/workers/repository/__snapshots__/apis.spec.js.snap b/test/workers/repository/__snapshots__/apis.spec.js.snap index 7af498776c268b29f8bef107c69bfc4bbe7f1723..13465b626c62cd768463f7201cbe60807bf450e7 100644 --- a/test/workers/repository/__snapshots__/apis.spec.js.snap +++ b/test/workers/repository/__snapshots__/apis.spec.js.snap @@ -7,28 +7,20 @@ Object { } `; -exports[`workers/repository/apis checkForLerna(config) ignores zero length lerna 1`] = `Object {}`; - -exports[`workers/repository/apis checkForLerna(config) implies lerna package path 1`] = ` -Object { - "lernaPackages": Array [ - "a", - "b", - ], -} +exports[`workers/repository/apis checkMonorepos adds lerna packages 1`] = ` +Array [ + "@a/b", + "@a/c", +] `; -exports[`workers/repository/apis checkForLerna(config) returns lerna package names 1`] = ` -Object { - "lernaPackages": Array [ - "a", - "b", - ], -} +exports[`workers/repository/apis checkMonorepos adds yarn workspaces 1`] = ` +Array [ + "@a/b", + "@a/c", +] `; -exports[`workers/repository/apis checkForLerna(config) swallows lerna 404 1`] = `Object {}`; - exports[`workers/repository/apis detectPackageFiles(config) adds package files to object 1`] = ` Array [ "package.json", diff --git a/test/workers/repository/apis.spec.js b/test/workers/repository/apis.spec.js index 24da3950d63cc87f7a38e7884dab250190a2060e..bada3eef81b7b2fe477f707f838f990860bfb56f 100644 --- a/test/workers/repository/apis.spec.js +++ b/test/workers/repository/apis.spec.js @@ -45,75 +45,76 @@ describe('workers/repository/apis', () => { expect(await apis.getNpmrc(config)).toMatchObject(config); }); }); - describe('detectSemanticCommits', () => { - it('disables semantic commits', async () => { - const config = { + describe('checkMonorepos', () => { + let config; + beforeEach(() => { + config = { + ...defaultConfig, api: { - getCommitMessages: jest.fn(() => []), + getFileJson: jest.fn(), }, logger, }; - const res = await apis.detectSemanticCommits(config); - expect(res).toEqual(false); }); - it('enables semantic commits', async () => { - const config = { - api: { - getCommitMessages: jest.fn(() => []), + it('adds yarn workspaces', async () => { + config.hasYarnWorkspaces = true; + config.packageFiles = [ + { + packageFile: 'package.json', + content: { workspaces: ['packages/*'] }, }, - logger, - }; - config.api.getCommitMessages.mockReturnValueOnce(['fix: something']); - const res = await apis.detectSemanticCommits(config); - expect(res).toEqual(true); - }); - }); - describe('checkForLerna(config)', () => { - it('swallows lerna 404', async () => { - const config = { - api: { - getFileJson: jest.fn(() => ({})), - getSubDirectories: jest.fn(() => { - throw new Error('some-error'); - }), + { + packageFile: 'packages/something/package.json', + content: { name: '@a/b' }, }, - logger, - }; - const res = await apis.checkForLerna(config); - expect(res).toMatchSnapshot(); + { + packageFile: 'packages/something-else/package.json', + content: { name: '@a/c' }, + }, + ]; + const res = await apis.checkMonorepos(config); + expect(res.monorepoPackages).toMatchSnapshot(); }); - it('ignores zero length lerna', async () => { - const config = { - api: { - getFileJson: jest.fn(() => ({ packages: ['packages/*'] })), - getSubDirectories: jest.fn(() => []), + it('adds lerna packages', async () => { + config.packageFiles = [ + { + packageFile: 'package.json', }, - logger, - }; - const res = await apis.checkForLerna(config); - expect(res).toMatchSnapshot(); + { + packageFile: 'packages/something/package.json', + content: { name: '@a/b' }, + }, + { + packageFile: 'packages/something-else/package.json', + content: { name: '@a/c' }, + }, + ]; + config.api.getFileJson.mockReturnValue({ packages: ['packages/*'] }); + const res = await apis.checkMonorepos(config); + expect(res.monorepoPackages).toMatchSnapshot(); }); - it('implies lerna package path', async () => { + }); + describe('detectSemanticCommits', () => { + it('disables semantic commits', async () => { const config = { api: { - getFileJson: jest.fn(() => ({})), - getSubDirectories: jest.fn(() => ['a', 'b']), + getCommitMessages: jest.fn(() => []), }, logger, }; - const res = await apis.checkForLerna(config); - expect(res).toMatchSnapshot(); + const res = await apis.detectSemanticCommits(config); + expect(res).toEqual(false); }); - it('returns lerna package names', async () => { + it('enables semantic commits', async () => { const config = { api: { - getFileJson: jest.fn(() => ({ packages: ['packages/*'] })), - getSubDirectories: jest.fn(() => ['a', 'b']), + getCommitMessages: jest.fn(() => []), }, logger, }; - const res = await apis.checkForLerna(config); - expect(res).toMatchSnapshot(); + config.api.getCommitMessages.mockReturnValueOnce(['fix: something']); + const res = await apis.detectSemanticCommits(config); + expect(res).toEqual(true); }); }); describe('initApis(config)', () => { diff --git a/yarn.lock b/yarn.lock index e8ae67d2c45657fd0633690bbc92b3be4eddac23..036741cee2ae55cd4fc14d4d1c234502767e4cdb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2958,7 +2958,7 @@ mimic-response@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.0.tgz#df3d3652a73fded6b9b0b24146e6fd052353458e" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: