Repository: kestra-io/kestra (java)

Issue:
Invalid pebble after migration
### Describe the issue

```
- id: load_bq_from_gcs_csv
  type: io.kestra.plugin.gcp.bigquery.LoadFromGcs
  from:
    - 'gs://{{ secret("GCS_LANDING_BUCKET") }}/{{ json(parent.taskrun.value)["gcs_path_prefix"] }}/{{ inputs.uuid_str }}_*.csv.gz'
  destinationTable: "{{ json(parent.taskrun.value)['destination_table'] }}"
  writeDisposition: WRITE_APPEND
  createDisposition: CREATE_NEVER
  autodetect: false
  format: CSV
  csvOptions:
    encoding: UTF-8
    fieldDelimiter: ","
    skipLeadingRows: 1
    allowQuotedNewLines: true
  allowFailure: true
```
used to work but migration from 0.20.11 to 0.21.3 made it throw this error:
```
2025-02-19 10:28:47.062io.pebbletemplates.pebble.error.ParserException: Unexpected character [\] (["gs://{{ secret(\"GCS_LANDING_BUCKET\") }}/{{ json(parent.taskrun.value)[\"gcs_path_prefix\"] }}/{{ inputs.uuid_str }}_*.csv.gz"]:1)
```

### Environment

- Kestra Version: 0.20.11 to 0.21.3


Pull request description:
fix(core): properly render list properties
Fixes #7511


Patch:
diff --git a/core/src/main/java/io/kestra/core/models/property/Property.java b/core/src/main/java/io/kestra/core/models/property/Property.java
index 328ae2c94..c9f3581bf 100644
--- a/core/src/main/java/io/kestra/core/models/property/Property.java
+++ b/core/src/main/java/io/kestra/core/models/property/Property.java
@@ -149,13 +149,15 @@ public class Property<T> {
                 if (trimmedExpression.startsWith("{{") && trimmedExpression.endsWith("}}")) {
                     property.value = MAPPER.readValue(runContext.render(property.expression, variables), type);
                 }
-                // Otherwise if it's already a list, we read it as a list first then render it from run context which handle list rendering by rendering each item of the list
+                // Otherwise, if it's already a list, we read it as a list first then render it from run context which handle list rendering by rendering each item of the list
                 else {
-                    List<?> asRawList = MAPPER.readValue(runContext.render(property.expression, variables), List.class);
+                    List<?> asRawList = MAPPER.readValue(property.expression, List.class);
                     property.value = (T) asRawList.stream()
                         .map(throwFunction(item -> {
                             if (item instanceof String str) {
-                                return MAPPER.convertValue(str, itemClazz);
+                                return MAPPER.convertValue(runContext.render(str, variables), itemClazz);
+                            } else if (item instanceof Map map) {
+                                return MAPPER.convertValue(runContext.render(map, variables), itemClazz);
                             }
                             return item;
                         }))


Test patch:
diff --git a/core/src/test/java/io/kestra/core/models/property/PropertyTest.java b/core/src/test/java/io/kestra/core/models/property/PropertyTest.java
index 72e9fc16a..09b75faec 100644
--- a/core/src/test/java/io/kestra/core/models/property/PropertyTest.java
+++ b/core/src/test/java/io/kestra/core/models/property/PropertyTest.java
@@ -302,7 +302,7 @@ class PropertyTest {
     void aListToRender() throws Exception {
         var task = DynamicPropertyExampleTask.builder()
             .items(new Property<>("""
-                ["python test.py --input1 \\"{{ item1 }}\\" --input2 \\"{{ item2 }}\\""]"""))
+                ["python test.py --input1 \\"{{ item1 }}\\" --input2 \\"{{ item2 }}\\"", "'gs://{{ renderOnce(\\"bucket\\") }}/{{ 'table' }}/{{ 'file' }}_*.csv.gz'"]"""))
             .properties(new Property<>("""
                 {
                   "key1": "{{value1}}",
@@ -319,7 +319,7 @@ class PropertyTest {
         var output = task.run(runContext);
 
         assertThat(output, notNullValue());
-        assertThat(output.getList(), containsInAnyOrder("python test.py --input1 \"item1\" --input2 \"item2\""));
+        assertThat(output.getList(), containsInAnyOrder("python test.py --input1 \"item1\" --input2 \"item2\"", "'gs://bucket/table/file_*.csv.gz'"));
     }
 
     @Builder