Use FileUtils.moveDirectory to support cross-filesystem moves by alphae-nix · Pull Request #343 · Cosium/git-code-format-maven-plugin
Problem
When running tests locally with ./mvnw --batch-mode clean verify, moveFiles() fails with:
java.nio.file.DirectoryNotEmptyException: /tmp/git-code-format-maven-plugin-test3626331939795592289/NonRootModuleTest_GIVEN_bad_formatted_files_WHEN_format_code_THEN_all_files_should_have_correct_format[3.5.0]_non-root-module at java.base/sun.nio.fs.UnixFileSystem.ensureEmptyDir(UnixFileSystem.java:797) at java.base/sun.nio.fs.UnixFileSystem.move(UnixFileSystem.java:900) at java.base/sun.nio.fs.UnixFileSystemProvider.move(UnixFileSystemProvider.java:289) at java.base/java.nio.file.Files.move(Files.java:1319) at com.cosium.code.format.AbstractTest.moveFiles(AbstractTest.java:148) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) at java.base/java.lang.reflect.Method.invoke(Method.java:565) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
Root cause
On Ubunut, /tmp is mounted as tmpfs, while the project directory lives on a disk filesystem (ext4, in my case).
Files.move() delegates to UnixFileSystemProvider.move() → UnixFileSystem.move() → UnixCopyFile.move(), which calls the native method rename. This native method wraps the Linux rename syscall, which fails with cross-device link
error when source and target are on different filesystems. Java handles this fallback for files (copy + delete) with the copyOption, but for non-empty directories it has no recursive fallback it calls ensureEmptyDir() on the source and immediately throws DirectoryNotEmptyException. cf. this comment on Files.move
Why it passes on GitHub Actions and not locally
The repo GitHub Actions Ubuntu runners do not mount /tmp as tmpfs, it is part of the root filesystem. Source and target are on the same filesystem, rename succeeds, and the tests pass. cf this comment
Fix
Replace Files.move() with FileUtils.moveDirectory(), which performs a recursive copy + delete and correctly handles cross-filesystem directory moves