feat(manager/poetry): extract python as a dependency from pyproject.toml (#24236)

This commit is contained in:
Joshua Tang 2023-09-05 01:17:25 +10:00 committed by GitHub
parent 0f54d4a806
commit 46c10be305
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 7 deletions

View file

@ -471,6 +471,17 @@ exports[`modules/manager/poetry/extract extractPackageFile() extracts multiple d
}, },
"versioning": "poetry", "versioning": "poetry",
}, },
{
"commitMessageTopic": "Python",
"currentValue": "~2.7 || ^3.4",
"datasource": "docker",
"depName": "python",
"depType": "dependencies",
"managerData": {
"nestedVersion": false,
},
"versioning": "poetry",
},
{ {
"currentValue": "^3.0", "currentValue": "^3.0",
"datasource": "pypi", "datasource": "pypi",
@ -554,6 +565,17 @@ exports[`modules/manager/poetry/extract extractPackageFile() handles multiple co
exports[`modules/manager/poetry/extract extractPackageFile() resolves lockedVersions from the lockfile 1`] = ` exports[`modules/manager/poetry/extract extractPackageFile() resolves lockedVersions from the lockfile 1`] = `
{ {
"deps": [ "deps": [
{
"commitMessageTopic": "Python",
"currentValue": "^3.9",
"datasource": "docker",
"depName": "python",
"depType": "dependencies",
"managerData": {
"nestedVersion": false,
},
"versioning": "poetry",
},
{ {
"currentValue": "*", "currentValue": "*",
"datasource": "pypi", "datasource": "pypi",

View file

@ -1,3 +1,4 @@
import { codeBlock } from 'common-tags';
import { join } from 'upath'; import { join } from 'upath';
import { envMock, mockExecAll } from '../../../../test/exec-util'; import { envMock, mockExecAll } from '../../../../test/exec-util';
import { Fixtures } from '../../../../test/fixtures'; import { Fixtures } from '../../../../test/fixtures';
@ -8,7 +9,7 @@ import * as docker from '../../../util/exec/docker';
import * as _hostRules from '../../../util/host-rules'; import * as _hostRules from '../../../util/host-rules';
import * as _datasource from '../../datasource'; import * as _datasource from '../../datasource';
import type { UpdateArtifactsConfig } from '../types'; import type { UpdateArtifactsConfig } from '../types';
import { getPoetryRequirement } from './artifacts'; import { getPoetryRequirement, getPythonConstraint } from './artifacts';
import { updateArtifacts } from '.'; import { updateArtifacts } from '.';
const pyproject1toml = Fixtures.get('pyproject.1.toml'); const pyproject1toml = Fixtures.get('pyproject.1.toml');
@ -33,6 +34,29 @@ const adminConfig: RepoGlobalConfig = {
const config: UpdateArtifactsConfig = {}; const config: UpdateArtifactsConfig = {};
describe('modules/manager/poetry/artifacts', () => { describe('modules/manager/poetry/artifacts', () => {
describe('getPythonConstraint', () => {
const pythonVersion = '3.11.3';
const poetryLock = codeBlock`
[metadata]
python-versions = "${pythonVersion}"
`;
it('detects from pyproject.toml', () => {
const pythonVersion = '3.11.5';
const pyprojectContent = codeBlock`
[tool.poetry.dependencies]
python = "${pythonVersion}"
`;
expect(getPythonConstraint(pyprojectContent, poetryLock)).toBe(
pythonVersion
);
});
it('detects from poetry.ock', () => {
expect(getPythonConstraint('', poetryLock)).toBe(pythonVersion);
});
});
describe('getPoetryRequirement', () => { describe('getPoetryRequirement', () => {
const poetry12lock = Fixtures.get('poetry12.lock'); const poetry12lock = Fixtures.get('poetry12.lock');
const poetry142lock = Fixtures.get('poetry142.lock'); const poetry142lock = Fixtures.get('poetry142.lock');

View file

@ -22,12 +22,33 @@ import { Lockfile, PoetrySchemaToml } from './schema';
import type { PoetryFile, PoetrySource } from './types'; import type { PoetryFile, PoetrySource } from './types';
export function getPythonConstraint( export function getPythonConstraint(
pyProjectContent: string,
existingLockFileContent: string existingLockFileContent: string
): string | null { ): string | null {
return Result.parse( // Read Python version from `pyproject.toml` first as it could have been updated
const pyprojectPythonConstraint = Result.parse(
pyProjectContent,
PoetrySchemaToml.transform(
({ packageFileContent }) =>
packageFileContent.deps.find((dep) => dep.depName === 'python')
?.currentValue
)
).unwrapOrNull();
if (pyprojectPythonConstraint) {
logger.debug('Using python version from pyproject.toml');
return pyprojectPythonConstraint;
}
const lockfilePythonConstraint = Result.parse(
existingLockFileContent, existingLockFileContent,
Lockfile.transform(({ pythonVersions }) => pythonVersions) Lockfile.transform(({ pythonVersions }) => pythonVersions)
).unwrapOrNull(); ).unwrapOrNull();
if (lockfilePythonConstraint) {
logger.debug('Using python version from poetry.lock');
return lockfilePythonConstraint;
}
return null;
} }
export function getPoetryRequirement( export function getPoetryRequirement(
@ -158,7 +179,7 @@ export async function updateArtifacts({
} }
const pythonConstraint = const pythonConstraint =
config?.constraints?.python ?? config?.constraints?.python ??
getPythonConstraint(existingLockFileContent); getPythonConstraint(newPackageFileContent, existingLockFileContent);
const poetryConstraint = const poetryConstraint =
config.constraints?.poetry ?? config.constraints?.poetry ??
getPoetryRequirement(newPackageFileContent, existingLockFileContent); getPoetryRequirement(newPackageFileContent, existingLockFileContent);

View file

@ -48,7 +48,7 @@ describe('modules/manager/poetry/extract', () => {
it('extracts multiple dependencies', async () => { it('extracts multiple dependencies', async () => {
const res = await extractPackageFile(pyproject1toml, filename); const res = await extractPackageFile(pyproject1toml, filename);
expect(res?.deps).toMatchSnapshot(); expect(res?.deps).toMatchSnapshot();
expect(res?.deps).toHaveLength(9); expect(res?.deps).toHaveLength(10);
expect(res?.extractedConstraints).toEqual({ expect(res?.extractedConstraints).toEqual({
python: '~2.7 || ^3.4', python: '~2.7 || ^3.4',
}); });
@ -74,7 +74,7 @@ describe('modules/manager/poetry/extract', () => {
it('can parse TOML v1 heterogeneous arrays', async () => { it('can parse TOML v1 heterogeneous arrays', async () => {
const res = await extractPackageFile(pyproject12toml, filename); const res = await extractPackageFile(pyproject12toml, filename);
expect(res).not.toBeNull(); expect(res).not.toBeNull();
expect(res?.deps).toHaveLength(2); expect(res?.deps).toHaveLength(3);
}); });
it('extracts registries', async () => { it('extracts registries', async () => {
@ -184,7 +184,10 @@ describe('modules/manager/poetry/extract', () => {
const res = await extractPackageFile(pyproject11toml, filename); const res = await extractPackageFile(pyproject11toml, filename);
expect(res).toMatchSnapshot({ expect(res).toMatchSnapshot({
extractedConstraints: { python: '^3.9' }, extractedConstraints: { python: '^3.9' },
deps: [{ lockedVersion: '1.17.5' }], deps: [
{ depName: 'python', currentValue: '^3.9' },
{ depName: 'boto3', lockedVersion: '1.17.5' },
],
}); });
}); });

View file

@ -7,6 +7,7 @@ import {
readLocalFile, readLocalFile,
} from '../../../util/fs'; } from '../../../util/fs';
import { Result } from '../../../util/result'; import { Result } from '../../../util/result';
import { DockerDatasource } from '../../datasource/docker';
import type { PackageFileContent } from '../types'; import type { PackageFileContent } from '../types';
import { Lockfile, PoetrySchemaToml } from './schema'; import { Lockfile, PoetrySchemaToml } from './schema';
@ -37,7 +38,11 @@ export async function extractPackageFile(
if (dep.currentValue) { if (dep.currentValue) {
pythonVersion = dep.currentValue; pythonVersion = dep.currentValue;
} }
return null; return {
...dep,
datasource: DockerDatasource.id,
commitMessageTopic: 'Python',
};
} }
const packageName = dep.packageName ?? dep.depName; const packageName = dep.packageName ?? dep.depName;

View file

@ -1,4 +1,5 @@
import type { Category } from '../../../constants'; import type { Category } from '../../../constants';
import { DockerDatasource } from '../../datasource/docker';
import { GithubTagsDatasource } from '../../datasource/github-tags'; import { GithubTagsDatasource } from '../../datasource/github-tags';
import { PypiDatasource } from '../../datasource/pypi'; import { PypiDatasource } from '../../datasource/pypi';
@ -9,6 +10,7 @@ export { updateLockedDependency } from './update-locked';
export const supportedDatasources = [ export const supportedDatasources = [
PypiDatasource.id, PypiDatasource.id,
GithubTagsDatasource.id, GithubTagsDatasource.id,
DockerDatasource.id,
]; ];
export const supportsLockFileMaintenance = true; export const supportsLockFileMaintenance = true;