feat: binarySource=docker avoid unstable tags (#12309)

This commit is contained in:
Rhys Arkins 2021-10-25 13:19:17 +02:00 committed by GitHub
parent b4665d35cf
commit 8571b3e68d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 24 additions and 81 deletions

View file

@ -72,8 +72,7 @@ export async function generateLockFiles(
lernaCommand = lernaCommand.replace('--ignore-scripts ', ''); lernaCommand = lernaCommand.replace('--ignore-scripts ', '');
} }
lernaCommand += cmdOptions; lernaCommand += cmdOptions;
const allowUnstable = true; // lerna will pick the default installed npm@6 unless we use node@>=15 const tagConstraint = await getNodeConstraint(config);
const tagConstraint = await getNodeConstraint(config, allowUnstable);
const execOptions: ExecOptions = { const execOptions: ExecOptions = {
cwd, cwd,
extraEnv: { extraEnv: {
@ -82,7 +81,7 @@ export async function generateLockFiles(
}, },
docker: { docker: {
image: 'node', image: 'node',
tagScheme: 'npm', tagScheme: 'node',
tagConstraint, tagConstraint,
preCommands, preCommands,
}, },

View file

@ -1,5 +1,4 @@
import { fs } from '../../../../test/util'; import { fs } from '../../../../test/util';
import { isStable } from '../../../versioning/node';
import { getNodeConstraint } from './node-version'; import { getNodeConstraint } from './node-version';
jest.mock('../../../util/fs'); jest.mock('../../../util/fs');
@ -16,45 +15,6 @@ describe('manager/npm/post-update/node-version', () => {
const res = await getNodeConstraint(config); const res = await getNodeConstraint(config);
expect(res).toEqual('^12.16.0'); expect(res).toEqual('^12.16.0');
}); });
it('augments to avoid node 15', async () => {
fs.readLocalFile = jest.fn();
fs.readLocalFile.mockResolvedValueOnce(null);
fs.readLocalFile.mockResolvedValueOnce(null);
const res = await getNodeConstraint({
...config,
constraints: { node: '>= 12.16.0' },
});
const isAugmentedRange = res === '>= 12.16.0 <15';
const node16IsStable = isStable('16.100.0');
expect(isAugmentedRange || node16IsStable).toBe(true);
});
it('forces node 15 if v2 lockfile detected and constraint allows', async () => {
fs.readLocalFile.mockResolvedValueOnce(null);
fs.readLocalFile.mockResolvedValueOnce(null);
fs.readLocalFile.mockResolvedValueOnce('{"lockfileVersion":2}');
const res = await getNodeConstraint({
...config,
constraints: { node: '>= 12.16.0' },
});
const isAugmentedRange = res === '>=15 <17';
const node16IsStable = isStable('16.100.0');
expect(isAugmentedRange || node16IsStable).toBe(true);
});
it('forces node 15 if v2 lockfile detected and no constraint', async () => {
fs.readLocalFile.mockResolvedValueOnce(null);
fs.readLocalFile.mockResolvedValueOnce(null);
fs.readLocalFile.mockResolvedValueOnce('{"lockfileVersion":2}');
const res = await getNodeConstraint(
{
...config,
constraints: {},
},
true
);
const isAugmentedRange = res === '>=15';
const node16IsStable = isStable('16.100.0');
expect(isAugmentedRange || node16IsStable).toBe(true);
});
it('returns .node-version value', async () => { it('returns .node-version value', async () => {
fs.readLocalFile = jest.fn(); fs.readLocalFile = jest.fn();
fs.readLocalFile.mockResolvedValueOnce(null); fs.readLocalFile.mockResolvedValueOnce(null);

View file

@ -1,8 +1,7 @@
import { satisfies, validRange } from 'semver'; import { validRange } from 'semver';
import { logger } from '../../../logger'; import { logger } from '../../../logger';
import { getSiblingFileName, readLocalFile } from '../../../util/fs'; import { getSiblingFileName, readLocalFile } from '../../../util/fs';
import { regEx } from '../../../util/regex'; import { regEx } from '../../../util/regex';
import { isStable } from '../../../versioning/node';
import type { PostUpdateConfig } from '../../types'; import type { PostUpdateConfig } from '../../types';
async function getNodeFile(filename: string): Promise<string> | null { async function getNodeFile(filename: string): Promise<string> | null {
@ -30,44 +29,14 @@ function getPackageJsonConstraint(config: PostUpdateConfig): string | null {
} }
export async function getNodeConstraint( export async function getNodeConstraint(
config: PostUpdateConfig, config: PostUpdateConfig
allowUnstable = false
): Promise<string> | null { ): Promise<string> | null {
const { packageFile } = config; const { packageFile } = config;
let constraint = const constraint =
(await getNodeFile(getSiblingFileName(packageFile, '.nvmrc'))) || (await getNodeFile(getSiblingFileName(packageFile, '.nvmrc'))) ||
(await getNodeFile(getSiblingFileName(packageFile, '.node-version'))) || (await getNodeFile(getSiblingFileName(packageFile, '.node-version'))) ||
getPackageJsonConstraint(config); getPackageJsonConstraint(config);
let lockfileVersion = 1; if (!constraint) {
try {
const lockFileName = getSiblingFileName(packageFile, 'package-lock.json');
lockfileVersion = JSON.parse(
await readLocalFile(lockFileName, 'utf8')
).lockfileVersion;
} catch (err) {
// do nothing
}
// Avoid using node 15 if node 14 also satisfies the same constraint
// Remove this once node 16 is LTS
if (constraint) {
if (
validRange(constraint) &&
satisfies('14.100.0', constraint) &&
satisfies('15.100.0', constraint) &&
!isStable('16.100.0')
) {
if (lockfileVersion === 2) {
logger.debug('Forcing node 15+ to ensure lockfileVersion=2 is used');
constraint = '>=15 <17';
} else if (validRange(`${constraint} <15`)) {
logger.debug('Augmenting constraint to avoid node 15');
constraint = `${constraint} <15`;
}
}
} else if (allowUnstable && lockfileVersion === 2) {
logger.debug('Using node >=15 for lockfileVersion=2');
constraint = '>=15';
} else {
logger.debug('No node constraint found - using latest'); logger.debug('No node constraint found - using latest');
} }
return constraint; return constraint;

View file

@ -65,7 +65,7 @@ export async function generateLockFile(
}, },
docker: { docker: {
image: 'node', image: 'node',
tagScheme: 'npm', tagScheme: 'node',
tagConstraint, tagConstraint,
preCommands, preCommands,
}, },

View file

@ -38,7 +38,7 @@ export async function generateLockFile(
}, },
docker: { docker: {
image: 'node', image: 'node',
tagScheme: 'npm', tagScheme: 'node',
tagConstraint, tagConstraint,
preCommands, preCommands,
}, },

View file

@ -129,7 +129,7 @@ export async function generateLockFile(
extraEnv, extraEnv,
docker: { docker: {
image: 'node', image: 'node',
tagScheme: 'npm', tagScheme: 'node',
tagConstraint, tagConstraint,
preCommands, preCommands,
}, },

View file

@ -95,6 +95,16 @@ describe('util/exec/docker/index', () => {
getPkgReleases.mockResolvedValueOnce({ releases } as never); getPkgReleases.mockResolvedValueOnce({ releases } as never);
expect(await getDockerTag('foo', '^1.2.3', 'npm')).toBe('1.9.9'); expect(await getDockerTag('foo', '^1.2.3', 'npm')).toBe('1.9.9');
}); });
it('filters out node unstable', async () => {
const releases = [
{ version: '12.0.0' },
{ version: '13.0.1' },
{ version: '14.0.2' },
{ version: '15.0.2' },
];
getPkgReleases.mockResolvedValueOnce({ releases } as never);
expect(await getDockerTag('foo', '>=12', 'node')).toBe('14.0.2');
});
}); });
describe('removeDockerContainer', () => { describe('removeDockerContainer', () => {

View file

@ -93,6 +93,11 @@ export async function getDockerTag(
versions = versions.filter( versions = versions.filter(
(version) => ver.isVersion(version) && ver.matches(version, constraint) (version) => ver.isVersion(version) && ver.matches(version, constraint)
); );
// Prefer stable versions over unstable, even if the range satisfies both types
if (!versions.every((version) => ver.isStable(version))) {
logger.debug('Filtering out unstable versions');
versions = versions.filter((version) => ver.isStable(version));
}
versions = versions.sort(ver.sortVersions.bind(ver)); versions = versions.sort(ver.sortVersions.bind(ver));
if (versions.length) { if (versions.length) {
const version = versions.pop(); const version = versions.pop();