feat: use package names for ignoring when lerna or workspaces (#787)

* add minimatch

* feat: use package names for ignoring when lerna or workspaces

Renovate will now:
- Find all package.json files matching lerna or yarn workspaces glob pattern
- Retrieve package names from within those package.json files
- Implicitly ignore (not renvoate) any of those names

Closes #781
This commit is contained in:
Rhys Arkins 2017-09-12 07:49:56 +02:00 committed by GitHub
parent 6acef47c87
commit 8fa94141a1
8 changed files with 114 additions and 100 deletions

View file

@ -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

View file

@ -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);
}

View file

@ -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');

View file

@ -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",

View file

@ -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 () => {

View file

@ -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",

View file

@ -45,6 +45,55 @@ describe('workers/repository/apis', () => {
expect(await apis.getNpmrc(config)).toMatchObject(config);
});
});
describe('checkMonorepos', () => {
let config;
beforeEach(() => {
config = {
...defaultConfig,
api: {
getFileJson: jest.fn(),
},
logger,
};
});
it('adds yarn workspaces', async () => {
config.hasYarnWorkspaces = true;
config.packageFiles = [
{
packageFile: 'package.json',
content: { workspaces: ['packages/*'] },
},
{
packageFile: 'packages/something/package.json',
content: { name: '@a/b' },
},
{
packageFile: 'packages/something-else/package.json',
content: { name: '@a/c' },
},
];
const res = await apis.checkMonorepos(config);
expect(res.monorepoPackages).toMatchSnapshot();
});
it('adds lerna packages', async () => {
config.packageFiles = [
{
packageFile: 'package.json',
},
{
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();
});
});
describe('detectSemanticCommits', () => {
it('disables semantic commits', async () => {
const config = {
@ -68,54 +117,6 @@ describe('workers/repository/apis', () => {
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');
}),
},
logger,
};
const res = await apis.checkForLerna(config);
expect(res).toMatchSnapshot();
});
it('ignores zero length lerna', async () => {
const config = {
api: {
getFileJson: jest.fn(() => ({ packages: ['packages/*'] })),
getSubDirectories: jest.fn(() => []),
},
logger,
};
const res = await apis.checkForLerna(config);
expect(res).toMatchSnapshot();
});
it('implies lerna package path', async () => {
const config = {
api: {
getFileJson: jest.fn(() => ({})),
getSubDirectories: jest.fn(() => ['a', 'b']),
},
logger,
};
const res = await apis.checkForLerna(config);
expect(res).toMatchSnapshot();
});
it('returns lerna package names', async () => {
const config = {
api: {
getFileJson: jest.fn(() => ({ packages: ['packages/*'] })),
getSubDirectories: jest.fn(() => ['a', 'b']),
},
logger,
};
const res = await apis.checkForLerna(config);
expect(res).toMatchSnapshot();
});
});
describe('initApis(config)', () => {
beforeEach(() => {
jest.resetAllMocks();

View file

@ -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: