Skip to content

Conversation

STollenaar
Copy link

@STollenaar STollenaar commented Jun 5, 2025

Changes

Added support for the terraform json file format. Expanded the parseHCL function to determine if a given file is a .tf.json or regular .tf file and do a JSON parse into HCL before passing that output into the HCL parser, which format is further supported by the code base

Context

Documentation (please check one with an [x])

  • I have updated the documentation, or
  • No documentation update is required

How I've tested my work (please select one)

I have verified these changes via:

  • Code inspection only, or
  • Newly added/modified unit tests, or
  • No unit tests but ran on a real repository, or
  • Both unit tests + ran on a real repository

Copy link
Member

@viceice viceice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need all those new fixtures. please reduce to minimum to satisfy coverage

@viceice
Copy link
Member

viceice commented Jun 6, 2025

I also think think you shouldn't convert to tf and parse again. you should directly transform to the parsed hcl structure.

isn't the hcl lib from terraform supporting those json files out of the box?

@viceice
Copy link
Member

viceice commented Jun 6, 2025

you can check if there's an additional library to @cdktf/hcl2json which support it

@STollenaar
Copy link
Author

STollenaar commented Jun 6, 2025

I don't think we need all those new fixtures. please reduce to minimum to satisfy coverage

Ok, I will remove a few fixtures. I tried to keep the same tests as we have for the regular .tf files to ensure complete coverage for both types

I also think think you shouldn't convert to tf and parse again. you should directly transform to the parsed hcl structure.

isn't the hcl lib from terraform supporting those json files out of the box?

so this is a bit tricky. When executing terraform directly it does support the json files. However, the syntax is a bit different. With the @cdktf/hcl2json when parsed there are some distinct differences on what the output will be. This is why a simple JSON.parse doesn't work as the rest of the renovate code would break.

Including a few screenshots on the subtle differences:
image
image
image

you can check if there's an additional library to @cdktf/hcl2json which support it

I checked around and I couldn't find a supported node library that would support the json to hcl parse. There are instances of GO packages, but that wouldn't work for this project.

@viceice
Copy link
Member

viceice commented Jun 7, 2025

ok, in this case you should directly convert the Json to the parsed hcl format and don't generate the hcl source code.

@STollenaar
Copy link
Author

ok, in this case you should directly convert the Jain to the parsed hcl format and don't generate the hcl source code.

From the .tf.json spec you don't really know when something is an array vs an object. in the kubernetes resources there is the metadata block for example. This is seen as an array, but written as an object. There are many of these little nuances that make it harder to go directly from JSON to that parsed hcl format

Copy link
Collaborator

@RahulGautamSingh RahulGautamSingh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you reduce the number of deps extracted in the tests? I can see many deps being extracted and most are similar. Best will be to only keeps deps which are unique somewhat.

If something similar can be done with the fixtures too, please consider doing it. We prefer adding fixtures only when its necessary.

Thanks!

@@ -0,0 +1,129 @@
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reduce fixtures to minimum size

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially resolved this by removing some coverage. But I do want to ask, why do we want to reduce the coverage which would make sure the behavior between the .tf and the .tf.json remains the same?

Copy link
Collaborator

@RahulGautamSingh RahulGautamSingh Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer to inline small fixtures wherever possible as it's better for performance. But it should not come at cost of coverage

@viceice
Copy link
Member

viceice commented Jun 28, 2025

ok, in this case you should directly convert the Jain to the parsed hcl format and don't generate the hcl source code.

From the .tf.json spec you don't really know when something is an array vs an object. in the kubernetes resources there is the metadata block for example. This is seen as an array, but written as an object. There are many of these little nuances that make it harder to go directly from JSON to that parsed hcl format

I don't agree. we know we only support specific types with specific properties, so we can directly use zod schema to parse and transform the known supported objects and discard all other things.

@STollenaar
Copy link
Author

ok, in this case you should directly convert the Jain to the parsed hcl format and don't generate the hcl source code.

From the .tf.json spec you don't really know when something is an array vs an object. in the kubernetes resources there is the metadata block for example. This is seen as an array, but written as an object. There are many of these little nuances that make it harder to go directly from JSON to that parsed hcl format

I don't agree. we know we only support specific types with specific properties, so we can directly use zod schema to parse and transform the known supported objects and discard all other things.

I changed it to use the zod schema. Tests pass so I think it does work correctly now. Might need to expand the test cases to cover all the supported terraform resources

@STollenaar STollenaar requested a review from viceice July 3, 2025 20:22
Copy link
Collaborator

@secustor secustor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cdktf/hcl2json directly parses JSON files while converting.

From the .tf.json spec you don't really know when something is an array vs an object. in the kubernetes resources there is the metadata block for example. This is seen as an array, but written as an object. There are many of these little nuances that make it harder to go directly from JSON to that parsed hcl format

This is how the spec describes it in their syntax docs.

When a JSON object property is named after a nested block type, the value of this property represents one or more blocks of that type. The value of the property must be either a JSON object or a JSON array.

To implement this it should be also possible to do a simply normalization from objects to array starting from the second or third level of the JSON objects

const GenericResourceInstance = z.record(tfLiteral);
const GenericResourceSchema = z.record(oneOrMany(GenericResourceInstance));

const KubernetesInstance = z.any().transform((orig) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this any?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry, an oversight. Removed for a typed value

'selector',
]);

function normalise(node: any): any {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
function normalise(node: any): any {
function normalise(node: unknown): unknown {

Do not use any.

If we are going this route we should do this for every block and not only the Kubernetes ones.

When a JSON object property is named after a nested block type, the value of this property represents one or more blocks of that type. The value of the property must be either a JSON object or a JSON array.

https://developer.hashicorp.com/terraform/language/syntax/json#nested-block-mapping

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going this route we should do this for every block and not only the Kubernetes ones.

Agreed, however renovate currently only supports the docker, helm and kubernetes resources for Terraform.

@secustor
Copy link
Collaborator

@cdktf/hcl2json directly parses JSON files while converting.

If you read that function, it actually only does a JSON.parse on it and then does a deep merge with the .tf files. If you were to do that with renovate you get errors since the extractor doesn't recognize that kind of syntax

I have read it and meant this in context of this comment and it is feasible to me to adapt the extractor logic to expect an array here, if it simplifies the code.

@RahulGautamSingh
Copy link
Collaborator

Confliced

Copy link
Collaborator

@RahulGautamSingh RahulGautamSingh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, we should add .tf.json to the managerFilePatterns

@@ -0,0 +1,129 @@
{
Copy link
Collaborator

@RahulGautamSingh RahulGautamSingh Aug 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer to inline small fixtures wherever possible as it's better for performance. But it should not come at cost of coverage

@STollenaar STollenaar force-pushed the feat/support-tf-json branch from bf86ec7 to dbb1419 Compare August 23, 2025 18:26
@STollenaar STollenaar force-pushed the feat/support-tf-json branch from ba95785 to fc2f3bb Compare August 23, 2025 18:33
@STollenaar
Copy link
Author

Also, we should add .tf.json to the managerFilePatterns

added the .json items to this, also updated to include the .tofu files

@RahulGautamSingh RahulGautamSingh added the ci:allow-undesirable Skip the undesirable files CI check label Aug 24, 2025
Copy link
Collaborator

@RahulGautamSingh RahulGautamSingh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@viceice viceice left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good but still too many fixtures which will slow down tests too much

@STollenaar
Copy link
Author

looks good but still too many fixtures which will slow down tests too much

Is this latest change to inline fixtures better?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ci:allow-undesirable Skip the undesirable files CI check
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support .tf.json Terraform JSON
4 participants