Skip to content

Commit

Permalink
feat(manager/npm): extract contraints again on post-update (#23131)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed Jul 19, 2023
1 parent dca3b01 commit 2d23e16
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 125 deletions.
47 changes: 47 additions & 0 deletions lib/modules/manager/npm/extract/index.spec.ts
Expand Up @@ -880,6 +880,53 @@ describe('modules/manager/npm/extract/index', () => {
});
});

describe('.extractAllPackageFiles()', () => {
it('runs', async () => {
fs.readLocalFile.mockResolvedValueOnce(input02Content);
const res = await npmExtract.extractAllPackageFiles(
defaultExtractConfig,
['package.json']
);
expect(res).toEqual([
{
deps: [
{
currentValue: '7.0.0',
datasource: 'npm',
depName: '@babel/core',
depType: 'dependencies',
prettyDepType: 'dependency',
},
{
currentValue: '1.21.0',
datasource: 'npm',
depName: 'config',
depType: 'dependencies',
prettyDepType: 'dependency',
},
],
extractedConstraints: {},
managerData: {
hasPackageManager: false,
lernaClient: undefined,
lernaJsonFile: undefined,
lernaPackages: undefined,
npmLock: undefined,
packageJsonName: 'renovate',
pnpmShrinkwrap: undefined,
workspacesPackages: undefined,
yarnLock: undefined,
yarnZeroInstall: false,
},
npmrc: undefined,
packageFile: 'package.json',
packageFileVersion: '1.0.0',
skipInstalls: true,
},
]);
});
});

