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(config/toml): support jinja templates in toml files #33123

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[project]
name = "{{ name }}"
dynamic = ["version"]
requires-python = ">=3.7"
license = {text = "MIT"}
{# comment #}
dependencies = [
"blinker",
{% if foo %}
"packaging>=20.9,!=22.0",
{% endif %}
]
readme = "README.md"
6 changes: 6 additions & 0 deletions lib/modules/manager/pep621/extract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -605,5 +605,11 @@ describe('modules/manager/pep621/extract', () => {
],
});
});

it('should resolve dependencies with template', async () => {
const templatePyProject = Fixtures.get('pyproject_with_template.toml');
const res = await extractPackageFile(templatePyProject, 'pyproject.toml');
expect(res?.deps).toHaveLength(2);
});
});
});
2 changes: 1 addition & 1 deletion lib/modules/manager/pep621/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function parsePyProject(
content: string,
): PyProject | null {
try {
const jsonMap = parseToml(content);
const jsonMap = parseToml(content, { removeTemplates: true });
return PyProjectSchema.parse(jsonMap);
} catch (err) {
logger.debug(
Expand Down
9 changes: 9 additions & 0 deletions lib/modules/manager/poetry/__fixtures__/pyproject.13.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[tool.poetry]
name = "{{ name }}"

{# comment #}
[tool.poetry.dependencies]
python = "^3.9"
{% if foo %}
dep1 = "^1.0.0"
{% endif %}
2 changes: 1 addition & 1 deletion lib/modules/manager/poetry/artifacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function getPoetryRequirement(
function getPoetrySources(content: string, fileName: string): PoetrySource[] {
let pyprojectFile: PoetryFile;
try {
pyprojectFile = parseToml(content) as PoetryFile;
pyprojectFile = parseToml(content, { removeTemplates: true }) as PoetryFile;
} catch (err) {
logger.debug({ err }, 'Error parsing pyproject.toml file');
return [];
Expand Down
8 changes: 8 additions & 0 deletions lib/modules/manager/poetry/extract.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const pyproject11toml = Fixtures.get('pyproject.11.toml');
const pyproject11tomlLock = Fixtures.get('pyproject.11.toml.lock');

const pyproject12toml = Fixtures.get('pyproject.12.toml');
const pyproject13toml = Fixtures.get('pyproject.13.toml');

describe('modules/manager/poetry/extract', () => {
describe('extractPackageFile()', () => {
Expand Down Expand Up @@ -496,5 +497,12 @@ describe('modules/manager/poetry/extract', () => {
]);
});
});

it('parses package file with template', async () => {
const res = await extractPackageFile(pyproject13toml, filename);
expect(res?.deps).toHaveLength(2);
expect(res?.deps[0].depName).toBe('python');
expect(res?.deps[1].depName).toBe('dep1');
});
});
});
2 changes: 1 addition & 1 deletion lib/util/schema-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export const MultidocYaml = z.string().transform((str, ctx): JsonArray => {

export const Toml = z.string().transform((str, ctx) => {
try {
return parseToml(str);
return parseToml(str, { removeTemplates: true });
} catch {
ctx.addIssue({ code: 'custom', message: 'Invalid TOML' });
return z.NEVER;
Expand Down
21 changes: 21 additions & 0 deletions lib/util/toml.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,25 @@ describe('util/toml', () => {

expect(() => parseToml(input)).toThrow(SyntaxError);
});

it('should parse content with templates', () => {
const input = codeBlock`
[project]
name = "{{ value }}"

{# comment #}
[tool.poetry.dependencies]
{% if enabled %}
python = "^3.12"
{%+ endif -%}
`;
expect(parseToml(input, { removeTemplates: true })).toStrictEqual({
project: { name: '' },
tool: {
poetry: {
dependencies: { python: '^3.12' },
},
},
});
});
});
20 changes: 18 additions & 2 deletions lib/util/toml.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
import { getStaticTOMLValue, parseTOML } from 'toml-eslint-parser';
import { regEx } from './regex';

export function parse(input: string): unknown {
const ast = parseTOML(input);
export interface TomlOptions {
removeTemplates?: boolean;
}

export function parse(input: string, options?: TomlOptions): unknown {
const massagedContent = massageContent(input, options);
const ast = parseTOML(massagedContent);
return getStaticTOMLValue(ast);
}

function massageContent(content: string, options?: TomlOptions): string {
if (options?.removeTemplates) {
return content
.replaceAll(regEx(/{%.+?%}/gs), '')
.replaceAll(regEx(/{{.+?}}/gs), '')
.replaceAll(regEx(/{#.+?#}/gs), '');
}
return content;
}
Loading