diff --git a/lib/manager/composer/artifacts.ts b/lib/manager/composer/artifacts.ts index 0780314bf8217cc04ed3f4dd3235de67b5bcc374..cf209a4d60202c3c5e566ffeb6bebd9ac2dd8dae 100644 --- a/lib/manager/composer/artifacts.ts +++ b/lib/manager/composer/artifacts.ts @@ -118,7 +118,7 @@ export async function updateArtifacts( cmd = 'composer'; } else { logger.warn({ config }, 'Unsupported binarySource'); - cmd = 'bundle'; + cmd = 'composer'; } let args; if (config.isLockFileMaintenance) { diff --git a/lib/manager/gomod/artifacts.ts b/lib/manager/gomod/artifacts.ts index f802b73960270ae0b7c00bbc3d01bff959d13854..b182ad8fa46d72370b7a5e7b8e65790dcf7d11cb 100644 --- a/lib/manager/gomod/artifacts.ts +++ b/lib/manager/gomod/artifacts.ts @@ -77,7 +77,7 @@ export async function updateArtifacts( cmd = 'go'; } else { logger.warn({ config }, 'Unsupported binarySource'); - cmd = 'bundle'; + cmd = 'go'; } let args = 'get -d ./...'; if (cmd.includes('.insteadOf')) { diff --git a/lib/manager/pip_setup/extract.ts b/lib/manager/pip_setup/extract.ts index 8e41dd5070de6e9f65c78d4bae19d10ba62cd34a..a9954ee84e47215c44bbb1de021f46ab28aa276b 100644 --- a/lib/manager/pip_setup/extract.ts +++ b/lib/manager/pip_setup/extract.ts @@ -49,7 +49,6 @@ export async function extractSetupFile( const cwd = config.localDir; let cmd: string; const args = [`"${join(__dirname, 'extract.py')}"`, `"${packageFile}"`]; - // istanbul ignore if if (config.binarySource === 'docker') { logger.info('Running python via docker'); await exec(`docker pull renovate/pip`); diff --git a/test/execUtil.ts b/test/execUtil.ts new file mode 100644 index 0000000000000000000000000000000000000000..5014cbd52d93f0512e5b84540bba66e4f44992c7 --- /dev/null +++ b/test/execUtil.ts @@ -0,0 +1,66 @@ +import { exec as _exec } from 'child_process'; +import { ExecOptions } from '../lib/util/exec'; + +type CallOptions = ExecOptions | null | undefined; + +export type ExecResult = { stdout: string; stderr: string } | Error; + +interface ExecSnapshot { + cmd: string; + options?: ExecOptions | null | undefined; +} + +export type ExecSnapshots = ExecSnapshot[]; + +export function execSnapshot(cmd: string, options?: CallOptions): ExecSnapshot { + const snapshot = { + cmd, + options, + }; + + const str = JSON.stringify(snapshot, (k, v) => (v === undefined ? null : v)); + + const cwd = process.cwd().replace(/\\(\w)/g, '/$1'); + return JSON.parse( + str + .replace(/\\(\w)/g, '/$1') + .split(cwd) + .join('/root/project') + ); +} + +const defaultExecResult = { stdout: '', stderr: '' }; + +export function mockExecAll( + execFn: jest.Mock<typeof _exec>, + execResult: ExecResult = defaultExecResult +): ExecSnapshots { + const snapshots = []; + execFn.mockImplementation((cmd, options, callback) => { + snapshots.push(execSnapshot(cmd, options)); + if (execResult instanceof Error) { + throw execResult; + } + callback(null, execResult); + return undefined; + }); + return snapshots; +} + +export function mockExecSequence( + execFn: jest.Mock<typeof _exec>, + execResults: ExecResult[] +): ExecSnapshots { + const snapshots = []; + execResults.forEach(execResult => { + execFn.mockImplementationOnce((cmd, options, callback) => { + snapshots.push(execSnapshot(cmd, options)); + if (execResult instanceof Error) { + throw execResult; + } + callback(null, execResult); + return undefined; + }); + }); + return snapshots; +} diff --git a/test/manager/bundler/__snapshots__/artifacts.spec.ts.snap b/test/manager/bundler/__snapshots__/artifacts.spec.ts.snap index 7f92845d826d3a3ab4296ea5706e67feddb20ae6..5b255c6b07ccec515b5881f4cec8fa2b509a6e01 100644 --- a/test/manager/bundler/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/bundler/__snapshots__/artifacts.spec.ts.snap @@ -11,7 +11,24 @@ Array [ ] `; -exports[`bundler.updateArtifacts() Docker .ruby-version 2`] = `"docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/ruby:1.2.0 bash -l -c \\"ruby --version && gem install bundler --no-document && bundle lock --update \\""`; +exports[`bundler.updateArtifacts() Docker .ruby-version 2`] = ` +Array [ + Object { + "cmd": "docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/ruby:1.2.0 bash -l -c \\"ruby --version && gem install bundler --no-document && bundle lock --update \\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; exports[`bundler.updateArtifacts() Docker compatibility options 1`] = ` Array [ @@ -24,10 +41,46 @@ Array [ ] `; -exports[`bundler.updateArtifacts() Docker compatibility options 2`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/ruby:latest bash -l -c \\"ruby --version && gem install bundler -v 3.2.1 --no-document && bundle lock --update \\""`; +exports[`bundler.updateArtifacts() Docker compatibility options 2`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/ruby:latest bash -l -c \\"ruby --version && gem install bundler -v 3.2.1 --no-document && bundle lock --update \\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; exports[`bundler.updateArtifacts() returns null if Gemfile.lock was not changed 1`] = `null`; +exports[`bundler.updateArtifacts() returns null if Gemfile.lock was not changed 2`] = ` +Array [ + Object { + "cmd": "bundle lock --update ", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + exports[`bundler.updateArtifacts() works explicit global binarySource 1`] = ` Array [ Object { @@ -39,6 +92,25 @@ Array [ ] `; +exports[`bundler.updateArtifacts() works explicit global binarySource 2`] = ` +Array [ + Object { + "cmd": "bundle lock --update ", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + exports[`bundler.updateArtifacts() works for default binarySource 1`] = ` Array [ Object { @@ -49,3 +121,22 @@ Array [ }, ] `; + +exports[`bundler.updateArtifacts() works for default binarySource 2`] = ` +Array [ + Object { + "cmd": "bundle lock --update ", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; diff --git a/test/manager/bundler/artifacts.spec.ts b/test/manager/bundler/artifacts.spec.ts index 7d91f5d3628fbf91551732f9abe0910cebe51573..a325af14760e57999e9066e02668432cc77ec96e 100644 --- a/test/manager/bundler/artifacts.spec.ts +++ b/test/manager/bundler/artifacts.spec.ts @@ -5,6 +5,7 @@ import { updateArtifacts } from '../../../lib/manager/bundler'; import { platform as _platform } from '../../../lib/platform'; import * as _datasource from '../../../lib/datasource/docker'; import { mocked } from '../../util'; +import { mockExecAll } from '../../execUtil'; const fs: jest.Mocked<typeof _fs> = _fs as any; const exec: jest.Mock<typeof _exec> = _exec as any; @@ -17,13 +18,28 @@ jest.mock('../../../lib/platform'); jest.mock('../../../lib/datasource/docker'); let config; +let processEnv; describe('bundler.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + jest.resetModules(); + config = { localDir: '/tmp/github/some/repo', }; + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('returns null by default', async () => { expect(await updateArtifacts('', [], '', config)).toBeNull(); @@ -31,10 +47,7 @@ describe('bundler.updateArtifacts()', () => { it('returns null if Gemfile.lock was not changed', async () => { platform.getFile.mockResolvedValueOnce('Current Gemfile.lock'); fs.outputFile.mockResolvedValueOnce(null as never); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: [], } as Git.StatusResult); @@ -42,14 +55,12 @@ describe('bundler.updateArtifacts()', () => { expect( await updateArtifacts('Gemfile', [], 'Updated Gemfile content', config) ).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('works for default binarySource', async () => { platform.getFile.mockResolvedValueOnce('Current Gemfile.lock'); fs.outputFile.mockResolvedValueOnce(null as never); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['Gemfile.lock'], } as Git.StatusResult); @@ -57,14 +68,12 @@ describe('bundler.updateArtifacts()', () => { expect( await updateArtifacts('Gemfile', [], 'Updated Gemfile content', config) ).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('works explicit global binarySource', async () => { platform.getFile.mockResolvedValueOnce('Current Gemfile.lock'); fs.outputFile.mockResolvedValueOnce(null as never); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['Gemfile.lock'], } as Git.StatusResult); @@ -75,10 +84,10 @@ describe('bundler.updateArtifacts()', () => { binarySource: 'global', }) ).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); describe('Docker', () => { it('.ruby-version', async () => { - let dockerCommand = null; platform.getFile.mockResolvedValueOnce('Current Gemfile.lock'); fs.outputFile.mockResolvedValueOnce(null as never); platform.getFile.mockResolvedValueOnce('1.2.0'); @@ -89,11 +98,7 @@ describe('bundler.updateArtifacts()', () => { { version: '1.3.0' }, ], }); - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['Gemfile.lock'], } as Git.StatusResult); @@ -104,10 +109,9 @@ describe('bundler.updateArtifacts()', () => { binarySource: 'docker', }) ).toMatchSnapshot(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('compatibility options', async () => { - let dockerCommand = null; platform.getFile.mockResolvedValueOnce('Current Gemfile.lock'); fs.outputFile.mockResolvedValueOnce(null as never); datasource.getPkgReleases.mockResolvedValueOnce({ @@ -117,11 +121,7 @@ describe('bundler.updateArtifacts()', () => { { version: '1.3.0' }, ], }); - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['Gemfile.lock'], } as Git.StatusResult); @@ -137,7 +137,7 @@ describe('bundler.updateArtifacts()', () => { }, }) ).toMatchSnapshot(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); }); }); diff --git a/test/manager/cargo/__snapshots__/artifacts.spec.ts.snap b/test/manager/cargo/__snapshots__/artifacts.spec.ts.snap index 6e4744b51073b3b22dfe667f1727c44813de82a1..cb423da45162027123492013a067d3746a0b2c1f 100644 --- a/test/manager/cargo/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/cargo/__snapshots__/artifacts.spec.ts.snap @@ -11,4 +11,59 @@ Array [ ] `; -exports[`.updateArtifacts() returns updated Cargo.lock with docker 1`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/rust cargo update --manifest-path /tmp/github/some/repo/Cargo.toml --package dep1"`; +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "cargo update --manifest-path /tmp/github/some/repo/Cargo.toml --package dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated Cargo.lock 1`] = ` +Array [ + Object { + "cmd": "cargo update --manifest-path /tmp/github/some/repo/Cargo.toml --package dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated Cargo.lock with docker 1`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/rust cargo update --manifest-path /tmp/github/some/repo/Cargo.toml --package dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; diff --git a/test/manager/cargo/artifacts.spec.ts b/test/manager/cargo/artifacts.spec.ts index b667dbe3c793025d457fecbd2d383d2281f6a619..f7a3e5071e96f13208841f394f84f2cbfbf20c76 100644 --- a/test/manager/cargo/artifacts.spec.ts +++ b/test/manager/cargo/artifacts.spec.ts @@ -3,6 +3,7 @@ import { exec as _exec } from 'child_process'; import * as cargo from '../../../lib/manager/cargo/artifacts'; import { platform as _platform } from '../../../lib/platform'; import { mocked } from '../../util'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -15,12 +16,24 @@ const config = { localDir: '/tmp/github/some/repo', }; +let processEnv; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + jest.resetModules(); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; }); afterEach(() => { - delete global.trustLevel; + process.env = processEnv; }); it('returns null if no Cargo.lock found', async () => { const updatedDeps = ['dep1']; @@ -35,40 +48,29 @@ describe('.updateArtifacts()', () => { }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current Cargo.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('Current Cargo.lock' as any); const updatedDeps = ['dep1']; expect( await cargo.updateArtifacts('Cargo.toml', updatedDeps, '', config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated Cargo.lock', async () => { platform.getFile.mockResolvedValueOnce('Old Cargo.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New Cargo.lock' as any); const updatedDeps = ['dep1']; - global.trustLevel = 'high'; expect( await cargo.updateArtifacts('Cargo.toml', updatedDeps, '{}', config) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated Cargo.lock with docker', async () => { - let dockerCommand = null; platform.getFile.mockResolvedValueOnce('Old Cargo.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New Cargo.lock' as any); const updatedDeps = ['dep1']; - global.trustLevel = 'high'; expect( await cargo.updateArtifacts('Cargo.toml', updatedDeps, '{}', { ...config, @@ -76,7 +78,7 @@ describe('.updateArtifacts()', () => { dockerUser: 'foobar', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { platform.getFile.mockResolvedValueOnce('Current Cargo.lock'); diff --git a/test/manager/composer/__snapshots__/artifacts.spec.ts.snap b/test/manager/composer/__snapshots__/artifacts.spec.ts.snap index 11db3911996def58f5e37e68106d847a788e2054..d3abf88eff6176c6a573fcfbe823bba20208dfd2 100644 --- a/test/manager/composer/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/composer/__snapshots__/artifacts.spec.ts.snap @@ -22,4 +22,122 @@ Array [ ] `; -exports[`.updateArtifacts() supports docker mode 1`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/composer\\":\\"/tmp/renovate/cache/others/composer\\" -e COMPOSER_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/composer composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader"`; +exports[`.updateArtifacts() performs lockFileMaintenance 1`] = ` +Array [ + Object { + "cmd": "composer install --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated composer.lock 1`] = ` +Array [ + Object { + "cmd": "composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports docker mode 1`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/composer\\":\\"/tmp/renovate/cache/others/composer\\" -e COMPOSER_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/composer composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports global mode 1`] = ` +Array [ + Object { + "cmd": "composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() uses hostRules to write auth.json 1`] = ` +Array [ + Object { + "cmd": "composer update --with-dependencies --ignore-platform-reqs --no-ansi --no-interaction --no-scripts --no-autoloader", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "COMPOSER_CACHE_DIR": "/tmp/renovate/cache/others/composer", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; diff --git a/test/manager/composer/artifacts.spec.ts b/test/manager/composer/artifacts.spec.ts index 154bdb75f5c9e90c455dab43ca62773157382228..1207685148ef68dc718a30bc25ead9f47f3120a9 100644 --- a/test/manager/composer/artifacts.spec.ts +++ b/test/manager/composer/artifacts.spec.ts @@ -4,6 +4,7 @@ import * as composer from '../../../lib/manager/composer/artifacts'; import { platform as _platform } from '../../../lib/platform'; import { mocked } from '../../util'; import { StatusResult } from '../../../lib/platform/git/storage'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -20,12 +21,24 @@ const config = { cacheDir: '/tmp/renovate/cache', }; +let processEnv; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + jest.resetModules(); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; }); afterEach(() => { - delete global.trustLevel; + process.env = processEnv; }); it('returns if no composer.lock found', async () => { expect( @@ -34,25 +47,20 @@ describe('.updateArtifacts()', () => { }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('Current composer.lock' as any); platform.getRepoStatus.mockResolvedValue({ modified: [] } as StatusResult); expect( await composer.updateArtifacts('composer.json', [], '{}', config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('uses hostRules to write auth.json', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('Current composer.lock' as any); const authConfig = { - localDir: '/tmp/github/some/repo', + ...config, registryUrls: ['https://packagist.renovatebot.com'], }; hostRules.find.mockReturnValue({ @@ -63,28 +71,23 @@ describe('.updateArtifacts()', () => { expect( await composer.updateArtifacts('composer.json', [], '{}', authConfig) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated composer.lock', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New composer.lock' as any); - global.trustLevel = 'high'; platform.getRepoStatus.mockResolvedValue({ modified: ['composer.lock'], } as StatusResult); expect( await composer.updateArtifacts('composer.json', [], '{}', config) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('performs lockFileMaintenance', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New composer.lock' as any); platform.getRepoStatus.mockResolvedValue({ modified: ['composer.lock'], @@ -95,16 +98,12 @@ describe('.updateArtifacts()', () => { isLockFileMaintenance: true, }) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports docker mode', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New composer.lock' as any); expect( @@ -114,14 +113,11 @@ describe('.updateArtifacts()', () => { dockerUser: 'foobar', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports global mode', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New composer.lock' as any); expect( await composer.updateArtifacts('composer.json', [], '{}', { @@ -129,6 +125,7 @@ describe('.updateArtifacts()', () => { binarySource: 'global', }) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { platform.getFile.mockResolvedValueOnce('Current composer.lock'); diff --git a/test/manager/gomod/__snapshots__/artifacts.spec.ts.snap b/test/manager/gomod/__snapshots__/artifacts.spec.ts.snap index 077ed134ea3e432100e1b17a12c394e691579f41..972d4c7bb3170c6dc0501894a9f5fc6c9d69bc8c 100644 --- a/test/manager/gomod/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/gomod/__snapshots__/artifacts.spec.ts.snap @@ -11,8 +11,141 @@ Array [ ] `; -exports[`.updateArtifacts() supports docker mode with credentials 1`] = `"docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go bash -c \\"git config --global url.\\\\\\"https://some-token@github.com/\\\\\\".insteadOf \\\\\\"https://github.com/\\\\\\" && go get -d ./...\\""`; +exports[`.updateArtifacts() catches errors 2`] = `Array []`; -exports[`.updateArtifacts() supports docker mode with credentials, appMode and trustLevel=high 1`] = `"docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go bash -c \\"git config --global url.\\\\\\"https://x-access-token:some-token@github.com/\\\\\\".insteadOf \\\\\\"https://github.com/\\\\\\" && go get -d ./...\\""`; +exports[`.updateArtifacts() returns if no go.sum found 1`] = `Array []`; -exports[`.updateArtifacts() supports docker mode without credentials 1`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go go get -d ./..."`; +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "go get -d ./...", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated go.sum 1`] = ` +Array [ + Object { + "cmd": "go get -d ./...", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports docker mode with credentials 1`] = ` +Array [ + Object { + "cmd": "docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go bash -c \\"git config --global url.\\\\\\"https://some-token@github.com/\\\\\\".insteadOf \\\\\\"https://github.com/\\\\\\" && go get -d ./...\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports docker mode with credentials and appMode enabled 1`] = ` +Array [ + Object { + "cmd": "docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go bash -c \\"git config --global url.\\\\\\"https://x-access-token:some-token@github.com/\\\\\\".insteadOf \\\\\\"https://github.com/\\\\\\" && go get -d ./...\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, + Object { + "cmd": "docker run --rm -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go bash -c \\"git config --global url.\\\\\\"https://x-access-token:some-token@github.com/\\\\\\".insteadOf \\\\\\"https://github.com/\\\\\\" && go mod tidy\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports docker mode without credentials 1`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/go\\":\\"/tmp/renovate/cache/others/go\\" -e GOPATH -e GOPROXY -e GONOSUMDB -e CGO_ENABLED=0 -w \\"/tmp/github/some/repo\\" renovate/go go get -d ./...", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports global mode 1`] = ` +Array [ + Object { + "cmd": "go get -d ./...", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "GOPATH": "/tmp/renovate/cache/others/go", + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; diff --git a/test/manager/gomod/artifacts.spec.ts b/test/manager/gomod/artifacts.spec.ts index b0b7cd0b367ea514b7a94325947810faa07acc87..d6be7fa1cce947f3b615f30f44c6aa88edcae68c 100644 --- a/test/manager/gomod/artifacts.spec.ts +++ b/test/manager/gomod/artifacts.spec.ts @@ -4,6 +4,7 @@ import * as gomod from '../../../lib/manager/gomod/artifacts'; import { platform as _platform } from '../../../lib/platform'; import { mocked } from '../../util'; import { StatusResult } from '../../../lib/platform/git/storage'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -32,38 +33,46 @@ const config = { cacheDir: '/tmp/renovate/cache', }; +let processEnv; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); - exec.mockImplementation((_cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + jest.resetModules(); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('returns if no go.sum found', async () => { + const execSnapshots = mockExecAll(exec); expect( await gomod.updateArtifacts('go.mod', [], gomod1, config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current go.sum'); - exec.mockImplementationOnce((_cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: [], } as StatusResult); expect( await gomod.updateArtifacts('go.mod', [], gomod1, config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated go.sum', async () => { platform.getFile.mockResolvedValueOnce('Current go.sum'); - exec.mockImplementationOnce((_cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['go.sum'], } as StatusResult); @@ -71,15 +80,11 @@ describe('.updateArtifacts()', () => { expect( await gomod.updateArtifacts('go.mod', [], gomod1, config) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports docker mode without credentials', async () => { platform.getFile.mockResolvedValueOnce('Current go.sum'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['go.sum'], } as StatusResult); @@ -91,14 +96,11 @@ describe('.updateArtifacts()', () => { dockerUser: 'foobar', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports global mode', async () => { platform.getFile.mockResolvedValueOnce('Current go.sum'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['go.sum'], } as StatusResult); @@ -109,18 +111,14 @@ describe('.updateArtifacts()', () => { binarySource: 'global', }) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports docker mode with credentials', async () => { hostRules.find.mockReturnValueOnce({ token: 'some-token', }); platform.getFile.mockResolvedValueOnce('Current go.sum'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['go.sum'], } as StatusResult); @@ -131,19 +129,14 @@ describe('.updateArtifacts()', () => { binarySource: 'docker', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); - it('supports docker mode with credentials, appMode and trustLevel=high', async () => { + it('supports docker mode with credentials and appMode enabled', async () => { hostRules.find.mockReturnValueOnce({ token: 'some-token', }); platform.getFile.mockResolvedValueOnce('Current go.sum'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValueOnce({ modified: ['go.sum'], } as StatusResult); @@ -152,7 +145,6 @@ describe('.updateArtifacts()', () => { fs.readFile.mockResolvedValueOnce('New go.sum 3' as any); try { global.appMode = true; - global.trustLevel = 'high'; expect( await gomod.updateArtifacts('go.mod', [], gomod1, { ...config, @@ -160,13 +152,13 @@ describe('.updateArtifacts()', () => { postUpdateOptions: ['gomodTidy'], }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); } finally { delete global.appMode; - delete global.trustLevel; } }); it('catches errors', async () => { + const execSnapshots = mockExecAll(exec); platform.getFile.mockResolvedValueOnce('Current go.sum'); fs.outputFile.mockImplementationOnce(() => { throw new Error('This update totally doesnt work'); @@ -174,5 +166,6 @@ describe('.updateArtifacts()', () => { expect( await gomod.updateArtifacts('go.mod', [], gomod1, config) ).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); }); diff --git a/test/manager/gradle/__snapshots__/index.spec.ts.snap b/test/manager/gradle/__snapshots__/index.spec.ts.snap index 15f9f422b2f672116eb9c2cf8c085d36ab22f9a6..bc48a849d149a05183a139867f869b5c014cccb8 100644 --- a/test/manager/gradle/__snapshots__/index.spec.ts.snap +++ b/test/manager/gradle/__snapshots__/index.spec.ts.snap @@ -2,31 +2,66 @@ exports[`manager/gradle extractPackageFile should configure the renovate report plugin 1`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; exports[`manager/gradle extractPackageFile should execute gradlew when available 1`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; exports[`manager/gradle extractPackageFile should return empty if renovate report is invalid 1`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; exports[`manager/gradle extractPackageFile should return empty if there are no dependencies 1`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; exports[`manager/gradle extractPackageFile should return empty if there is no dependency report 1`] = ` Array [ - "gradle --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "gradle --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; @@ -155,7 +190,14 @@ Array [ exports[`manager/gradle extractPackageFile should return gradle dependencies 2`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; @@ -225,7 +267,14 @@ Array [ exports[`manager/gradle extractPackageFile should return gradle dependencies for build.gradle in subdirectories if there is gradlew in the same directory 2`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir/foo", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; @@ -354,7 +403,14 @@ Array [ exports[`manager/gradle extractPackageFile should return gradle.kts dependencies 2`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; @@ -362,23 +418,55 @@ exports[`manager/gradle extractPackageFile should return null and gradle should exports[`manager/gradle extractPackageFile should run gradlew through \`sh\` when available but not executable 1`] = ` Array [ - "sh gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "sh gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; exports[`manager/gradle extractPackageFile should throw registry failure if gradle execution fails 1`] = `[Error: registry-failure]`; -exports[`manager/gradle extractPackageFile should throw registry failure if gradle execution fails 2`] = `Array []`; +exports[`manager/gradle extractPackageFile should throw registry failure if gradle execution fails 2`] = ` +Array [ + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, +] +`; exports[`manager/gradle extractPackageFile should use docker even if gradlew is available 1`] = ` Array [ - "docker run --rm -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle gradle --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "docker run --rm -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle gradle --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": null, + }, + }, ] `; exports[`manager/gradle extractPackageFile should use docker if required 1`] = ` Array [ - "docker run --rm -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle gradle --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "docker run --rm -v \\"localDir\\":\\"localDir\\" -w \\"localDir\\" renovate/gradle gradle --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; @@ -425,7 +513,14 @@ Array [ exports[`manager/gradle extractPackageFile should use repositories only for current project 2`] = ` Array [ - "./gradlew --init-script renovate-plugin.gradle renovate", + Object { + "cmd": "./gradlew --init-script renovate-plugin.gradle renovate", + "options": Object { + "cwd": "localDir", + "encoding": "utf-8", + "timeout": 20000, + }, + }, ] `; diff --git a/test/manager/gradle/index.spec.ts b/test/manager/gradle/index.spec.ts index 0cd795a18bf65d99100258b8261b77bb2d319734..2a68572dc8022f248bdd5fcd7066a45050f5e137 100644 --- a/test/manager/gradle/index.spec.ts +++ b/test/manager/gradle/index.spec.ts @@ -4,6 +4,7 @@ import fsReal from 'fs'; import { exec as _exec } from 'child_process'; import * as manager from '../../../lib/manager/gradle'; import { platform as _platform, Platform } from '../../../lib/platform'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -19,61 +20,67 @@ const config = { }, }; +let processEnv; + const updatesDependenciesReport = fsReal.readFileSync( 'test/datasource/gradle/_fixtures/updatesReport.json', 'utf8' ); +const gradleOutput = { + stdout: 'gradle output', + stderr: '', +}; + describe('manager/gradle', () => { beforeEach(() => { jest.resetAllMocks(); + jest.resetModules(); + fs.readFile.mockResolvedValue(updatesDependenciesReport as any); fs.mkdir.mockResolvedValue(); fs.exists.mockResolvedValue(true); fs.access.mockResolvedValue(undefined); platform.getFile.mockResolvedValue('some content'); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); describe('extractPackageFile', () => { it('should return gradle dependencies', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const dependencies = await manager.extractAllPackageFiles(config, [ 'build.gradle', 'subproject/build.gradle', ]); expect(dependencies).toMatchSnapshot(); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return gradle.kts dependencies', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const dependencies = await manager.extractAllPackageFiles(config, [ 'build.gradle.kts', 'subproject/build.gradle.kts', ]); expect(dependencies).toMatchSnapshot(); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return empty if there are no dependencies', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); fs.readFile.mockResolvedValue(fsReal.readFileSync( 'test/datasource/gradle/_fixtures/updatesReportEmpty.json', @@ -84,28 +91,20 @@ describe('manager/gradle', () => { ]); expect(dependencies).toEqual([]); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should throw registry failure if gradle execution fails', async () => { - const commands = []; - exec.mockImplementation((cmd, _options, _callback) => { - throw new Error(); - }); + const execSnapshots = mockExecAll(exec, new Error()); await expect( manager.extractAllPackageFiles(config, ['build.gradle']) ).rejects.toMatchSnapshot(); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return empty if there is no dependency report', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); fs.exists.mockResolvedValue(false); const dependencies = await manager.extractAllPackageFiles(config, [ @@ -113,16 +112,11 @@ describe('manager/gradle', () => { ]); expect(dependencies).toEqual([]); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return empty if renovate report is invalid', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const renovateReport = ` Invalid JSON] @@ -133,16 +127,11 @@ describe('manager/gradle', () => { 'build.gradle', ]); expect(dependencies).toEqual([]); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should use repositories only for current project', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const multiProjectUpdatesReport = fsReal.readFileSync( 'test/datasource/gradle/_fixtures/MultiProjectUpdatesReport.json', @@ -154,16 +143,11 @@ describe('manager/gradle', () => { 'build.gradle', ]); expect(dependencies).toMatchSnapshot(); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should execute gradlew when available', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); await manager.extractAllPackageFiles(config, ['build.gradle']); @@ -174,16 +158,11 @@ describe('manager/gradle', () => { cwd: 'localDir', timeout: 20000, }); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should run gradlew through `sh` when available but not executable', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); fs.access.mockRejectedValue(undefined); await manager.extractAllPackageFiles(config, ['build.gradle']); @@ -195,16 +174,11 @@ describe('manager/gradle', () => { cwd: 'localDir', timeout: 20000, }); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return null and gradle should not be executed if no root build.gradle', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); fs.exists.mockResolvedValue(false); @@ -214,47 +188,32 @@ describe('manager/gradle', () => { ).toBeNull(); expect(exec).toHaveBeenCalledTimes(0); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should return gradle dependencies for build.gradle in subdirectories if there is gradlew in the same directory', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const dependencies = await manager.extractAllPackageFiles(config, [ 'foo/build.gradle', ]); expect(dependencies).toMatchSnapshot(); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should configure the renovate report plugin', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); await manager.extractAllPackageFiles(config, ['build.gradle']); expect(toUnix(fs.writeFile.mock.calls[0][0] as string)).toBe( 'localDir/renovate-plugin.gradle' ); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should use docker if required', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const configWithDocker = { binarySource: 'docker', @@ -263,16 +222,11 @@ describe('manager/gradle', () => { await manager.extractAllPackageFiles(configWithDocker, ['build.gradle']); expect(exec.mock.calls[0][0].includes('docker run')).toBe(true); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should use docker even if gradlew is available', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const configWithDocker = { binarySource: 'docker', @@ -282,18 +236,13 @@ describe('manager/gradle', () => { await manager.extractAllPackageFiles(configWithDocker, ['build.gradle']); expect(exec.mock.calls[0][0].includes('docker run')).toBe(true); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); }); describe('updateDependency', () => { it('should update an existing module dependency', () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const buildGradleContent = fsReal.readFileSync( 'test/datasource/gradle/_fixtures/build.gradle.example1', @@ -313,16 +262,11 @@ describe('manager/gradle', () => { expect(buildGradleContentUpdated).toMatch('cglib:cglib-nodep:3.2.8'); expect(buildGradleContentUpdated).not.toMatch('cglib:cglib-nodep:3.1'); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should update an existing plugin dependency', () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const buildGradleContent = ` plugins { @@ -351,16 +295,11 @@ describe('manager/gradle', () => { 'id "com.github.ben-manes.versions" version "0.20.0"' ); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('should update an existing plugin dependency with Kotlin DSL', () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'gradle output', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec, gradleOutput); const buildGradleContent = ` plugins { @@ -389,7 +328,7 @@ describe('manager/gradle', () => { 'id("com.github.ben-manes.versions") version "0.20.0"' ); - expect(commands.map(x => x.replace(/\\(\w)/g, '/$1'))).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); }); }); diff --git a/test/manager/mix/__snapshots__/artifacts.spec.ts.snap b/test/manager/mix/__snapshots__/artifacts.spec.ts.snap index 40d412327800ebf75a5daf2a26c87eba02979acc..c054de2c7672a1af774c8b8ec63715d98777a3ee 100644 --- a/test/manager/mix/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/mix/__snapshots__/artifacts.spec.ts.snap @@ -11,6 +11,18 @@ Array [ ] `; +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "mix deps.update plug", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + }, + }, +] +`; + exports[`.updateArtifacts() returns updated mix.lock 1`] = ` Array [ Object { @@ -22,4 +34,14 @@ Array [ ] `; -exports[`.updateArtifacts() returns updated mix.lock 2`] = `"docker run --rm -v /tmp/github/some/repo:/tmp/github/some/repo -w /tmp/github/some/repo renovate/mix mix deps.update plug"`; +exports[`.updateArtifacts() returns updated mix.lock 2`] = ` +Array [ + Object { + "cmd": "docker run --rm -v /tmp/github/some/repo:/tmp/github/some/repo -w /tmp/github/some/repo renovate/mix mix deps.update plug", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + }, + }, +] +`; diff --git a/test/manager/mix/artifacts.spec.ts b/test/manager/mix/artifacts.spec.ts index 351c7b9d6357889289a1bcf47d2734e76d90b201..fee2cfd0e5a9a8b703bfb13879d3c7ec09be3067 100644 --- a/test/manager/mix/artifacts.spec.ts +++ b/test/manager/mix/artifacts.spec.ts @@ -3,6 +3,7 @@ import { exec as _exec } from 'child_process'; import { platform as _platform } from '../../../lib/platform'; import { updateArtifacts } from '../../../lib/manager/mix'; import { mocked } from '../../util'; +import { mockExecAll } from '../../execUtil'; const fs: jest.Mocked<typeof _fs> = _fs as any; const exec: jest.Mock<typeof _exec> = _exec as any; @@ -16,9 +17,24 @@ const config = { localDir: '/tmp/github/some/repo', }; +let processEnv; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + jest.resetModules(); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('returns null if no mix.lock found', async () => { expect(await updateArtifacts('mix.exs', ['plug'], '', config)).toBeNull(); @@ -39,21 +55,14 @@ describe('.updateArtifacts()', () => { }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current mix.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockResolvedValueOnce('Current mix.lock' as any); expect(await updateArtifacts('mix.exs', ['plug'], '', config)).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated mix.lock', async () => { platform.getFile.mockResolvedValueOnce('Old mix.lock'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockResolvedValueOnce('New mix.lock' as any); expect( await updateArtifacts('mix.exs', ['plug'], '{}', { @@ -61,7 +70,7 @@ describe('.updateArtifacts()', () => { binarySource: 'docker', }) ).toMatchSnapshot(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { platform.getFile.mockResolvedValueOnce('Current mix.lock'); diff --git a/test/manager/pip_setup/__snapshots__/extract.spec.ts.snap b/test/manager/pip_setup/__snapshots__/extract.spec.ts.snap index edf76c1da3ae9f65c07372fb33389d3c8bc7dc7f..d7b56fcb7d751b484a2aa1fbf7334677d67ba411 100644 --- a/test/manager/pip_setup/__snapshots__/extract.spec.ts.snap +++ b/test/manager/pip_setup/__snapshots__/extract.spec.ts.snap @@ -4,8 +4,23 @@ exports[`lib/manager/pip_setup/extract getPythonAlias returns the python alias t exports[`lib/manager/pip_setup/extract getPythonAlias returns the python alias to use 2`] = ` Array [ - "python --version", - "python3 --version", - "python3.8 --version", + Object { + "cmd": "python --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3.8 --version", + "options": Object { + "encoding": "utf-8", + }, + }, ] `; diff --git a/test/manager/pip_setup/__snapshots__/index.spec.ts.snap b/test/manager/pip_setup/__snapshots__/index.spec.ts.snap index 1b142057153b55428bd7250f465bf14ad2aba1c2..50e6efd331cba1dcea4116a4df53a9c3f89eda9e 100644 --- a/test/manager/pip_setup/__snapshots__/index.spec.ts.snap +++ b/test/manager/pip_setup/__snapshots__/index.spec.ts.snap @@ -1,5 +1,164 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`lib/manager/pip_setup/index extractPackageFile() catches error 1`] = ` +Array [ + Object { + "cmd": "python --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3.8 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "<extract.py> \\"/tmp/folders/foobar.py\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "timeout": 5000, + }, + }, +] +`; + +exports[`lib/manager/pip_setup/index extractPackageFile() returns found deps (docker) 1`] = ` +Object { + "deps": Array [ + Object { + "currentValue": ">=3.1.13.0,<5.0", + "datasource": "pypi", + "depName": "celery", + "managerData": Object { + "lineNumber": 36, + }, + }, + Object { + "currentValue": ">=1.7", + "datasource": "pypi", + "depName": "logging_tree", + "managerData": Object { + "lineNumber": 39, + }, + }, + Object { + "currentValue": ">=2.2", + "datasource": "pypi", + "depName": "pygments", + "managerData": Object { + "lineNumber": 40, + }, + }, + Object { + "currentValue": ">=5.0", + "datasource": "pypi", + "depName": "psutil", + "managerData": Object { + "lineNumber": 41, + }, + }, + Object { + "currentValue": ">=3.0", + "datasource": "pypi", + "depName": "objgraph", + "managerData": Object { + "lineNumber": 42, + }, + }, + Object { + "currentValue": ">=1.11.23,<2.0", + "datasource": "pypi", + "depName": "django", + "managerData": Object { + "lineNumber": 45, + }, + }, + Object { + "currentValue": ">=0.11,<2.0", + "datasource": "pypi", + "depName": "flask", + "managerData": Object { + "lineNumber": 48, + }, + }, + Object { + "currentValue": ">=1.4,<2.0", + "datasource": "pypi", + "depName": "blinker", + "managerData": Object { + "lineNumber": 49, + }, + }, + Object { + "currentValue": ">=19.7.0,<20.0", + "datasource": "pypi", + "depName": "gunicorn", + "managerData": Object { + "lineNumber": 61, + }, + }, + Object { + "currentValue": ">=3.2.1,<4.0", + "datasource": "pypi", + "depName": "statsd", + "managerData": Object { + "lineNumber": 62, + }, + }, + Object { + "currentValue": ">=0.15.3,<0.16", + "datasource": "pypi", + "depName": "Werkzeug", + "managerData": Object { + "lineNumber": 62, + }, + }, + Object { + "currentValue": ">=2.10.0,<3.0", + "datasource": "pypi", + "depName": "requests", + "managerData": Object { + "lineNumber": 63, + }, + "skipReason": "ignored", + }, + Object { + "currentValue": ">=5.27.1,<7.0", + "datasource": "pypi", + "depName": "raven", + "managerData": Object { + "lineNumber": 64, + }, + }, + Object { + "currentValue": ">=0.15.2,<0.17", + "datasource": "pypi", + "depName": "future", + "managerData": Object { + "lineNumber": 65, + }, + }, + Object { + "currentValue": ">=1.0.16,<2.0", + "datasource": "pypi", + "depName": "ipaddress", + "managerData": Object { + "lineNumber": 66, + }, + }, + ], +} +`; + exports[`lib/manager/pip_setup/index extractPackageFile() returns found deps 1`] = ` Object { "deps": Array [ @@ -127,3 +286,65 @@ Object { ], } `; + +exports[`lib/manager/pip_setup/index extractPackageFile() returns found deps 2`] = ` +Array [ + Object { + "cmd": "python --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3.8 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "<extract.py> \\"test/manager/pip_setup/_fixtures/setup.py\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "timeout": 5000, + }, + }, +] +`; + +exports[`lib/manager/pip_setup/index extractPackageFile() should return null for invalid file 1`] = ` +Array [ + Object { + "cmd": "python --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "python3.8 --version", + "options": Object { + "encoding": "utf-8", + }, + }, + Object { + "cmd": "<extract.py> \\"/tmp/folders/foobar.py\\"", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "timeout": 5000, + }, + }, +] +`; diff --git a/test/manager/pip_setup/extract.spec.ts b/test/manager/pip_setup/extract.spec.ts index 49093ec7ba2574aa68e010da7e9e4601a64f3800..8504e422400ca726d12a64ff27ce589f2e8fc38a 100644 --- a/test/manager/pip_setup/extract.spec.ts +++ b/test/manager/pip_setup/extract.spec.ts @@ -6,15 +6,30 @@ import { getPythonAlias, pythonVersions, } from '../../../lib/manager/pip_setup/extract'; +import { mockExecSequence } from '../../execUtil'; const exec: jest.Mock<typeof _exec> = _exec as any; jest.mock('child_process'); +let processEnv; + describe('lib/manager/pip_setup/extract', () => { beforeEach(() => { jest.resetAllMocks(); jest.resetModules(); resetModule(); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); describe('parsePythonVersion', () => { it('returns major and minor version numbers', () => { @@ -23,25 +38,15 @@ describe('lib/manager/pip_setup/extract', () => { }); describe('getPythonAlias', () => { it('returns the python alias to use', async () => { - const commands = []; - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: '', stderr: 'Python 2.7.17\\n' }); - return undefined; - }); - exec.mockImplementationOnce((cmd, _options, _callback) => { - commands.push(cmd); - throw new Error(); - }); - exec.mockImplementationOnce((cmd, _options, callback) => { - commands.push(cmd); - callback(null, { stdout: 'Python 3.8.0\\n', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecSequence(exec, [ + { stdout: '', stderr: 'Python 2.7.17\\n' }, + new Error(), + { stdout: 'Python 3.8.0\\n', stderr: '' }, + ]); const result = await getPythonAlias(); expect(pythonVersions.includes(result)).toBe(true); expect(result).toMatchSnapshot(); - expect(commands).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); }); // describe('Test for presence of mock lib', () => { diff --git a/test/manager/pip_setup/index.spec.ts b/test/manager/pip_setup/index.spec.ts index 596f6b0e540c44b41ed4ea782f8db298b412d3c2..097bc5437b4ac7e45842faf66fa3243d81cefd8c 100644 --- a/test/manager/pip_setup/index.spec.ts +++ b/test/manager/pip_setup/index.spec.ts @@ -1,9 +1,8 @@ import { readFileSync } from 'fs'; import { exec as _exec } from 'child_process'; -import { file as _file } from 'tmp-promise'; -import { relative } from 'path'; import * as extract from '../../../lib/manager/pip_setup/extract'; import { extractPackageFile } from '../../../lib/manager/pip_setup'; +import { ExecSnapshots, mockExecAll, mockExecSequence } from '../../execUtil'; const packageFile = 'test/manager/pip_setup/_fixtures/setup.py'; const content = readFileSync(packageFile, 'utf8'); @@ -12,16 +11,26 @@ const packageFileJson = 'test/manager/pip_setup/_fixtures/setup.py.json'; const jsonContent = readFileSync(packageFileJson, 'utf8'); const config = { - localDir: '.', + localDir: '/tmp/github/some/repo', }; +let processEnv; + const exec: jest.Mock<typeof _exec> = _exec as any; jest.mock('child_process'); -async function tmpFile() { - const file = await _file({ postfix: '.py' }); - return relative('.', file.path); -} +const pythonVersionCallResults = [ + { stdout: '', stderr: 'Python 2.7.17\\n' }, + { stdout: 'Python 3.7.5\\n', stderr: '' }, + new Error(), +]; + +// TODO: figure out snapshot similarity for each CI platform +const fixSnapshots = (snapshots: ExecSnapshots): ExecSnapshots => + snapshots.map(snapshot => ({ + ...snapshot, + cmd: snapshot.cmd.replace(/^.*\/extract\.py"\s+/, '<extract.py> '), + })); describe('lib/manager/pip_setup/index', () => { describe('extractPackageFile()', () => { @@ -30,49 +39,68 @@ describe('lib/manager/pip_setup/index', () => { jest.resetModules(); extract.resetModule(); - exec.mockImplementationOnce((_cmd, _options, callback) => { - callback(null, { stdout: '', stderr: 'Python 2.7.17\\n' }); - return undefined; - }); - exec.mockImplementationOnce((_cmd, _options, callback) => { - callback(null, { stdout: 'Python 3.7.5\\n', stderr: '' }); - return undefined; - }); - exec.mockImplementationOnce((_cmd, _options, _callback) => { - throw new Error(); - }); + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('returns found deps', async () => { - exec.mockImplementationOnce((_cmd, _options, callback) => { - callback(null, { stdout: jsonContent, stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecSequence(exec, [ + ...pythonVersionCallResults, + { stdout: jsonContent, stderr: '' }, + ]); expect( await extractPackageFile(content, packageFile, config) ).toMatchSnapshot(); expect(exec).toHaveBeenCalledTimes(4); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); - it('should return null for invalid file', async () => { - exec.mockImplementationOnce((_cmd, _options, _callback) => { - throw new Error(); - }); + it('returns found deps (docker)', async () => { + const execSnapshots = mockExecSequence(exec, [ + { stdout: '', stderr: '' }, // docker pull + { stdout: jsonContent, stderr: '' }, + ]); expect( - await extractPackageFile('raise Exception()', await tmpFile(), config) + await extractPackageFile(content, packageFile, { + ...config, + binarySource: 'docker', + }) + ).toMatchSnapshot(); + expect(execSnapshots).toHaveLength(2); // TODO: figure out volume arguments in Windows + }); + it('should return null for invalid file', async () => { + const execSnapshots = mockExecSequence(exec, [ + ...pythonVersionCallResults, + new Error(), + ]); + expect( + await extractPackageFile( + 'raise Exception()', + '/tmp/folders/foobar.py', + config + ) ).toBeNull(); expect(exec).toHaveBeenCalledTimes(4); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('catches error', async () => { - jest.resetAllMocks(); - jest.resetModules(); - extract.resetModule(); - exec.mockImplementation((_cmd, _options, _callback) => { - throw new Error(); - }); + const execSnapshots = mockExecAll(exec, new Error()); expect( - await extractPackageFile('raise Exception()', await tmpFile(), config) + await extractPackageFile( + 'raise Exception()', + '/tmp/folders/foobar.py', + config + ) ).toBeNull(); - expect(exec).toHaveBeenCalledTimes(4); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); }); /* diff --git a/test/manager/pipenv/__snapshots__/artifacts.spec.ts.snap b/test/manager/pipenv/__snapshots__/artifacts.spec.ts.snap index 62306183153d4cec2c8ce1f6e9a6b2ba2fedd883..a03c90d07b2f844f76f67513c1e2a3dd6a0e8933 100644 --- a/test/manager/pipenv/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/pipenv/__snapshots__/artifacts.spec.ts.snap @@ -11,4 +11,62 @@ Array [ ] `; -exports[`.updateArtifacts() supports docker mode 1`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/pipenv\\":\\"/tmp/renovate/cache/others/pipenv\\" -e LC_ALL -e LANG -e PIPENV_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/pipenv pipenv lock"`; +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "pipenv lock", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + "PIPENV_CACHE_DIR": "/tmp/renovate/cache/others/pipenv", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated Pipfile.lock 1`] = ` +Array [ + Object { + "cmd": "pipenv lock", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + "PIPENV_CACHE_DIR": "/tmp/renovate/cache/others/pipenv", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() supports docker mode 1`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache/others/pipenv\\":\\"/tmp/renovate/cache/others/pipenv\\" -e LC_ALL -e LANG -e PIPENV_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/pipenv pipenv lock", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + "PIPENV_CACHE_DIR": "/tmp/renovate/cache/others/pipenv", + }, + }, + }, +] +`; diff --git a/test/manager/pipenv/artifacts.spec.ts b/test/manager/pipenv/artifacts.spec.ts index 15f1de78491a47314090cea87b862152a36c6cc6..3c58aadb160f722dbd6711d5bba22710e8112636 100644 --- a/test/manager/pipenv/artifacts.spec.ts +++ b/test/manager/pipenv/artifacts.spec.ts @@ -4,6 +4,7 @@ import * as pipenv from '../../../lib/manager/pipenv/artifacts'; import { platform as _platform } from '../../../lib/platform'; import { mocked } from '../../util'; import { StatusResult } from '../../../lib/platform/git/storage'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -18,50 +19,50 @@ const config = { cacheDir: '/tmp/renovate/cache', }; +const processEnv = process.env; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; }); afterEach(() => { - delete global.trustLevel; + process.env = processEnv; }); + it('returns if no Pipfile.lock found', async () => { expect(await pipenv.updateArtifacts('Pipfile', [], '', config)).toBeNull(); }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current Pipfile.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('Current Pipfile.lock' as any); expect( await pipenv.updateArtifacts('Pipfile', [], '{}', config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated Pipfile.lock', async () => { platform.getFile.mockResolvedValueOnce('Current Pipfile.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValue({ modified: ['Pipfile.lock'], } as StatusResult); fs.readFile.mockReturnValueOnce('New Pipfile.lock' as any); - global.trustLevel = 'high'; expect( await pipenv.updateArtifacts('Pipfile', [], '{}', config) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('supports docker mode', async () => { platform.getFile.mockResolvedValueOnce('Current Pipfile.lock'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); platform.getRepoStatus.mockResolvedValue({ modified: ['Pipfile.lock'], } as StatusResult); @@ -73,7 +74,7 @@ describe('.updateArtifacts()', () => { dockerUser: 'foobar', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { platform.getFile.mockResolvedValueOnce('Current Pipfile.lock'); diff --git a/test/manager/poetry/__snapshots__/artifacts.spec.ts.snap b/test/manager/poetry/__snapshots__/artifacts.spec.ts.snap index fc0d6ac02d138479652a520d56af9284371c284d..c093f262c65cdddfa78e62fc5f463a62607173d4 100644 --- a/test/manager/poetry/__snapshots__/artifacts.spec.ts.snap +++ b/test/manager/poetry/__snapshots__/artifacts.spec.ts.snap @@ -11,4 +11,59 @@ Array [ ] `; -exports[`.updateArtifacts() returns updated poetry.lock using docker 1`] = `"docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/poetry poetry update --lock --no-interaction dep1"`; +exports[`.updateArtifacts() returns null if unchanged 1`] = ` +Array [ + Object { + "cmd": "poetry update --lock --no-interaction dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated poetry.lock 1`] = ` +Array [ + Object { + "cmd": "poetry update --lock --no-interaction dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; + +exports[`.updateArtifacts() returns updated poetry.lock using docker 1`] = ` +Array [ + Object { + "cmd": "docker run --rm --user=foobar -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -w \\"/tmp/github/some/repo\\" renovate/poetry poetry update --lock --no-interaction dep1", + "options": Object { + "cwd": "/tmp/github/some/repo", + "encoding": "utf-8", + "env": Object { + "HOME": "/home/user", + "HTTPS_PROXY": "https://example.com", + "HTTP_PROXY": "http://example.com", + "NO_PROXY": "localhost", + "PATH": "/tmp/path", + }, + }, + }, +] +`; diff --git a/test/manager/poetry/artifacts.spec.ts b/test/manager/poetry/artifacts.spec.ts index 70df1be40e0a4f8761fc14dad25f056f3f1eb987..6c1e425edd8eb30b8adf54a2d3ee118237f65e45 100644 --- a/test/manager/poetry/artifacts.spec.ts +++ b/test/manager/poetry/artifacts.spec.ts @@ -3,6 +3,7 @@ import { exec as _exec } from 'child_process'; import { updateArtifacts } from '../../../lib/manager/poetry/artifacts'; import { platform as _platform } from '../../../lib/platform'; import { mocked } from '../../util'; +import { mockExecAll } from '../../execUtil'; jest.mock('fs-extra'); jest.mock('child_process'); @@ -15,12 +16,21 @@ const config = { localDir: '/tmp/github/some/repo', }; +const processEnv = process.env; + describe('.updateArtifacts()', () => { beforeEach(() => { jest.resetAllMocks(); + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; }); afterEach(() => { - delete global.trustLevel; + process.env = processEnv; }); it('returns null if no poetry.lock found', async () => { const updatedDeps = ['dep1']; @@ -33,40 +43,29 @@ describe('.updateArtifacts()', () => { }); it('returns null if unchanged', async () => { platform.getFile.mockResolvedValueOnce('Current poetry.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('Current poetry.lock' as any); const updatedDeps = ['dep1']; expect( await updateArtifacts('pyproject.toml', updatedDeps, '', config) ).toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated poetry.lock', async () => { platform.getFile.mockResolvedValueOnce('Old poetry.lock'); - exec.mockImplementationOnce((cmd, _options, callback) => { - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New poetry.lock' as any); const updatedDeps = ['dep1']; - global.trustLevel = 'high'; expect( await updateArtifacts('pyproject.toml', updatedDeps, '{}', config) ).not.toBeNull(); + expect(execSnapshots).toMatchSnapshot(); }); it('returns updated poetry.lock using docker', async () => { platform.getFile.mockResolvedValueOnce('Old poetry.lock'); - let dockerCommand = null; - exec.mockImplementationOnce((cmd, _options, callback) => { - dockerCommand = cmd; - callback(null, { stdout: '', stderr: '' }); - return undefined; - }); + const execSnapshots = mockExecAll(exec); fs.readFile.mockReturnValueOnce('New poetry.lock' as any); const updatedDeps = ['dep1']; - global.trustLevel = 'high'; expect( await updateArtifacts('pyproject.toml', updatedDeps, '{}', { ...config, @@ -74,7 +73,7 @@ describe('.updateArtifacts()', () => { dockerUser: 'foobar', }) ).not.toBeNull(); - expect(dockerCommand.replace(/\\(\w)/g, '/$1')).toMatchSnapshot(); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { platform.getFile.mockResolvedValueOnce('Current poetry.lock'); diff --git a/test/workers/branch/lock-files/__snapshots__/lerna.spec.ts.snap b/test/workers/branch/lock-files/__snapshots__/lerna.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..52b590332c64c5be3c0822d27bd055d5a6bc33de --- /dev/null +++ b/test/workers/branch/lock-files/__snapshots__/lerna.spec.ts.snap @@ -0,0 +1,53 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLockFiles() defaults to latest 1`] = ` +Array [ + Object { + "cmd": "npm i -g -C ~/.npm/lerna@latest lerna@latest && npm install --package-lock-only --no-audit && ~/.npm/lerna@latest/bin/lerna bootstrap --no-ci -- --package-lock-only --no-audit", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFiles() generates package-lock.json files 1`] = ` +Array [ + Object { + "cmd": "npm i -g -C ~/.npm/lerna@2.0.0 lerna@2.0.0 && npm install --package-lock-only --no-audit && ~/.npm/lerna@2.0.0/bin/lerna bootstrap --no-ci -- --package-lock-only --no-audit", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFiles() generates yarn.lock files 1`] = ` +Array [ + Object { + "cmd": "npm i -g -C ~/.npm/lerna@2.0.0 lerna@2.0.0 && yarn install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879 && ~/.npm/lerna@2.0.0/bin/lerna bootstrap --no-ci -- --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFiles() performs full npm install 1`] = ` +Array [ + Object { + "cmd": "npm install --ignore-scripts --no-audit && lerna bootstrap --no-ci -- --ignore-scripts --no-audit", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; diff --git a/test/workers/branch/lock-files/__snapshots__/npm.spec.ts.snap b/test/workers/branch/lock-files/__snapshots__/npm.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..b85c9f10518e985e64ba3a5ddc97892b17499c53 --- /dev/null +++ b/test/workers/branch/lock-files/__snapshots__/npm.spec.ts.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLockFile catches errors 1`] = `Array []`; + +exports[`generateLockFile finds npm embedded in renovate 1`] = `Array []`; + +exports[`generateLockFile finds npm globally 1`] = `Array []`; + +exports[`generateLockFile generates lock files 1`] = ` +Array [ + Object { + "cmd": "node node_modules/npm/bin/npm-cli.js dedupe", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFile performs full install 1`] = `Array []`; + +exports[`generateLockFile performs lock file updates 1`] = ` +Array [ + Object { + "cmd": "node node_modules/npm/bin/npm-cli.js install --package-lock-only --no-audit some-dep@1.0.1", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFile performs npm-shrinkwrap.json updates (no package-lock.json) 1`] = `Array []`; + +exports[`generateLockFile performs npm-shrinkwrap.json updates 1`] = `Array []`; + +exports[`generateLockFile uses fallback npm 1`] = `Array []`; diff --git a/test/workers/branch/lock-files/__snapshots__/pnpm.spec.ts.snap b/test/workers/branch/lock-files/__snapshots__/pnpm.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..00f4127041c57814bc967ab3603423d7e8760afa --- /dev/null +++ b/test/workers/branch/lock-files/__snapshots__/pnpm.spec.ts.snap @@ -0,0 +1,79 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLockFile catches errors 1`] = ` +Array [ + Object { + "cmd": "node node_modules/pnpm/lib/bin/pnpm.js install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile finds pnpm embedded in renovate 1`] = ` +Array [ + Object { + "cmd": "node /node_modules/renovate/node_modules/pnpm/lib/bin/pnpm.js install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile finds pnpm globally 1`] = ` +Array [ + Object { + "cmd": "node /node_modules/pnpm/lib/bin/pnpm.js install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile generates lock files 1`] = ` +Array [ + Object { + "cmd": "node node_modules/pnpm/lib/bin/pnpm.js install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile uses docker pnpm 1`] = ` +Array [ + Object { + "cmd": "docker run --rm -v \\"some-dir\\":\\"some-dir\\" -v \\"some-cache-dir\\":\\"some-cache-dir\\" -e NPM_CONFIG_CACHE -e npm_config_store -w \\"some-dir\\" renovate/pnpm pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile uses fallback pnpm 1`] = ` +Array [ + Object { + "cmd": "pnpm install --lockfile-only --ignore-scripts --ignore-pnpmfile", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; diff --git a/test/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap b/test/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..ab92f675a38d15bcc46e5706a4f61ac08107350d --- /dev/null +++ b/test/workers/branch/lock-files/__snapshots__/yarn.spec.ts.snap @@ -0,0 +1,124 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateLockFile catches errors 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile detects yarnIntegrity 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, + Object { + "cmd": "<yarn> upgrade some-dep --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFile finds yarn embedded in renovate 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile finds yarn globally 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; + +exports[`generateLockFile generates lock files 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, + Object { + "cmd": "npx yarn-deduplicate@1.1.1 --strategy fewer && yarn", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, + Object { + "cmd": "npx yarn-deduplicate@1.1.1 --strategy highest && yarn", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFile performs lock file updates 1`] = ` +Array [ + Object { + "cmd": "<yarn> install --ignore-scripts --ignore-engines --ignore-platform --mutex file:/tmp/yarn.mutext", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, + Object { + "cmd": "<yarn> upgrade some-dep --ignore-scripts --ignore-engines --ignore-platform --mutex file:/tmp/yarn.mutext", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": Object {}, + }, + }, +] +`; + +exports[`generateLockFile uses fallback yarn 1`] = ` +Array [ + Object { + "cmd": "yarn install --ignore-scripts --ignore-engines --ignore-platform --mutex network:31879", + "options": Object { + "cwd": "some-dir", + "encoding": "utf-8", + "env": null, + }, + }, +] +`; diff --git a/test/workers/branch/lock-files/lerna.spec.ts b/test/workers/branch/lock-files/lerna.spec.ts index 4efabd08485f5e721cdb6ee145d6360df8540394..806ed0f74489fad3c610d40fa5200e99c1e179f3 100644 --- a/test/workers/branch/lock-files/lerna.spec.ts +++ b/test/workers/branch/lock-files/lerna.spec.ts @@ -1,15 +1,19 @@ -import * as _exec from '../../../../lib/util/exec'; +import { exec as _exec } from 'child_process'; import * as _lernaHelper from '../../../../lib/manager/npm/post-update/lerna'; import { platform as _platform } from '../../../../lib/platform'; import { mocked } from '../../../util'; +import { mockExecAll } from '../../../execUtil'; -jest.mock('../../../../lib/util/exec'); +jest.mock('child_process'); -const exec = mocked(_exec).exec; +const exec: jest.Mock<typeof _exec> = _exec as any; const lernaHelper = mocked(_lernaHelper); const platform = mocked(_platform); describe('generateLockFiles()', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); it('returns if no lernaClient', async () => { const res = await lernaHelper.generateLockFiles(undefined, 'some-dir', {}); expect(res.error).toBe(false); @@ -18,7 +22,7 @@ describe('generateLockFiles()', () => { platform.getFile.mockResolvedValueOnce( JSON.stringify({ dependencies: { lerna: '2.0.0' } }) ); - exec.mockResolvedValueOnce({} as never); + const execSnapshots = mockExecAll(exec); const skipInstalls = true; const res = await lernaHelper.generateLockFiles( 'npm', @@ -27,12 +31,13 @@ describe('generateLockFiles()', () => { skipInstalls ); expect(res.error).toBe(false); + expect(execSnapshots).toMatchSnapshot(); }); it('performs full npm install', async () => { platform.getFile.mockResolvedValueOnce( JSON.stringify({ dependencies: { lerna: '2.0.0' } }) ); - exec.mockResolvedValueOnce({} as never); + const execSnapshots = mockExecAll(exec); const skipInstalls = false; const binarySource = 'global'; const res = await lernaHelper.generateLockFiles( @@ -43,19 +48,22 @@ describe('generateLockFiles()', () => { binarySource ); expect(res.error).toBe(false); + expect(execSnapshots).toMatchSnapshot(); }); it('generates yarn.lock files', async () => { platform.getFile.mockResolvedValueOnce( JSON.stringify({ devDependencies: { lerna: '2.0.0' } }) ); - exec.mockResolvedValueOnce({} as never); + const execSnapshots = mockExecAll(exec); const res = await lernaHelper.generateLockFiles('yarn', 'some-dir', {}); expect(res.error).toBe(false); + expect(execSnapshots).toMatchSnapshot(); }); it('defaults to latest', async () => { platform.getFile.mockReturnValueOnce(undefined); - exec.mockResolvedValueOnce({} as never); + const execSnapshots = mockExecAll(exec); const res = await lernaHelper.generateLockFiles('npm', 'some-dir', {}); expect(res.error).toBe(false); + expect(execSnapshots).toMatchSnapshot(); }); }); diff --git a/test/workers/branch/lock-files/npm.spec.ts b/test/workers/branch/lock-files/npm.spec.ts index 2cfcc7e81412dfd6464dc20fd6a65f6b76142950..d2867ec6f5dfb105b898c41622229d25308036bc 100644 --- a/test/workers/branch/lock-files/npm.spec.ts +++ b/test/workers/branch/lock-files/npm.spec.ts @@ -1,29 +1,26 @@ import { getInstalledPath } from 'get-installed-path'; import path from 'path'; import _fs from 'fs-extra'; -import * as _exec from '../../../../lib/util/exec'; +import { exec as _exec } from 'child_process'; import * as npmHelper from '../../../../lib/manager/npm/post-update/npm'; import { mocked } from '../../../util'; +import { mockExecAll } from '../../../execUtil'; jest.mock('fs-extra'); -jest.mock('../../../../lib/util/exec'); +jest.mock('child_process'); jest.mock('get-installed-path'); getInstalledPath.mockImplementation(() => null); -const exec = mocked(_exec).exec; +const exec: jest.Mock<typeof _exec> = _exec as any; const fs = mocked(_fs); describe('generateLockFile', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); it('generates lock files', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const skipInstalls = true; const postUpdateOptions = ['npmDedupe']; @@ -36,17 +33,11 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBeUndefined(); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('performs lock file updates', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const skipInstalls = true; const updates = [ @@ -62,17 +53,11 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBeUndefined(); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('performs npm-shrinkwrap.json updates', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.pathExists.mockImplementationOnce(() => true); fs.move = jest.fn(); fs.readFile = jest.fn(() => 'package-lock-contents') as never; @@ -98,17 +83,11 @@ describe('generateLockFile', () => { ); expect(res.error).toBeUndefined(); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('performs npm-shrinkwrap.json updates (no package-lock.json)', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.pathExists.mockImplementationOnce(() => false); fs.move = jest.fn(); fs.readFile = jest.fn((_, _1) => 'package-lock-contents') as never; @@ -130,13 +109,11 @@ describe('generateLockFile', () => { ); expect(res.error).toBeUndefined(); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('performs full install', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const skipInstalls = false; const binarySource = 'global'; @@ -149,13 +126,11 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBeUndefined(); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { getInstalledPath.mockReturnValueOnce('node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: 'some-error', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => { throw new Error('not found'); }) as never; @@ -167,6 +142,7 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBe(true); expect(res.lockFile).not.toBeDefined(); + expect(execSnapshots).toMatchSnapshot(); }); it('finds npm embedded in renovate', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -176,10 +152,7 @@ describe('generateLockFile', () => { getInstalledPath.mockImplementationOnce( () => '/node_modules/renovate/node_modules/npm' ); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await npmHelper.generateLockFile( 'some-dir', @@ -188,6 +161,7 @@ describe('generateLockFile', () => { ); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('finds npm globally', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -198,10 +172,7 @@ describe('generateLockFile', () => { throw new Error('not found'); }); getInstalledPath.mockImplementationOnce(() => '/node_modules/npm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await npmHelper.generateLockFile( 'some-dir', @@ -210,6 +181,7 @@ describe('generateLockFile', () => { ); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('uses fallback npm', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -222,10 +194,7 @@ describe('generateLockFile', () => { getInstalledPath.mockImplementationOnce(() => { throw new Error('not found'); }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await npmHelper.generateLockFile( 'some-dir', @@ -234,5 +203,6 @@ describe('generateLockFile', () => { ); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); }); diff --git a/test/workers/branch/lock-files/pnpm.spec.ts b/test/workers/branch/lock-files/pnpm.spec.ts index 755771c749e6ad6ff893e48f14c7e24541f7073f..2aeb9cc305ba907c116af212d524998125e6ffe6 100644 --- a/test/workers/branch/lock-files/pnpm.spec.ts +++ b/test/workers/branch/lock-files/pnpm.spec.ts @@ -1,54 +1,62 @@ import { getInstalledPath } from 'get-installed-path'; import _fs from 'fs-extra'; -import * as _exec from '../../../../lib/util/exec'; +import { exec as _exec } from 'child_process'; import { mocked } from '../../../util'; import * as _pnpmHelper from '../../../../lib/manager/npm/post-update/pnpm'; +import { mockExecAll } from '../../../execUtil'; jest.mock('fs-extra'); -jest.mock('../../../../lib/util/exec'); +jest.mock('child_process'); jest.mock('get-installed-path'); getInstalledPath.mockImplementation(() => null); -const exec = mocked(_exec).exec; +const exec: jest.Mock<typeof _exec> = _exec as any; const fs = mocked(_fs); const pnpmHelper = mocked(_pnpmHelper); +let processEnv; + describe('generateLockFile', () => { let env; let config; beforeEach(() => { config = { cacheDir: 'some-cache-dir' }; + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('generates lock files', async () => { getInstalledPath.mockReturnValueOnce('node_modules/pnpm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await pnpmHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('uses docker pnpm', async () => { getInstalledPath.mockReturnValueOnce('node_modules/pnpm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; config.binarySource = 'docker'; const res = await pnpmHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('catches errors', async () => { getInstalledPath.mockReturnValueOnce('node_modules/pnpm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: 'some-error', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => { throw new Error('not found'); }) as never; @@ -56,6 +64,7 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBe(true); expect(res.lockFile).not.toBeDefined(); + expect(execSnapshots).toMatchSnapshot(); }); it('finds pnpm embedded in renovate', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -65,14 +74,12 @@ describe('generateLockFile', () => { getInstalledPath.mockImplementationOnce( () => '/node_modules/renovate/node_modules/pnpm' ); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await pnpmHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('finds pnpm globally', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -83,14 +90,12 @@ describe('generateLockFile', () => { throw new Error('not found'); }); getInstalledPath.mockImplementationOnce(() => '/node_modules/pnpm'); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const res = await pnpmHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); it('uses fallback pnpm', async () => { getInstalledPath.mockImplementationOnce(() => { @@ -103,14 +108,12 @@ describe('generateLockFile', () => { getInstalledPath.mockImplementationOnce(() => { throw new Error('not found'); }); - exec.mockResolvedValueOnce({ - stdout: '', - stderr: '', - }); + const execSnapshots = mockExecAll(exec); fs.readFile = jest.fn(() => 'package-lock-contents') as never; config.binarySource = 'global'; const res = await pnpmHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(execSnapshots).toMatchSnapshot(); }); }); diff --git a/test/workers/branch/lock-files/yarn.spec.ts b/test/workers/branch/lock-files/yarn.spec.ts index 8000617f5585c3d5d64568ab2cdfa615a7fb3d90..5e4c9cc3bb587e26a4f9840052c12de07d828824 100644 --- a/test/workers/branch/lock-files/yarn.spec.ts +++ b/test/workers/branch/lock-files/yarn.spec.ts @@ -1,29 +1,48 @@ import { getInstalledPath } from 'get-installed-path'; import _fs from 'fs-extra'; -import * as _exec from '../../../../lib/util/exec'; +import { exec as _exec } from 'child_process'; import * as _yarnHelper from '../../../../lib/manager/npm/post-update/yarn'; import { mocked } from '../../../util'; +import { ExecSnapshots, mockExecAll } from '../../../execUtil'; jest.mock('fs-extra'); -jest.mock('../../../../lib/util/exec'); +jest.mock('child_process'); jest.mock('get-installed-path'); getInstalledPath.mockImplementation(() => null); -const exec = mocked(_exec).exec; +const exec: jest.Mock<typeof _exec> = _exec as any; const fs = mocked(_fs); const yarnHelper = mocked(_yarnHelper); +let processEnv; + +// TODO: figure out snapshot similarity for each CI platform +const fixSnapshots = (snapshots: ExecSnapshots): ExecSnapshots => + snapshots.map(snapshot => ({ + ...snapshot, + cmd: snapshot.cmd.replace(/^.*\/yarn.*?\.js\s+/, '<yarn> '), + })); + describe('generateLockFile', () => { beforeEach(() => { delete process.env.YARN_MUTEX_FILE; jest.resetAllMocks(); - exec.mockResolvedValue({ - stdout: '', - stderr: '', - }); + + processEnv = process.env; + process.env = { + HTTP_PROXY: 'http://example.com', + HTTPS_PROXY: 'https://example.com', + NO_PROXY: 'localhost', + HOME: '/home/user', + PATH: '/tmp/path', + }; + }); + afterEach(() => { + process.env = processEnv; }); it('generates lock files', async () => { + const execSnapshots = mockExecAll(exec); getInstalledPath.mockReturnValueOnce('node_modules/yarn'); fs.readFile = jest.fn(() => 'package-lock-contents') as never; /** @type {NodeJS.ProcessEnv} */ @@ -34,8 +53,11 @@ describe('generateLockFile', () => { const res = await yarnHelper.generateLockFile('some-dir', env, config); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('performs lock file updates', async () => { + const execSnapshots = mockExecAll(exec); + getInstalledPath.mockReturnValueOnce('node_modules/yarn'); fs.readFile = jest.fn(() => 'package-lock-contents') as never; @@ -44,8 +66,11 @@ describe('generateLockFile', () => { { depName: 'some-dep', isLockfileUpdate: true }, ]); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('detects yarnIntegrity', async () => { + const execSnapshots = mockExecAll(exec); + getInstalledPath.mockReturnValueOnce('node_modules/yarn'); fs.readFile = jest.fn(() => 'package-lock-contents') as never; const config = { @@ -55,10 +80,11 @@ describe('generateLockFile', () => { { depName: 'some-dep', isLockfileUpdate: true }, ]); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('catches errors', async () => { getInstalledPath.mockReturnValueOnce('node_modules/yarn'); - exec.mockResolvedValueOnce({ + const execSnapshots = mockExecAll(exec, { stdout: '', stderr: 'some-error', }); @@ -69,8 +95,10 @@ describe('generateLockFile', () => { expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.error).toBe(true); expect(res.lockFile).not.toBeDefined(); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('finds yarn embedded in renovate', async () => { + const execSnapshots = mockExecAll(exec); getInstalledPath.mockImplementationOnce(() => { throw new Error('not found'); }); @@ -82,8 +110,10 @@ describe('generateLockFile', () => { const res = await yarnHelper.generateLockFile('some-dir'); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('finds yarn globally', async () => { + const execSnapshots = mockExecAll(exec); getInstalledPath.mockImplementationOnce(() => { throw new Error('not found'); }); @@ -96,8 +126,10 @@ describe('generateLockFile', () => { const res = await yarnHelper.generateLockFile('some-dir'); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); it('uses fallback yarn', async () => { + const execSnapshots = mockExecAll(exec); getInstalledPath.mockImplementationOnce(() => { throw new Error('not found'); }); @@ -114,5 +146,6 @@ describe('generateLockFile', () => { }); expect(fs.readFile).toHaveBeenCalledTimes(1); expect(res.lockFile).toEqual('package-lock-contents'); + expect(fixSnapshots(execSnapshots)).toMatchSnapshot(); }); });