Repository: kestra-io/kestra (java)

Issue:
UploadFiles task doesn't upload Namespace Files as expected
### Describe the issue

I'm trying to download scripts from Git and upload them to my namespace. Both approaches resulted in a successful execution but without files being actually uploaded:

```yaml
id: upload_from_git
namespace: dev

tasks:
  - id: wdir
    type: io.kestra.plugin.core.flow.WorkingDirectory
    tasks:
      - id: git
        type: io.kestra.plugin.git.Clone
        url: https://github.com/kestra-io/scripts
        branch: main
  
      - id: upload
        type: io.kestra.plugin.core.namespace.UploadFiles
        namespace: dev
        destination: /etl
        files: 
          - etl/
```

zip approach:

```yaml
id: upload
namespace: dev

tasks:
  - id: download
    type: io.kestra.plugin.core.http.Download
    uri: https://github.com/kestra-io/scripts/archive/refs/heads/main.zip
  
  - id: unzip
    type: io.kestra.plugin.compress.ArchiveDecompress
    from: "{{ outputs.download.uri }}"
    algorithm: ZIP
  
  - id: upload
    type: io.kestra.plugin.core.namespace.UploadFiles
    namespace: dev
    # destination: /scripts/
    files: "{{ outputs.unzip.files }}"
```

### Environment

- Kestra Version:
- Operating System (OS/Docker/Kubernetes):
- Java Version (if you don't run kestra in Docker):


Pull request description:
fix(core): upload files now handle string as input for Files and throw an error if input type is incorrect
close #3919

Patch:
diff --git a/build.gradle b/build.gradle
index 2cab55f0c..1d7d8d673 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,7 +20,7 @@ plugins {
 
     // test
     id "com.adarshr.test-logger" version "4.0.0"
-    id "org.sonarqube" version "5.0.0.4638"
+    id "org.sonarqube" version "5.1.0.4882"
     id 'jacoco-report-aggregation'
 
     // helper
diff --git a/core/src/main/java/io/kestra/plugin/core/namespace/UploadFiles.java b/core/src/main/java/io/kestra/plugin/core/namespace/UploadFiles.java
index c7c9d5a96..386402393 100644
--- a/core/src/main/java/io/kestra/plugin/core/namespace/UploadFiles.java
+++ b/core/src/main/java/io/kestra/plugin/core/namespace/UploadFiles.java
@@ -1,11 +1,15 @@
 package io.kestra.plugin.core.namespace;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import io.kestra.core.exceptions.IllegalVariableEvaluationException;
 import io.kestra.core.models.annotations.Example;
 import io.kestra.core.models.annotations.Plugin;
 import io.kestra.core.models.annotations.PluginProperty;
 import io.kestra.core.models.tasks.RunnableTask;
 import io.kestra.core.models.tasks.Task;
 import io.kestra.core.runners.RunContext;
+import io.kestra.core.serializers.JacksonMapper;
 import io.kestra.core.storages.Namespace;
 import io.kestra.core.utils.FileUtils;
 import io.swagger.v3.oas.annotations.media.Schema;
@@ -75,8 +79,9 @@ public class UploadFiles extends Task implements RunnableTask<UploadFiles.Output
     @Schema(
         title = "A list of files.",
         description = "This can be a list of strings, where each string can be either a regex glob pattern or a file path. Providing a list requires specifying a `destination` where files will be stored.\n" +
-                    "This can also be a map where you can provide a specific destination path for a URI, which can be useful if you need to rename a file or move it to a different folder.",
-        anyOf = {List.class, Map.class}
+                    "This can also be a map where you can provide a specific destination path for a URI, which can be useful if you need to rename a file or move it to a different folder.\n" +
+                    "Finally, this can also be a string if its a pebble expression that render to a list or a map, or a single URI (that will be handle like a list of one).",
+        anyOf = {List.class, Map.class, String.class}
     )
     @PluginProperty(dynamic = true)
     private Object files;
@@ -105,10 +110,12 @@ public class UploadFiles extends Task implements RunnableTask<UploadFiles.Output
 
         final Namespace storageNamespace = runContext.storage().namespace(renderedNamespace);
 
+        if (files instanceof String filesString) {
+            // check if rendered filesString is a map, a list or a string
+            files = renderFilesString(runContext, filesString);
+        }
+
         if (files instanceof List<?> filesList) {
-            if (renderedDestination == null) {
-                throw new RuntimeException("Destination must be set when providing a List for the `files` property.");
-            }
             filesList = runContext.render((List<String>) filesList);
 
             final List<String> regexs = new ArrayList<>();
@@ -150,6 +157,9 @@ public class UploadFiles extends Task implements RunnableTask<UploadFiles.Output
                     throw new IllegalArgumentException("files must be a List<String> or a Map<String, String>");
                 }
             }
+        } else {
+            throw new IllegalArgumentException("Files must be a List<String> or a Map<String, String>");
+
         }
 
         return Output.builder().build();
@@ -161,4 +171,17 @@ public class UploadFiles extends Task implements RunnableTask<UploadFiles.Output
         private final Map<String, URI> files;
     }
 
+    private Object renderFilesString(RunContext runContext, String filesString) throws IllegalVariableEvaluationException, JsonProcessingException {
+        String rendered = runContext.render(filesString);
+        if (runContext.storage().isFileExist(URI.create(rendered))) {
+            return List.of(rendered);
+        } else {
+            try {
+                return JacksonMapper.ofJson().readValue(rendered, Map.class);
+            } catch (JsonMappingException e) {
+                return JacksonMapper.ofJson().readValue(rendered, List.class);
+            }
+        }
+    }
+
 }
diff --git a/platform/build.gradle b/platform/build.gradle
index b7283ff83..183bebc7a 100644
--- a/platform/build.gradle
+++ b/platform/build.gradle
@@ -115,7 +115,7 @@ dependencies {
         api group: 'org.exparity', name: 'hamcrest-date', version: '2.0.8'
         api 'com.github.tomakehurst:wiremock-jre8:3.0.1'
         api "org.apache.kafka:kafka-streams-test-utils:$kafkaVersion"
-        api "com.microsoft.playwright:playwright:1.44.0"
+        api "com.microsoft.playwright:playwright:1.45.0"
 
         // Kestra components
         api "io.kestra:core:$version"


Test patch:
diff --git a/e2e-tests/build.gradle b/e2e-tests/build.gradle
index 5a23988c9..77dfcd9bf 100644
--- a/e2e-tests/build.gradle
+++ b/e2e-tests/build.gradle
@@ -4,7 +4,7 @@ configurations {
 
 dependencies {
     testImplementation project(':tests')
-    testImplementation("com.microsoft.playwright:playwright:1.44.0")
+    testImplementation("com.microsoft.playwright:playwright:1.45.0")
 }
 
 /**********************************************************************************************************************\