Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(manager/npm): prepare for buildpack support #16979

Merged
merged 3 commits into from
Aug 4, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions lib/modules/manager/npm/post-update/__snapshots__/npm.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`modules/manager/npm/post-update/npm catches errors 1`] = `Array []`;

exports[`modules/manager/npm/post-update/npm finds npm globally 1`] = `Array []`;

exports[`modules/manager/npm/post-update/npm generates lock files 1`] = `
Array [
Object {
Expand Down Expand Up @@ -45,8 +41,6 @@ Array [
]
`;

exports[`modules/manager/npm/post-update/npm performs full install 1`] = `Array []`;

exports[`modules/manager/npm/post-update/npm performs lock file maintenance 1`] = `
Array [
Object {
Expand Down Expand Up @@ -202,9 +196,3 @@ Array [
},
]
`;

exports[`modules/manager/npm/post-update/npm performs npm-shrinkwrap.json updates (no package-lock.json) 1`] = `Array []`;

exports[`modules/manager/npm/post-update/npm performs npm-shrinkwrap.json updates 1`] = `Array []`;

exports[`modules/manager/npm/post-update/npm uses docker npm 1`] = `Array []`;
26 changes: 25 additions & 1 deletion lib/modules/manager/npm/post-update/node-version.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { fs } from '../../../../../test/util';
import { getNodeConstraint, getNodeUpdate } from './node-version';
import {
getNodeConstraint,
getNodeToolContraint,
getNodeUpdate,
} from './node-version';

jest.mock('../../../../util/fs');

Expand Down Expand Up @@ -56,4 +60,24 @@ describe('modules/manager/npm/post-update/node-version', () => {
expect(getNodeUpdate([])).toBeUndefined();
});
});

