Skip to content
Snippets Groups Projects
Unverified Commit a56e0de4 authored by Rhys Arkins's avatar Rhys Arkins Committed by GitHub
Browse files

feat: move localDir awareness to util/exec (#5207)

parent 520429f1
Branches
Tags
No related merge requests found
import is from '@sindresorhus/is';
import { parse, join } from 'upath';
import { outputFile, readFile } from 'fs-extra';
import { exec, ExecOptions } from '../../util/exec';
import { logger } from '../../logger';
import { UpdateArtifact, UpdateArtifactsResult } from '../common';
import { platform } from '../../platform';
import {
getSiblingFileName,
getSubDirectory,
readLocalFile,
writeLocalFile,
} from '../../util/fs';
export async function updateArtifacts({
packageFileName,
updatedDeps,
newPackageFileContent,
config,
}: UpdateArtifact): Promise<UpdateArtifactsResult[] | null> {
logger.debug(`poetry.updateArtifacts(${packageFileName})`);
if (!is.nonEmptyArray(updatedDeps)) {
logger.debug('No updated poetry deps - returning null');
return null;
}
const subDirectory = parse(packageFileName).dir;
let lockFileName = join(subDirectory, 'poetry.lock');
let existingLockFileContent = await platform.getFile(lockFileName);
const subDirectory = getSubDirectory(packageFileName);
// Try poetry.lock first
let lockFileName = getSiblingFileName(packageFileName, 'poetry.lock');
let existingLockFileContent = await readLocalFile(lockFileName);
if (!existingLockFileContent) {
lockFileName = join(subDirectory, 'pyproject.lock');
existingLockFileContent = await platform.getFile(lockFileName);
// Try pyproject.lock next
lockFileName = getSiblingFileName(packageFileName, 'pyproject.lock');
existingLockFileContent = await readLocalFile(lockFileName);
if (!existingLockFileContent) {
logger.debug(`No lock file found`);
return null;
}
}
logger.debug(`Updating ${lockFileName}`);
const localPackageFileName = join(config.localDir, packageFileName);
const localLockFileName = join(config.localDir, lockFileName);
try {
await outputFile(localPackageFileName, newPackageFileContent);
await writeLocalFile(packageFileName, newPackageFileContent);
const cmd: string[] = [];
for (let i = 0; i < updatedDeps.length; i += 1) {
const dep = updatedDeps[i];
cmd.push(`poetry update --lock --no-interaction ${dep}`);
}
const execOptions: ExecOptions = {
cwd: join(config.localDir, subDirectory),
subDirectory,
docker: { image: 'renovate/poetry' },
};
await exec(cmd, execOptions);
const newPoetryLockContent = await readFile(localLockFileName, 'utf8');
const newPoetryLockContent = await readLocalFile(lockFileName);
if (existingLockFileContent === newPoetryLockContent) {
logger.debug(`${lockFileName} is unchanged`);
return null;
......
import { join } from 'path';
import { hrtime } from 'process';
import { promisify } from 'util';
import {
......@@ -32,6 +33,7 @@ const pExec: (
type ExtraEnv<T = unknown> = Record<string, T>;
export interface ExecOptions extends ChildProcessExecOptions {
subDirectory?: string;
extraEnv?: Opt<ExtraEnv>;
docker?: Opt<DockerOptions>;
}
......@@ -77,13 +79,19 @@ export async function exec(
cmd: string | string[],
opts: ExecOptions = {}
): Promise<ExecResult> {
const { env, extraEnv, docker } = opts;
const cwd = opts.cwd || execConfig.localDir;
const { env, extraEnv, docker, subDirectory } = opts;
let cwd;
// istanbul ignore if
if (subDirectory) {
cwd = join(execConfig.localDir, subDirectory);
}
cwd = cwd || opts.cwd || execConfig.localDir;
const childEnv = createChildEnv(env, extraEnv);
const execOptions: ExecOptions = { ...opts };
delete execOptions.extraEnv;
delete execOptions.docker;
delete execOptions.subDirectory;
const pExecOptions: ChildProcessExecOptions & { encoding: string } = {
encoding: 'utf-8',
......
import { parse, join } from 'upath';
import { outputFile, readFile } from 'fs-extra';
import { logger } from '../logger';
let localDir = '';
export function setFsConfig(config: any): void {
localDir = config.localDir;
}
export function getSubDirectory(fileName: string): string {
return parse(fileName).dir;
}
export function getSiblingFileName(
existingFileNameWithPath: string,
otherFileName: string
): string {
const subDirectory = getSubDirectory(existingFileNameWithPath);
return join(subDirectory, otherFileName);
}
export async function readLocalFile(fileName: string): Promise<string> {
const localFileName = join(localDir, fileName);
try {
const fileContent = await readFile(localFileName, 'utf8');
return fileContent;
} catch (err) /* istanbul ignore next */ {
logger.trace({ err }, 'Error reading local file');
return null;
}
}
export async function writeLocalFile(
fileName: string,
fileContent: string
): Promise<void> {
const localFileName = join(localDir, fileName);
await outputFile(localFileName, fileContent);
}
import { setExecConfig } from './exec';
import { setFsConfig } from './fs';
export function setUtilConfig(config: any): void {
setExecConfig(config);
setFsConfig(config);
}
......@@ -12,7 +12,7 @@ import { initPlatform } from '../../platform';
import * as hostRules from '../../util/host-rules';
import { printStats } from '../../util/got/stats';
import * as limits from './limits';
import { setExecConfig } from '../../util/exec';
import { setUtilConfig } from '../../util';
type RenovateConfig = configParser.RenovateConfig;
type RenovateRepository = configParser.RenovateRepository;
......@@ -77,7 +77,7 @@ export async function start(): Promise<0 | 1> {
break;
}
const repoConfig = await getRepositoryConfig(config, repository);
setExecConfig(repoConfig);
setUtilConfig(repoConfig);
if (repoConfig.hostRules) {
hostRules.clear();
repoConfig.hostRules.forEach(rule => hostRules.add(rule));
......
......@@ -2,7 +2,6 @@ import { join } from 'upath';
import _fs from 'fs-extra';
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 { envMock, mockExecAll } from '../../execUtil';
import * as _env from '../../../lib/util/exec/env';
......@@ -16,7 +15,6 @@ jest.mock('../../../lib/util/exec/env');
const fs: jest.Mocked<typeof _fs> = _fs as any;
const exec: jest.Mock<typeof _exec> = _exec as any;
const env = mocked(_env);
const platform = mocked(_platform);
const config = {
localDir: join('/tmp/github/some/repo'),
......@@ -50,7 +48,7 @@ describe('.updateArtifacts()', () => {
).toBeNull();
});
it('returns null if unchanged', async () => {
platform.getFile.mockResolvedValueOnce('Current poetry.lock');
fs.readFile.mockReturnValueOnce('Current poetry.lock' as any);
const execSnapshots = mockExecAll(exec);
fs.readFile.mockReturnValueOnce('Current poetry.lock' as any);
const updatedDeps = ['dep1'];
......@@ -65,7 +63,7 @@ describe('.updateArtifacts()', () => {
expect(execSnapshots).toMatchSnapshot();
});
it('returns updated poetry.lock', async () => {
platform.getFile.mockResolvedValueOnce('Old poetry.lock');
fs.readFile.mockResolvedValueOnce('Old poetry.lock' as any);
const execSnapshots = mockExecAll(exec);
fs.readFile.mockReturnValueOnce('New poetry.lock' as any);
const updatedDeps = ['dep1'];
......@@ -85,7 +83,7 @@ describe('.updateArtifacts()', () => {
binarySource: BinarySource.Docker,
dockerUser: 'foobar',
});
platform.getFile.mockResolvedValueOnce('Old poetry.lock');
fs.readFile.mockResolvedValueOnce('Old poetry.lock' as any);
const execSnapshots = mockExecAll(exec);
fs.readFile.mockReturnValueOnce('New poetry.lock' as any);
const updatedDeps = ['dep1'];
......@@ -102,7 +100,7 @@ describe('.updateArtifacts()', () => {
expect(execSnapshots).toMatchSnapshot();
});
it('catches errors', async () => {
platform.getFile.mockResolvedValueOnce('Current poetry.lock');
fs.readFile.mockResolvedValueOnce('Current poetry.lock' as any);
fs.outputFile.mockImplementationOnce(() => {
throw new Error('not found');
});
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment