Skip to content

fix: detect the project folder of a Gradle module from the classpath (#25632) (CP: 25.3) - #25645

Merged
vaadin-bot merged 1 commit into
25.3from
cherry-pick-25632-to-25.3-1789049611442
Sep 10, 2026
Merged

fix: detect the project folder of a Gradle module from the classpath (#25632) (CP: 25.3)#25645
vaadin-bot merged 1 commit into
25.3from
cherry-pick-25632-to-25.3-1789049611442

Conversation

@vaadin-bot

Copy link
Copy Markdown
Collaborator

This PR cherry-picks changes from the original PR #25632 to branch 25.3.

Original PR description

Summary

In development mode Vaadin finds the project folder from the classpath, but it only knew Maven's target/classes. A Gradle project fell back to the working directory, so an app started from the root of a multi-project build prepared its frontend in the root project instead of in the module being run. This change teaches the detection about Gradle's output folders.

Fixes #25630

What changed

  • FileIOUtils.getProjectFolderFromClasspath now also recognizes the two Gradle source set output layouts: <buildDir>/classes/<language>/<sourceSet> and <buildDir>/resources/<sourceSet>.
  • The build directory name is configurable in Gradle, so a candidate folder is accepted only when it really belongs to a Gradle build: it has a build.gradle/build.gradle.kts of its own, or it lies inside a build whose root has a settings.gradle/settings.gradle.kts. The settings check is needed because a subproject that the root project configures has no build script of its own.
  • The resources layout is checked before the classes one. A build directory named classes makes the two overlap (<project>/classes/resources/main), and the classes layout would climb one level too far.

Background: since the Gradle plugin no longer runs vaadinPrepareFrontend in development mode, there is no flow-build-info.json carrying project.basedir. With an IDE run configuration the working directory is the root project, which has a build script, so the old fallback accepted it and generated package.json, node_modules and src/main/frontend in the wrong place.

Test summary

# Status What the test verifies Why it matters
1 build/classes/java/main resolves to the project folder The main fix: Gradle classes output must be recognized
2 out/resources/main (custom build dir name) resolves to the project folder Resources-only output and non-default build dir names must work
3 With a build dir named classes, classes/resources/main still resolves to the project folder, not its parent Overlapping layouts must not climb one level too far
4 A module with no build script resolves when the root has settings.gradle or settings.gradle.kts Subprojects configured from the root are common and were previously missed
5 A matching folder outside any Gradle build returns null The build dir name is configurable, so name matching alone would claim unrelated paths
6 An app run with the build root as working directory reports the module folder as project folder and <module>/src/main/frontend as frontend folder End-to-end proof of the reported bug: frontend files must not land in the root project
  • FileIOUtilsTest.projectFolderForGradleClassesFolder → 1
  • FileIOUtilsTest.projectFolderForGradleResourcesFolderInCustomBuildFolder → 2
  • FileIOUtilsTest.projectFolderForGradleResourcesFolderInBuildFolderNamedClasses → 3
  • FileIOUtilsTest.projectFolderForGradleModuleWithoutBuildScript (parameterized over both settings script DSLs) → 4
  • FileIOUtilsTest.noProjectFolderForClassesFolderOutsideGradleBuild → 5
  • MiscMultiModuleTest.dev mode project folder is the module folder, not the working directory → 6

Left untested on purpose: the Maven target/classes path and the Windows/Unix path handling, which existing tests in FileIOUtilsTest already cover and this change does not touch.

…25632)

## Summary
In development mode Vaadin finds the project folder from the classpath,
but it only knew Maven's `target/classes`. A Gradle project fell back to
the working directory, so an app started from the root of a
multi-project build prepared its frontend in the root project instead of
in the module being run. This change teaches the detection about
Gradle's output folders.

Fixes #25630

## What changed
- `FileIOUtils.getProjectFolderFromClasspath` now also recognizes the
two Gradle source set output layouts:
`<buildDir>/classes/<language>/<sourceSet>` and
`<buildDir>/resources/<sourceSet>`.
- The build directory name is configurable in Gradle, so a candidate
folder is accepted only when it really belongs to a Gradle build: it has
a `build.gradle`/`build.gradle.kts` of its own, or it lies inside a
build whose root has a `settings.gradle`/`settings.gradle.kts`. The
settings check is needed because a subproject that the root project
configures has no build script of its own.
- The resources layout is checked before the classes one. A build
directory named `classes` makes the two overlap
(`<project>/classes/resources/main`), and the classes layout would climb
one level too far.

Background: since the Gradle plugin no longer runs
`vaadinPrepareFrontend` in development mode, there is no
`flow-build-info.json` carrying `project.basedir`. With an IDE run
configuration the working directory is the root project, which has a
build script, so the old fallback accepted it and generated
`package.json`, `node_modules` and `src/main/frontend` in the wrong
place.

## Test summary

| # | Status | What the test verifies | Why it matters |
|---|--------|------------------------|----------------|
| 1 | ✅ | `build/classes/java/main` resolves to the project folder | The
main fix: Gradle classes output must be recognized |
| 2 | ✅ | `out/resources/main` (custom build dir name) resolves to the
project folder | Resources-only output and non-default build dir names
must work |
| 3 | ✅ | With a build dir named `classes`, `classes/resources/main`
still resolves to the project folder, not its parent | Overlapping
layouts must not climb one level too far |
| 4 | ✅ | A module with no build script resolves when the root has
`settings.gradle` or `settings.gradle.kts` | Subprojects configured from
the root are common and were previously missed |
| 5 | ✅ | A matching folder outside any Gradle build returns `null` |
The build dir name is configurable, so name matching alone would claim
unrelated paths |
| 6 | ✅ | An app run with the build root as working directory reports
the module folder as project folder and `<module>/src/main/frontend` as
frontend folder | End-to-end proof of the reported bug: frontend files
must not land in the root project |

- `FileIOUtilsTest.projectFolderForGradleClassesFolder` → 1
-
`FileIOUtilsTest.projectFolderForGradleResourcesFolderInCustomBuildFolder`
→ 2
-
`FileIOUtilsTest.projectFolderForGradleResourcesFolderInBuildFolderNamedClasses`
→ 3
- `FileIOUtilsTest.projectFolderForGradleModuleWithoutBuildScript`
(parameterized over both settings script DSLs) → 4
- `FileIOUtilsTest.noProjectFolderForClassesFolderOutsideGradleBuild` →
5
- `MiscMultiModuleTest.dev mode project folder is the module folder, not
the working directory` → 6

Left untested on purpose: the Maven `target/classes` path and the
Windows/Unix path handling, which existing tests in `FileIOUtilsTest`
already cover and this change does not touch.

---------

Co-authored-by: totally-not-ai[bot] <290682512+totally-not-ai[bot]@users.noreply.github.com>
@vaadin-bot

Copy link
Copy Markdown
Collaborator Author

This PR is eligible for auto-merging policy, so it has been approved automatically. If there are pending conditions, auto merge (with 'squash' method) has been enabled for this PR [Message is sent from bot]

@vaadin-bot
vaadin-bot enabled auto-merge (squash) September 10, 2026 14:26
@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Test Results

 1 439 files  ±0   1 523 suites  ±0   1h 32m 16s ⏱️ - 3m 57s
12 036 tests +6  11 968 ✅ +6  68 💤 ±0  0 ❌ ±0 
12 354 runs  +6  12 286 ✅ +6  68 💤 ±0  0 ❌ ±0 

Results for commit 84db1f9. ± Comparison against base commit cee0b87.

@vaadin-bot
vaadin-bot merged commit 0390d74 into 25.3 Sep 10, 2026
42 checks passed
@vaadin-bot
vaadin-bot deleted the cherry-pick-25632-to-25.3-1789049611442 branch September 10, 2026 14:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants