This is an automated email from the ASF dual-hosted git repository.

bamaer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git


The following commit(s) were added to refs/heads/main by this push:
     new 8f614e8045 fix folder check button, fixes #8252 (#9015)
8f614e8045 is described below

commit 8f614e8045d7f7f6fee37bcb206402ead3af9a59
Author: Hans Van Akelyen <[email protected]>
AuthorDate: Mon Oct 19 17:14:06 2026 +0200

    fix folder check button, fixes #8252 (#9015)
---
 .../apache/hop/workflow/actions/ftp/ActionFtp.java | 20 +++++++
 .../hop/workflow/actions/ftp/ActionFtpDialog.java  | 62 ++++++++++++++--------
 .../actions/ftp/ActionFtpExecutionTest.java        | 47 ++++++++++++++++
 3 files changed, 108 insertions(+), 21 deletions(-)

diff --git 
a/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtp.java
 
b/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtp.java
index 848f0e284f..a76c6b553f 100644
--- 
a/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtp.java
+++ 
b/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtp.java
@@ -18,6 +18,7 @@
 package org.apache.hop.workflow.actions.ftp;
 
 import com.google.common.annotations.VisibleForTesting;
+import java.io.IOException;
 import java.io.OutputStream;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -485,6 +486,25 @@ public class ActionFtp extends ActionBase implements 
Cloneable, IAction, IFtpCon
     return normalizedPath;
   }
 
+  /**
+   * Change into each folder in turn, the way the action does when it runs: 
the remote directory
+   * from the folder the login lands in, the move-to folder from inside the 
remote directory. The
+   * dialog checks its folders with this.
+   *
+   * @param ftpClient a logged in client, left in the last folder it could 
change into
+   * @param folders the resolved and normalized folders, the remote directory 
first
+   * @return the first folder which isn't there, or null when they all are
+   */
+  public static String findMissingFolder(FTPClient ftpClient, String... 
folders)
+      throws IOException {
+    for (String folder : folders) {
+      if (!ftpClient.changeWorkingDirectory(folder)) {
+        return folder;
+      }
+    }
+    return null;
+  }
+
   private void addFilenameToResultFilenames(
       Result result, IWorkflowEngine<WorkflowMeta> parentWorkflow, String 
filename)
       throws HopException {
diff --git 
a/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtpDialog.java
 
b/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtpDialog.java
index 3a995c5c1e..a8e56597e3 100644
--- 
a/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtpDialog.java
+++ 
b/plugins/tech/ftp/src/main/java/org/apache/hop/workflow/actions/ftp/ActionFtpDialog.java
@@ -17,6 +17,7 @@
 
 package org.apache.hop.workflow.actions.ftp;
 
+import java.util.Arrays;
 import org.apache.commons.net.ftp.FTPClient;
 import org.apache.hop.core.Const;
 import org.apache.hop.core.Props;
@@ -1209,7 +1210,7 @@ public class ActionFtpDialog extends ActionDialog {
     // Add listeners
     wTest.addListener(SWT.Selection, e -> test());
     wbTestFolderExists.addListener(
-        SWT.Selection, e -> checkRemoteFolder(wMoveToDirectory.getText()));
+        SWT.Selection, e -> checkRemoteFolder(wFtpDirectory.getText(), 
wMoveToDirectory.getText()));
     wbTestChangeFolderExists.addListener(
         SWT.Selection, e -> checkRemoteFolder(wFtpDirectory.getText()));
 
@@ -1244,29 +1245,48 @@ public class ActionFtpDialog extends ActionDialog {
     closeFtpConnection();
   }
 
-  private void checkRemoteFolder(String folderName) {
-    if (!Utils.isEmpty(folderName) && connectToFtp()) {
-      try {
-        boolean exists = ftpclient.changeWorkingDirectory(folderName);
-        if (exists) {
-          MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_INFORMATION);
-          mb.setMessage(
-              BaseMessages.getString(PKG, "ActionFtp.FolderExists.OK", 
folderName) + Const.CR);
-          mb.setText(BaseMessages.getString(PKG, 
"ActionFtp.FolderExists.Title.Ok"));
-          mb.open();
-        } else {
-          MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
-          mb.setMessage(
-              BaseMessages.getString(PKG, "ActionFtp.FolderExists.NOK", 
folderName) + Const.CR);
-          mb.setText(BaseMessages.getString(PKG, 
"ActionFtp.FolderExists.Title.Bad"));
-          mb.open();
-        }
-      } catch (Exception e) {
+  /**
+   * Check a remote folder the way the action finds it when it runs, on a 
fresh login. A client kept
+   * open between checks is still in the folder the previous check changed 
into, which made a
+   * relative folder look missing the second time it was checked.
+   *
+   * @param folders the folders to change into in turn, the one to check last
+   */
+  private void checkRemoteFolder(String... folders) {
+    if (Utils.isEmpty(folders[folders.length - 1])) {
+      return;
+    }
+    String[] path =
+        Arrays.stream(folders)
+            .filter(folder -> !Utils.isEmpty(folder))
+            .map(folder -> action.normalizePath(variables.resolve(folder)))
+            .toArray(String[]::new);
+    try {
+      if (!connectToFtp()) {
+        return;
+      }
+      String missing = ActionFtp.findMissingFolder(ftpclient, path);
+      if (missing == null) {
+        MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_INFORMATION);
+        mb.setMessage(
+            BaseMessages.getString(PKG, "ActionFtp.FolderExists.OK", 
path[path.length - 1])
+                + Const.CR);
+        mb.setText(BaseMessages.getString(PKG, 
"ActionFtp.FolderExists.Title.Ok"));
+        mb.open();
+      } else {
         MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
-        mb.setMessage("Error checking remote folder: " + e.getMessage());
-        mb.setText("Folder Check Failed");
+        mb.setMessage(
+            BaseMessages.getString(PKG, "ActionFtp.FolderExists.NOK", missing) 
+ Const.CR);
+        mb.setText(BaseMessages.getString(PKG, 
"ActionFtp.FolderExists.Title.Bad"));
         mb.open();
       }
+    } catch (Exception e) {
+      MessageBox mb = new MessageBox(shell, SWT.OK | SWT.ICON_ERROR);
+      mb.setMessage("Error checking remote folder: " + e.getMessage());
+      mb.setText("Folder Check Failed");
+      mb.open();
+    } finally {
+      closeFtpConnection();
     }
   }
 
diff --git 
a/plugins/tech/ftp/src/test/java/org/apache/hop/workflow/actions/ftp/ActionFtpExecutionTest.java
 
b/plugins/tech/ftp/src/test/java/org/apache/hop/workflow/actions/ftp/ActionFtpExecutionTest.java
index 74734edaa6..68b1baa7fb 100644
--- 
a/plugins/tech/ftp/src/test/java/org/apache/hop/workflow/actions/ftp/ActionFtpExecutionTest.java
+++ 
b/plugins/tech/ftp/src/test/java/org/apache/hop/workflow/actions/ftp/ActionFtpExecutionTest.java
@@ -28,11 +28,13 @@ import static org.mockito.Mockito.when;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Comparator;
+import org.apache.commons.net.ftp.FTPClient;
 import org.apache.hop.core.HopEnvironment;
 import org.apache.hop.core.Result;
 import org.apache.hop.core.logging.LogLevel;
 import org.apache.hop.metadata.api.IHopMetadataProvider;
 import org.apache.hop.metadata.serializer.memory.MemoryMetadataProvider;
+import org.apache.hop.vfs.ftp.FtpHelper;
 import org.apache.hop.vfs.ftp.FtpSecurityMode;
 import org.apache.hop.vfs.ftp.FtpTestServer;
 import org.apache.hop.vfs.ftp.metadata.FtpConnection;
@@ -431,6 +433,51 @@ class ActionFtpExecutionTest {
     assertEquals("from the outbox", 
Files.readString(targetDir.resolve("wanted.txt")));
   }
 
+  /**
+   * The "Check folder" buttons of the dialog have to find a folder where the 
action does: a
+   * relative move-to folder inside the remote directory.
+   */
+  @Test
+  @DisplayName("The folder check finds a relative move-to folder where the 
action does")
+  void theFolderCheckFollowsTheAction(@TempDir Path targetDir) throws 
Exception {
+    Files.createDirectories(serverRoot.resolve("outbox/done"));
+    server.writeFile("outbox/moved.txt", "move me");
+
+    ActionFtp action = configure(targetDir);
+    action.setRemoteDirectory("outbox");
+    action.setMoveFiles(true);
+    action.setMoveToDirectory("done");
+
+    FTPClient client = FtpHelper.connect(action, null);
+    try {
+      assertNull(ActionFtp.findMissingFolder(client, "outbox", "done"));
+    } finally {
+      FtpHelper.disconnect(action.getLogChannel(), client);
+    }
+
+    Result result = action.execute(new Result(), 0);
+
+    assertTrue(result.isResult());
+    assertEquals("move me", server.readFile("outbox/done/moved.txt"));
+  }
+
+  @Test
+  @DisplayName("The folder check names the first folder which isn't there")
+  void theFolderCheckNamesTheMissingFolder(@TempDir Path targetDir) throws 
Exception {
+    Files.createDirectories(serverRoot.resolve("outbox/done"));
+
+    ActionFtp action = configure(targetDir);
+    FTPClient client = FtpHelper.connect(action, null);
+    try {
+      String home = client.printWorkingDirectory();
+      assertEquals("not-there", ActionFtp.findMissingFolder(client, 
"not-there", "done"));
+      client.changeWorkingDirectory(home);
+      assertEquals("not-there", ActionFtp.findMissingFolder(client, "outbox", 
"not-there"));
+    } finally {
+      FtpHelper.disconnect(action.getLogChannel(), client);
+    }
+  }
+
   @Test
   @DisplayName("A unique name is found for a file which has no extension 
either")
   void createUniqueForAFileWithoutAnExtension(@TempDir Path targetDir) throws 
Exception {

Reply via email to