describe('.postExtract()', () => {
it('runs', async () => {
await expect(npmExtract.postExtract([])).resolves.not.toThrow();
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/manager/npm/extract/npm.ts
@@ -1,6 +1,6 @@
import { logger } from '../../../../logger';
import { readLocalFile } from '../../../../util/fs';
import { PackageLock } from './schema';
import { PackageLock } from '../schema';
import type { LockFile } from './types';

export async function getNpmLock(filePath: string): Promise<LockFile> {
Expand Down
69 changes: 29 additions & 40 deletions lib/modules/manager/npm/post-update/lerna.spec.ts
@@ -1,33 +1,25 @@
import { envMock, mockExecAll } from '../../../../../test/exec-util';
import { env, mockedFunction, partial } from '../../../../../test/util';
import { env, fs, mockedFunction, partial } from '../../../../../test/util';
import { GlobalConfig } from '../../../../config/global';
import type { RepoGlobalConfig } from '../../../../config/types';
import type { PackageFileContent, PostUpdateConfig } from '../../types';
import * as lernaHelper from './lerna';
import { getNodeToolConstraint } from './node-version';

jest.mock('../../../../util/exec/env');
jest.mock('../../../../util/fs');
jest.mock('./node-version');
jest.mock('../../../datasource');

process.env.CONTAINERBASE = 'true';

function lernaPkgFile(lernaClient: string): Partial<PackageFileContent> {
return {
deps: [{ depName: 'lerna', currentValue: '2.0.0' }],
managerData: { lernaClient },
};
}

function lernaPkgFileWithoutLernaDep(
lernaClient: string
): Partial<PackageFileContent> {
return {
managerData: { lernaClient },
};
}

const config = partial<PostUpdateConfig>();
const config = partial<PostUpdateConfig>({ constraints: { lerna: '2.0.0' } });

describe('modules/manager/npm/post-update/lerna', () => {
const globalConfig: RepoGlobalConfig = {
Expand Down Expand Up @@ -97,10 +89,13 @@ describe('modules/manager/npm/post-update/lerna', () => {

it('generates yarn.lock files', async () => {
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValueOnce(
'{"packageManager":"yarn@^1.10.0"}'
);
const res = await lernaHelper.generateLockFiles(
lernaPkgFile('yarn'),
'some-dir',
{ ...config, extractedConstraints: { yarn: '^1.10.0' } },
{ ...config },
{}
);
expect(execSnapshots).toMatchSnapshot();
Expand All @@ -110,9 +105,9 @@ describe('modules/manager/npm/post-update/lerna', () => {
it('defaults to latest and skips bootstrap if lerna version unspecified', async () => {
const execSnapshots = mockExecAll();
const res = await lernaHelper.generateLockFiles(
lernaPkgFileWithoutLernaDep('npm'),
lernaPkgFile('npm'),
'some-dir',
config,
{ ...config, constraints: null },
{}
);
expect(res.error).toBeFalse();
Expand All @@ -125,7 +120,7 @@ describe('modules/manager/npm/post-update/lerna', () => {
const res = await lernaHelper.generateLockFiles(
lernaPkgFile('npm'),
'some-dir',
{ ...config, constraints: { npm: '^6.0.0' } },
{ ...config, constraints: { ...config.constraints, npm: '^6.0.0' } },
{}
);
expect(res.error).toBeFalse();
Expand All @@ -143,7 +138,7 @@ describe('modules/manager/npm/post-update/lerna', () => {
const res = await lernaHelper.generateLockFiles(
lernaPkgFile('npm'),
'some-dir',
{ ...config, constraints: { npm: '6.0.0' } },
{ ...config, constraints: { ...config.constraints, npm: '6.0.0' } },
{}
);
expect(execSnapshots).toMatchObject([
Expand Down Expand Up @@ -189,7 +184,7 @@ describe('modules/manager/npm/post-update/lerna', () => {
const res = await lernaHelper.generateLockFiles(
lernaPkgFile('npm'),
'some-dir',
{ ...config, constraints: { npm: '6.0.0' } },
{ ...config, constraints: { ...config.constraints, npm: '6.0.0' } },
{}
);
expect(res.error).toBeFalse();
Expand Down Expand Up @@ -222,42 +217,36 @@ describe('modules/manager/npm/post-update/lerna', () => {

describe('getLernaVersion()', () => {
it('returns specified version', () => {
const pkg = {
deps: [
{ depName: 'lerna', currentValue: '^2.0.0', currentVersion: '2.0.0' },
],
};
expect(lernaHelper.getLernaVersion(pkg)).toBe('2.0.0');
const pkg = {};
expect(
lernaHelper.getLernaVersion(pkg, { engines: { lerna: '2.0.0' } })
).toBe('2.0.0');
});

it('returns specified range', () => {
const pkg = {
deps: [
{ depName: 'lerna', currentValue: '1.x || >=2.5.0 || 5.0.0 - 7.2.3' },
],
};
expect(lernaHelper.getLernaVersion(pkg)).toBe(
'1.x || >=2.5.0 || 5.0.0 - 7.2.3'
);
const pkg = {};
expect(
lernaHelper.getLernaVersion(pkg, {
engines: { lerna: '1.x || >=2.5.0 || 5.0.0 - 7.2.3' },
})
).toBe('1.x || >=2.5.0 || 5.0.0 - 7.2.3');
});

it('returns latest if no lerna dep is specified', () => {
const pkg = {
deps: [{ depName: 'something-else', currentValue: '1.2.3' }],
};
expect(lernaHelper.getLernaVersion(pkg)).toBeNull();
const pkg = {};
expect(lernaHelper.getLernaVersion(pkg, {})).toBeNull();
});

it('returns latest if pkg has no deps at all', () => {
const pkg = {};
expect(lernaHelper.getLernaVersion(pkg)).toBeNull();
expect(lernaHelper.getLernaVersion(pkg, {})).toBeNull();
});

it('returns latest if specified lerna version is not a valid semVer range', () => {
const pkg = {
deps: [{ depName: 'lerna', currentValue: '[a.b.c;' }],
};
expect(lernaHelper.getLernaVersion(pkg)).toBeNull();
const pkg = {};
expect(
lernaHelper.getLernaVersion(pkg, { engines: { lerna: '[a.b.c;' } })
).toBeNull();
});
});
});
31 changes: 20 additions & 11 deletions lib/modules/manager/npm/post-update/lerna.ts
Expand Up @@ -15,24 +15,27 @@ import type {
PackageFileContent,
PostUpdateConfig,
} from '../../types';
import type { PackageJsonSchema } from '../schema';
import type { NpmManagerData } from '../types';
import { getNodeToolConstraint } from './node-version';
import type { GenerateLockFileResult } from './types';
import { getPackageManagerVersion, lazyLoadPackageJson } from './utils';

// Exported for testability
export function getLernaVersion(
lernaPackageFile: Partial<PackageFile<NpmManagerData>>
lernaPackageFile: Partial<PackageFile<NpmManagerData>>,
lazyPgkJson: PackageJsonSchema
): string | null {
const lernaDep = lernaPackageFile.deps?.find((d) => d.depName === 'lerna');
if (!lernaDep?.currentValue || !semver.validRange(lernaDep.currentValue)) {
const constraint = getPackageManagerVersion('lerna', lazyPgkJson);
if (!constraint || !semver.validRange(constraint)) {
logger.warn(
// TODO: types (#7154)
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
`Could not detect lerna version in ${lernaPackageFile.packageFile}, using 'latest'`
);
return null;
}
return lernaDep.currentVersion ?? lernaDep.currentValue;
return constraint;
}

export async function generateLockFiles(
Expand All @@ -48,19 +51,22 @@ export async function generateLockFiles(
return { error: false };
}
logger.debug(`Spawning lerna with ${lernaClient} to create lock files`);
const toolConstraints: ToolConstraint[] = [
await getNodeToolConstraint(config, [], lockFileDir),
];

const cmd: string[] = [];
let cmdOptions = '';
try {
const lazyPgkJson = lazyLoadPackageJson(lockFileDir);
const toolConstraints: ToolConstraint[] = [
await getNodeToolConstraint(config, [], lockFileDir, lazyPgkJson),
];
if (lernaClient === 'yarn') {
const yarnTool: ToolConstraint = {
toolName: 'yarn',
constraint: '^1.22.18', // needs to be a v1 yarn, otherwise v2 will be installed
};
const yarnCompatibility =
config.constraints?.yarn ?? config.extractedConstraints?.yarn;
config.constraints?.yarn ??
getPackageManagerVersion('yarn', await lazyPgkJson.getValue());
if (semver.validRange(yarnCompatibility)) {
yarnTool.constraint = yarnCompatibility;
}
Expand All @@ -73,7 +79,8 @@ export async function generateLockFiles(
} else if (lernaClient === 'npm') {
const npmTool: ToolConstraint = { toolName: 'npm' };
const npmCompatibility =
config.constraints?.npm ?? config.extractedConstraints?.npm;
config.constraints?.npm ??
getPackageManagerVersion('npm', await lazyPgkJson.getValue());
if (semver.validRange(npmCompatibility)) {
npmTool.constraint = npmCompatibility;
}
Expand Down Expand Up @@ -107,15 +114,17 @@ export async function generateLockFiles(
extraEnv.NPM_AUTH = env.NPM_AUTH;
extraEnv.NPM_EMAIL = env.NPM_EMAIL;
}
const lernaVersion = getLernaVersion(lernaPackageFile);
const lernaVersion =
config.constraints?.lerna ??
getLernaVersion(lernaPackageFile, await lazyPgkJson.getValue());
if (
!is.string(lernaVersion) ||
(semver.valid(lernaVersion) && semver.gte(lernaVersion, '7.0.0'))
) {
logger.debug('Skipping lerna bootstrap');
cmd.push(`${lernaClient} install ${cmdOptions}`);
} else {
logger.debug(`Using lerna version ${String(lernaVersion)}`);
logger.debug(`Using lerna version ${lernaVersion}`);
toolConstraints.push({ toolName: 'lerna', constraint: lernaVersion });
cmd.push('lerna info || echo "Ignoring lerna info failure"');
cmd.push(`${lernaClient} install ${cmdOptions}`);
Expand Down

0 comments on commit 2d23e16

Please sign in to comment.