describe('getNodeToolContraint()', () => {
it('returns getNodeUpdate', async () => {
expect(
await getNodeToolContraint(config, [
{ depName: 'node', newValue: '16.15.0' },
])
).toEqual({
toolName: 'node',
constraint: '16.15.0',
});
});

it('returns getNodeConstraint', async () => {
expect(await getNodeToolContraint(config, [])).toEqual({
toolName: 'node',
constraint: '^12.16.0',
});
});
});
});
19 changes: 17 additions & 2 deletions lib/modules/manager/npm/post-update/node-version.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import semver from 'semver';
import { logger } from '../../../../logger';
import type { ToolConstraint } from '../../../../util/exec/types';
import { getSiblingFileName, readLocalFile } from '../../../../util/fs';
import { newlineRegex, regEx } from '../../../../util/regex';
import type { PostUpdateConfig, Upgrade } from '../../types';
Expand Down Expand Up @@ -35,9 +36,10 @@ export async function getNodeConstraint(
config: Partial<PostUpdateConfig>
): Promise<string | null> {
const { packageFile } = config;
// TODO: fix types (#7154)
const constraint =
(await getNodeFile(getSiblingFileName(packageFile, '.nvmrc'))) ??
(await getNodeFile(getSiblingFileName(packageFile, '.node-version'))) ??
(await getNodeFile(getSiblingFileName(packageFile!, '.nvmrc'))) ??
(await getNodeFile(getSiblingFileName(packageFile!, '.node-version'))) ??
getPackageJsonConstraint(config);
if (!constraint) {
logger.debug('No node constraint found - using latest');
Expand All @@ -48,3 +50,16 @@ export async function getNodeConstraint(
export function getNodeUpdate(upgrades: Upgrade[]): string | undefined {
return upgrades.find((u) => u.depName === 'node')?.newValue;
}

export async function getNodeToolContraint(
viceice marked this conversation as resolved.
Show resolved Hide resolved
config: Partial<PostUpdateConfig>,
upgrades: Upgrade[]
): Promise<ToolConstraint> {
const constraint =
getNodeUpdate(upgrades) ?? (await getNodeConstraint(config));

return {
toolName: 'node',
constraint,
};
}
91 changes: 84 additions & 7 deletions lib/modules/manager/npm/post-update/npm.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
import upath from 'upath';
import { envMock, mockExecAll } from '../../../../../test/exec-util';
import { Fixtures } from '../../../../../test/fixtures';
import { env, fs } from '../../../../../test/util';
import { env, fs, mockedFunction } from '../../../../../test/util';
import { GlobalConfig } from '../../../../config/global';
import { getNodeToolContraint } from './node-version';
import * as npmHelper from './npm';

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

process.env.BUILDPACK = 'true';

describe('modules/manager/npm/post-update/npm', () => {
beforeEach(() => {
jest.resetAllMocks();
jest.resetModules();
env.getChildProcessEnv.mockReturnValue(envMock.basic);
GlobalConfig.set({ localDir: '' });
mockedFunction(getNodeToolContraint).mockResolvedValueOnce({
toolName: 'node',
constraint: '16.16.0',
});
});

it('generates lock files', async () => {
Expand Down Expand Up @@ -109,7 +116,8 @@ describe('modules/manager/npm/post-update/npm', () => {
);
expect(res.error).toBeUndefined();
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
// TODO: is that right?
expect(execSnapshots).toEqual([]);
});

it('performs npm-shrinkwrap.json updates (no package-lock.json)', async () => {
Expand All @@ -131,7 +139,8 @@ describe('modules/manager/npm/post-update/npm', () => {
);
expect(res.error).toBeUndefined();
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
// TODO: is that right?
expect(execSnapshots).toEqual([]);
});

it('performs full install', async () => {
Expand All @@ -148,7 +157,8 @@ describe('modules/manager/npm/post-update/npm', () => {
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.error).toBeUndefined();
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
// TODO: is that right?
expect(execSnapshots).toEqual([]);
});

it('runs twice if remediating', async () => {
Expand Down Expand Up @@ -181,7 +191,7 @@ describe('modules/manager/npm/post-update/npm', () => {
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.error).toBeTrue();
expect(res.lockFile).toBeUndefined();
expect(execSnapshots).toMatchSnapshot();
expect(execSnapshots).toEqual([]);
});

it('finds npm globally', async () => {
Expand All @@ -194,7 +204,8 @@ describe('modules/manager/npm/post-update/npm', () => {
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
// TODO: is that right?
expect(execSnapshots).toEqual([]);
});

it('uses docker npm', async () => {
Expand All @@ -208,7 +219,8 @@ describe('modules/manager/npm/post-update/npm', () => {
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
// TODO: is that right?
expect(execSnapshots).toEqual([]);
});

it('performs lock file maintenance', async () => {
Expand All @@ -226,4 +238,69 @@ describe('modules/manager/npm/post-update/npm', () => {
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchSnapshot();
});

it('works for docker mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'docker',
allowScripts: true,
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await npmHelper.generateLockFile(
'some-dir',
{},
'package-lock.json',
{ constraints: { npm: '6.0.0' } },
[{ isLockFileMaintenance: true }]
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull renovate/node' },
{ cmd: 'docker ps --filter name=renovate_node -aq' },
{
cmd:
'docker run --rm --name=renovate_node --label=renovate_child ' +
'-v "/tmp":"/tmp" ' +
'-e BUILDPACK_CACHE_DIR ' +
'-w "some-dir" ' +
'renovate/node ' +
'bash -l -c "' +
'install-tool npm 6.0.0 ' +
'&& ' +
'hash -d npm 2>/dev/null || true ' +
'&& ' +
'npm install --package-lock-only --no-audit' +
'"',
},
]);
});

it('works for install mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'install',
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await npmHelper.generateLockFile(
'some-dir',
{},
'package-lock.json',
{ constraints: { npm: '6.0.0' } },
[{ isLockFileMaintenance: true }]
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool npm 6.0.0' },
{ cmd: 'hash -d npm 2>/dev/null || true' },
{
cmd: 'npm install --package-lock-only --no-audit --ignore-scripts',
},
]);
});
});
59 changes: 59 additions & 0 deletions lib/modules/manager/npm/post-update/pnpm.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ jest.mock('../../../../util/fs');
jest.mock('./node-version');

delete process.env.NPM_CONFIG_CACHE;
process.env.BUILDPACK = 'true';

describe('modules/manager/npm/post-update/pnpm', () => {
let config: PostUpdateConfig;
Expand Down Expand Up @@ -178,4 +179,62 @@ describe('modules/manager/npm/post-update/pnpm', () => {
expect(fs.readLocalFile).toHaveBeenCalledTimes(3);
expect(res.lockFile).toBe('lockfileVersion: 5.3\n');
});

it('works for docker mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'docker',
allowScripts: true,
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, constraints: { pnpm: '6.0.0' } }
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'docker pull renovate/node' },
{ cmd: 'docker ps --filter name=renovate_node -aq' },
{
cmd:
'docker run --rm --name=renovate_node --label=renovate_child ' +
'-v "/tmp":"/tmp" ' +
'-e BUILDPACK_CACHE_DIR ' +
'-w "some-dir" ' +
'renovate/node ' +
'bash -l -c "' +
'install-tool pnpm 6.0.0 ' +
'&& ' +
'pnpm install --recursive --lockfile-only' +
'"',
},
]);
});

it('works for install mode', async () => {
GlobalConfig.set({
localDir: '',
cacheDir: '/tmp',
binarySource: 'install',
});
const execSnapshots = mockExecAll();
fs.readLocalFile.mockResolvedValue('package-lock-contents');
const res = await pnpmHelper.generateLockFile(
'some-dir',
{},
{ ...config, constraints: { pnpm: '6.0.0' } }
);
expect(fs.readLocalFile).toHaveBeenCalledTimes(1);
expect(res.lockFile).toBe('package-lock-contents');
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool pnpm 6.0.0' },
{
cmd: 'pnpm install --recursive --lockfile-only --ignore-scripts --ignore-pnpmfile',
},
]);
});
});
2 changes: 2 additions & 0 deletions lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ export interface PostUpdateConfig<T = Record<string, any>>
skipInstalls?: boolean;
ignoreScripts?: boolean;

packageFile?: string;

upgrades: Upgrade[];
npmLock?: string;
yarnLock?: string;
Expand Down
5 changes: 5 additions & 0 deletions lib/util/exec/buildpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ const allToolConfig: Record<string, ToolConfig> = {
depName: 'jsonnet-bundler/jsonnet-bundler',
versioning: semverVersioningId,
},
node: {
datasource: 'node',
depName: 'node',
versioning: npmVersioningId,
},
npm: {
datasource: 'npm',
depName: 'npm',
Expand Down