Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(manager/pep621): support pdm lock files #22244

Merged
merged 5 commits into from May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
105 changes: 105 additions & 0 deletions lib/modules/manager/pep621/artifacts.spec.ts
@@ -0,0 +1,105 @@
import { join } from 'upath';
import { mockExecAll } from '../../../../test/exec-util';
import { fs, mockedFunction } from '../../../../test/util';
import { GlobalConfig } from '../../../config/global';
import type { RepoGlobalConfig } from '../../../config/types';
import { getPkgReleases as _getPkgReleases } from '../../datasource';
import type { UpdateArtifactsConfig } from '../types';
import { updateArtifacts } from './artifacts';

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

const getPkgReleases = mockedFunction(_getPkgReleases);

const config: UpdateArtifactsConfig = {};
const adminConfig: RepoGlobalConfig = {
localDir: join('/tmp/github/some/repo'),
cacheDir: join('/tmp/cache'),
containerbaseDir: join('/tmp/cache/containerbase'),
};

describe('modules/manager/pep621/artifacts', () => {
describe('updateArtifacts()', () => {
it('return null if all processors returns are empty', async () => {
const updatedDeps = [
{
packageName: 'dep1',
},
];
const result = await updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config,
updatedDeps,
});
expect(result).toBeNull();
});

it('return processor result', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
fs.readLocalFile.mockResolvedValueOnce('old test content');
fs.readLocalFile.mockResolvedValueOnce('new test content');
// pdm
getPkgReleases.mockResolvedValueOnce({
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
});

const updatedDeps = [{ packageName: 'dep1' }];
const result = await updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config: {},
updatedDeps,
});
expect(result).toEqual([
{
file: {
contents: 'new test content',
path: 'pdm.lock',
type: 'addition',
},
},
]);
expect(execSnapshots).toMatchObject([
{
cmd: 'docker pull containerbase/sidecar',
options: {
encoding: 'utf-8',
},
},
{
cmd: 'docker ps --filter name=renovate_sidecar -aq',
options: {
encoding: 'utf-8',
},
},
{
cmd:
'docker run --rm --name=renovate_sidecar --label=renovate_child ' +
'-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' +
'-v "/tmp/cache":"/tmp/cache" ' +
'-e BUILDPACK_CACHE_DIR ' +
'-e CONTAINERBASE_CACHE_DIR ' +
'-w "/tmp/github/some/repo" ' +
'containerbase/sidecar ' +
'bash -l -c "' +
'install-tool pdm v2.5.0 ' +
'&& ' +
'pdm update dep1' +
'"',
options: {
cwd: '/tmp/github/some/repo',
encoding: 'utf-8',
env: {
BUILDPACK_CACHE_DIR: '/tmp/cache/containerbase',
CONTAINERBASE_CACHE_DIR: '/tmp/cache/containerbase',
},
},
},
]);
});
});
});
23 changes: 23 additions & 0 deletions lib/modules/manager/pep621/artifacts.ts
@@ -0,0 +1,23 @@
import is from '@sindresorhus/is';
import { writeLocalFile } from '../../../util/fs';
import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
import { processors } from './processors';

export async function updateArtifacts(
updateArtifact: UpdateArtifact
): Promise<UpdateArtifactsResult[] | null> {
const { packageFileName, newPackageFileContent } = updateArtifact;

await writeLocalFile(packageFileName, newPackageFileContent);
secustor marked this conversation as resolved.
Show resolved Hide resolved

// process specific tool sets
const result: UpdateArtifactsResult[] = [];
for (const processor of processors) {
const artifactUpdates = await processor.updateArtifacts(updateArtifact);
if (is.array(artifactUpdates)) {
result.push(...artifactUpdates);
}
}

return result.length > 0 ? result : null;
}
3 changes: 3 additions & 0 deletions lib/modules/manager/pep621/index.ts
@@ -1,8 +1,11 @@
import { PypiDatasource } from '../../datasource/pypi';
export { extractPackageFile } from './extract';
export { updateArtifacts } from './artifacts';

export const supportedDatasources = [PypiDatasource.id];

export const supportsLockFileMaintenance = true;

