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

View file

@ -1,5 +1,4 @@
import { fs } from '../../../../test/util';
import { isStable } from '../../../versioning/node';
import { getNodeConstraint } from './node-version';
jest.mock('../../../util/fs');
@ -16,45 +15,6 @@ describe('manager/npm/post-update/node-version', () => {
const res = await getNodeConstraint(config);
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 () => {
fs.readLocalFile = jest.fn();
fs.readLocalFile.mockResolvedValueOnce(null);

View file

@ -1,8 +1,7 @@
import { satisfies, validRange } from 'semver';
import { validRange } from 'semver';
import { logger } from '../../../logger';
import { getSiblingFileName, readLocalFile } from '../../../util/fs';
import { regEx } from '../../../util/regex';
import { isStable } from '../../../versioning/node';
import type { PostUpdateConfig } from '../../types';
async function getNodeFile(filename: string): Promise<string> | null {
@ -30,44 +29,14 @@ function getPackageJsonConstraint(config: PostUpdateConfig): string | null {
}
export async function getNodeConstraint(
config: PostUpdateConfig,
allowUnstable = false
config: PostUpdateConfig
): Promise<string> | null {
const { packageFile } = config;
let constraint =
const constraint =
(await getNodeFile(getSiblingFileName(packageFile, '.nvmrc'))) ||
(await getNodeFile(getSiblingFileName(packageFile, '.node-version'))) ||
getPackageJsonConstraint(config);
let lockfileVersion = 1;
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 {
if (!constraint) {
logger.debug('No node constraint found - using latest');
}
return constraint;

View file

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

View file

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

View file

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

View file

@ -95,6 +95,16 @@ describe('util/exec/docker/index', () => {
getPkgReleases.mockResolvedValueOnce({ releases } as never);
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', () => {

View file

@ -93,6 +93,11 @@ export async function getDockerTag(
versions = versions.filter(
(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));
if (versions.length) {
const version = versions.pop();