Skip to content

Commit

Permalink
feat(versioning): add python versioning for buildpack (#17147)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed Aug 12, 2022
1 parent 321afb5 commit 60ed6ad
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 8 deletions.
Expand Up @@ -111,7 +111,7 @@ Array [
},
},
Object {
"cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache\\":\\"/tmp/renovate/cache\\" -e PIPENV_CACHE_DIR -e PIP_CACHE_DIR -e BUILDPACK_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/sidecar bash -l -c \\"install-tool python 3.10.2 && pip install --user pipenv && pipenv lock\\"",
"cmd": "docker run --rm --name=renovate_sidecar --label=renovate_child -v \\"/tmp/github/some/repo\\":\\"/tmp/github/some/repo\\" -v \\"/tmp/renovate/cache\\":\\"/tmp/renovate/cache\\" -e PIPENV_CACHE_DIR -e PIP_CACHE_DIR -e BUILDPACK_CACHE_DIR -w \\"/tmp/github/some/repo\\" renovate/sidecar bash -l -c \\"install-tool python 3.7.6 && pip install --user pipenv && pipenv lock\\"",
"options": Object {
"cwd": "/tmp/github/some/repo",
"encoding": "utf-8",
Expand Down
7 changes: 4 additions & 3 deletions lib/modules/manager/pipenv/artifacts.spec.ts
Expand Up @@ -53,6 +53,7 @@ describe('modules/manager/pipenv/artifacts', () => {
// python
getPkgReleases.mockResolvedValueOnce({
releases: [
{ version: '3.7.6' },
{ version: '3.8.5' },
{ version: '3.9.1' },
{ version: '3.10.2' },
Expand Down Expand Up @@ -123,7 +124,7 @@ describe('modules/manager/pipenv/artifacts', () => {
packageFileName: 'Pipfile',
updatedDeps: [],
newPackageFileContent: 'some new content',
config: { ...config, constraints: { python: '3.7' } },
config: { ...config, constraints: { python: '== 3.8.*' } },
})
).not.toBeNull();
expect(execSnapshots).toMatchSnapshot();
Expand Down Expand Up @@ -155,7 +156,7 @@ describe('modules/manager/pipenv/artifacts', () => {

it('supports install mode', async () => {
GlobalConfig.set({ ...adminConfig, binarySource: 'install' });
pipFileLock._meta.requires.python_version = '3.7';
pipFileLock._meta.requires.python_full_version = '3.7.6';
fs.ensureCacheDir.mockResolvedValueOnce(
'/tmp/renovate/cache/others/pipenv'
);
Expand All @@ -175,7 +176,7 @@ describe('modules/manager/pipenv/artifacts', () => {
})
).not.toBeNull();
expect(execSnapshots).toMatchObject([
{ cmd: 'install-tool python 3.10.2' },
{ cmd: 'install-tool python 3.7.6' },
{ cmd: 'pip install --user pipenv' },
{ cmd: 'pipenv lock', options: { cwd: '/tmp/github/some/repo' } },
]);
Expand Down
2 changes: 2 additions & 0 deletions lib/modules/versioning/api.ts
Expand Up @@ -19,6 +19,7 @@ import * as nuget from './nuget';
import * as pep440 from './pep440';
import * as perl from './perl';
import * as poetry from './poetry';
import * as python from './python';
import * as redhat from './redhat';
import * as regex from './regex';
import * as rez from './rez';
Expand Down Expand Up @@ -53,6 +54,7 @@ api.set(nuget.id, nuget.api);
api.set(pep440.id, pep440.api);
api.set(perl.id, perl.api);
api.set(poetry.id, poetry.api);
api.set(python.id, python.api);
api.set(redhat.id, redhat.api);
api.set(regex.id, regex.api);
api.set(rez.id, rez.api);
Expand Down
102 changes: 102 additions & 0 deletions lib/modules/versioning/python/index.spec.ts
@@ -0,0 +1,102 @@
import { partial } from '../../../../test/util';
import type { NewValueConfig } from '../types';
import { api as versioning } from '.';

describe('modules/versioning/python/index', () => {
test.each`
version | expected
${'17.04.00'} | ${true}
${'17.b4.0'} | ${false}
${'1.2.3'} | ${true}
${'1.2.3-foo'} | ${true}
${'1.2.3foo'} | ${false}
${'1.2.3a0'} | ${true}
${'1.2.3b1'} | ${true}
${'1.2.3rc23'} | ${true}
${'*'} | ${true}
${'~1.2.3'} | ${true}
${'^1.2.3'} | ${true}
${'>1.2.3'} | ${true}
${'~=1.9'} | ${true}
${'==1.9'} | ${true}
${'===1.9.4'} | ${true}
${'renovatebot/renovate'} | ${false}
${'renovatebot/renovate#master'} | ${false}
${'https://github.com/renovatebot/renovate.git'} | ${false}
`('isValid("$version") === $expected', ({ version, expected }) => {
expect(!!versioning.isValid(version)).toBe(expected);
});

test.each`
version | range | expected
${'4.2.0'} | ${'4.2, >= 3.0, < 5.0.0'} | ${true}
${'4.2.0'} | ${'2.0, >= 3.0, < 5.0.0'} | ${false}
${'4.2.2'} | ${'4.2.0, < 4.2.4'} | ${false}
${'4.2.2'} | ${'^4.2.0, < 4.2.4'} | ${true}
${'4.2.0'} | ${'4.3.0, 3.0.0'} | ${false}
${'4.2.0'} | ${'> 5.0.0, <= 6.0.0'} | ${false}
${'4.2.0'} | ${'*'} | ${true}
${'1.9.4'} | ${'==1.9'} | ${true}
${'1.9.4'} | ${'===1.9.4'} | ${true}
${'1.9.4'} | ${'===1.9.3'} | ${false}
${'0.8.0a1'} | ${'^0.8.0-alpha.0'} | ${true}
${'0.7.4'} | ${'^0.8.0-alpha.0'} | ${false}
${'1.4'} | ${'1.4'} | ${true}
${'1.4.5'} | ${'== 1.4.*'} | ${true}
${'1.5.5'} | ${'== 1.4.*'} | ${false}
${'1.4.5'} | ${'== 1.4.5'} | ${true}
${'1.4.6'} | ${'== 1.4.5'} | ${false}
`(
'matches("$version", "$range") === "$expected"',
({ version, range, expected }) => {
expect(versioning.matches(version, range)).toBe(expected);
}
);

test.each`
version | range | expected
${'0.9.0'} | ${'>= 1.0.0 <= 2.0.0'} | ${true}
${'1.9.0'} | ${'>= 1.0.0 <= 2.0.0'} | ${false}
${'1.9.0'} | ${'== 2.7.*'} | ${false}
`(
'isLessThanRange("$version", "$range") === "$expected"',
({ version, range, expected }) => {
expect(versioning.isLessThanRange?.(version, range)).toBe(expected);
}
);

test.each`
versions | range | expected
${['0.4.0', '0.5.0', '4.2.0', '4.3.0', '5.0.0']} | ${'4.*, > 4.2'} | ${'4.3.0'}
${['0.4.0', '0.5.0', '4.2.0', '5.0.0']} | ${'^4.0.0'} | ${'4.2.0'}
${['0.4.0', '0.5.0', '4.2.0', '5.0.0']} | ${'^4.0.0, = 0.5.0'} | ${null}
${['0.4.0', '0.5.0', '4.2.0', '5.0.0']} | ${'^4.0.0, > 4.1.0, <= 4.3.5'} | ${'4.2.0'}
${['0.4.0', '0.5.0', '4.2.0', '5.0.0']} | ${'^6.2.0, 3.*'} | ${null}
${['0.8.0a2', '0.8.0a7']} | ${'^0.8.0-alpha.0'} | ${'0.8.0-alpha.2'}
${['1.0.0', '2.0.0']} | ${'^3.0.0'} | ${null}
${['1.0.0', '2.0.0']} | ${'== 3.7.*'} | ${null}
`(
'minSatisfyingVersion($versions, "$range") === $expected',
({ versions, range, expected }) => {
expect(versioning.minSatisfyingVersion(versions, range)).toBe(expected);
}
);

test.each`
versions | range | expected
${['4.2.1', '0.4.0', '0.5.0', '4.0.0', '4.2.0', '5.0.0']} | ${'4.*.0, < 4.2.5'} | ${'4.2.1'}
${['0.4.0', '0.5.0', '4.0.0', '4.2.0', '5.0.0', '5.0.3']} | ${'5.0, > 5.0.0'} | ${'5.0.3'}
${['0.8.0a2', '0.8.0a7']} | ${'^0.8.0-alpha.0'} | ${'0.8.0-alpha.7'}
${['1.0.0', '2.0.0']} | ${'^3.0.0'} | ${null}
${['1.0.0', '2.0.0']} | ${'== 3.7.*'} | ${null}
`(
'getSatisfyingVersion($versions, "$range") === $expected',
({ versions, range, expected }) => {
expect(versioning.getSatisfyingVersion(versions, range)).toBe(expected);
}
);

test('getNewValue()', () => {
expect(versioning.getNewValue(partial<NewValueConfig>({}))).toBeNull();
});
});
57 changes: 57 additions & 0 deletions lib/modules/versioning/python/index.ts
@@ -0,0 +1,57 @@
import { api as pep440 } from '../pep440';
import { api as poetry } from '../poetry';
import type { NewValueConfig, VersioningApi } from '../types';

export const id = 'python';
export const displayName = 'Python';
export const urls = [];
export const supportsRanges = false;

function isLessThanRange(version: string, range: string): boolean {
return poetry.isValid(range)
? poetry.isLessThanRange!(version, range)
: pep440.isLessThanRange!(version, range);
}

function isValid(input: string): boolean {
return poetry.isValid(input) || pep440.isValid(input);
}

function matches(version: string, range: string): boolean {
return poetry.isValid(range)
? poetry.matches(version, range)
: pep440.matches(version, range);
}

function getSatisfyingVersion(
versions: string[],
range: string
): string | null {
return poetry.isValid(range)
? poetry.getSatisfyingVersion(versions, range)
: pep440.getSatisfyingVersion(versions, range);
}

function minSatisfyingVersion(
versions: string[],
range: string
): string | null {
return poetry.isValid(range)
? poetry.minSatisfyingVersion(versions, range)
: pep440.minSatisfyingVersion(versions, range);
}

function getNewValue(_: NewValueConfig): string | null {
return null;
}

export const api: VersioningApi = {
...poetry,
getNewValue,
getSatisfyingVersion,
isLessThanRange,
isValid,
matches,
minSatisfyingVersion,
};
export default api;
1 change: 1 addition & 0 deletions lib/modules/versioning/python/readme.md
@@ -0,0 +1 @@
Python versioning is a little like a mix of PEP440 and Poetry SemVer.
4 changes: 2 additions & 2 deletions lib/util/exec/buildpack.spec.ts
Expand Up @@ -132,9 +132,9 @@ describe('util/exec/buildpack', () => {
${'^3.9'} | ${'3.10.4'}
${'3.9.*'} | ${'3.9.1'}
${'>3.8,<3.10'} | ${'3.9.1'}
${'==3.9.1'} | ${'3.10.4'}
${'==3.9.*'} | ${'3.9.1'}
`(
'supports python ranges "$version" == "$expected"',
'supports python ranges "$version" => "$expected"',
async ({ version: constraint, expected }) => {
datasource.getPkgReleases.mockResolvedValueOnce({
releases: [
Expand Down
4 changes: 2 additions & 2 deletions lib/util/exec/buildpack.ts
Expand Up @@ -8,7 +8,7 @@ import { id as composerVersioningId } from '../../modules/versioning/composer';
import { id as nodeVersioningId } from '../../modules/versioning/node';
import { id as npmVersioningId } from '../../modules/versioning/npm';
import { id as pep440VersioningId } from '../../modules/versioning/pep440';
import { id as poetryVersioningId } from '../../modules/versioning/poetry';
import { id as pythonVersioningId } from '../../modules/versioning/python';
import { id as rubyVersioningId } from '../../modules/versioning/ruby';
import { id as semverVersioningId } from '../../modules/versioning/semver';
import { id as semverCoercedVersioningId } from '../../modules/versioning/semver-coerced';
Expand Down Expand Up @@ -94,7 +94,7 @@ const allToolConfig: Record<string, ToolConfig> = {
python: {
datasource: 'github-releases',
depName: 'containerbase/python-prebuild',
versioning: poetryVersioningId,
versioning: pythonVersioningId,
},
yarn: {
datasource: 'npm',
Expand Down

0 comments on commit 60ed6ad

Please sign in to comment.