export const defaultConfig = {
fileMatch: ['(^|/)pyproject\\.toml$'],
};
172 changes: 172 additions & 0 deletions lib/modules/manager/pep621/processors/pdm.spec.ts
@@ -0,0 +1,172 @@
import { join } from 'upath';
import { mockExecAll } from '../../../../../test/exec-util';
import { fs, mockedFunction } from '../../../../../test/util';
import { GlobalConfig } from '../../../../config/global';
import type { RepoGlobalConfig } from '../../../../config/types';
import { getPkgReleases as _getPkgReleases } from '../../../datasource';
import type { UpdateArtifactsConfig } from '../../types';
import { PdmProcessor } from './pdm';

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

const getPkgReleases = mockedFunction(_getPkgReleases);

const config: UpdateArtifactsConfig = {};
const adminConfig: RepoGlobalConfig = {
localDir: join('/tmp/github/some/repo'),
cacheDir: join('/tmp/cache'),
containerbaseDir: join('/tmp/cache/containerbase'),
};

const processor = new PdmProcessor();

describe('modules/manager/pep621/processors/pdm', () => {
describe('updateArtifacts()', () => {
it('return null if there is no lock file', async () => {
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
const updatedDeps = [{ packageName: 'dep1' }];
const result = await processor.updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config,
updatedDeps,
});
expect(result).toBeNull();
});

it('return null if the lock file is unchanged', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
fs.readLocalFile.mockResolvedValueOnce('test content');
fs.readLocalFile.mockResolvedValueOnce('test content');
// pdm
getPkgReleases.mockResolvedValueOnce({
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
});

const updatedDeps = [{ packageName: 'dep1' }];
const result = await processor.updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config: {},
updatedDeps,
});
expect(result).toBeNull();
expect(execSnapshots).toMatchObject([
{
cmd: 'docker pull containerbase/sidecar',
},
{
cmd: 'docker ps --filter name=renovate_sidecar -aq',
},
{
cmd:
'docker run --rm --name=renovate_sidecar --label=renovate_child ' +
'-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' +
'-v "/tmp/cache":"/tmp/cache" ' +
'-e BUILDPACK_CACHE_DIR ' +
'-e CONTAINERBASE_CACHE_DIR ' +
'-w "/tmp/github/some/repo" ' +
'containerbase/sidecar ' +
'bash -l -c "' +
'install-tool pdm v2.5.0 ' +
'&& ' +
'pdm update dep1' +
'"',
},
]);
});

it('returns artifact error', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
fs.readLocalFile.mockImplementationOnce(() => {
throw new Error('test error');
});

const updatedDeps = [{ packageName: 'dep1' }];
const result = await processor.updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config: {},
updatedDeps,
});
expect(result).toEqual([
{ artifactError: { lockFile: 'pdm.lock', stderr: 'test error' } },
]);
expect(execSnapshots).toEqual([]);
});

it('return update dep update', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set(adminConfig);
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
fs.readLocalFile.mockResolvedValueOnce('test content');
fs.readLocalFile.mockResolvedValueOnce('changed test content');
// pdm
getPkgReleases.mockResolvedValueOnce({
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
});

const updatedDeps = [{ packageName: 'dep1' }, { packageName: 'dep2' }];
const result = await processor.updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config: {},
updatedDeps,
});
expect(result).toEqual([
{
file: {
contents: 'changed test content',
path: 'pdm.lock',
type: 'addition',
},
},
]);
expect(execSnapshots).toMatchObject([
{
cmd: 'pdm update dep1 dep2',
},
]);
});

it('return update on lockfileMaintenance', async () => {
const execSnapshots = mockExecAll();
GlobalConfig.set(adminConfig);
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
fs.readLocalFile.mockResolvedValueOnce('test content');
fs.readLocalFile.mockResolvedValueOnce('changed test content');
// pdm
getPkgReleases.mockResolvedValueOnce({
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
});

const result = await processor.updateArtifacts({
packageFileName: 'pyproject.toml',
newPackageFileContent: '',
config: {
updateType: 'lockFileMaintenance',
},
updatedDeps: [],
});
expect(result).toEqual([
{
file: {
contents: 'changed test content',
path: 'pdm.lock',
type: 'addition',
},
},
]);
expect(execSnapshots).toMatchObject([
{
cmd: 'pdm update',
},
]);
});
});
});