You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by GitBox <gi...@apache.org> on 2026/10/20 21:21:23 UTC

[GH] (grails-intellij-plugin/feature/custom-folders): Workflow run "Licensing - RAT Report" failed!

The GitHub Actions job "Licensing - RAT Report" on grails-intellij-plugin.git/feature/custom-folders has failed.
Run started by GitHub user amondel2 (triggered by amondel2).

Head commit for run:
dd808bfbb0ed7ebda2f960428662b32c2d1827d6 / aaron <am...@gmail.com>
Add configurable custom folders to the Grails project view

The Grails pane rendered grails-app's fixed set of directories and the
test roots. This adds custom folders on top: paths (global defaults
plus a per-project override) that appear as nodes under the application
node, editable on a settings page and manageable from the tree with Add
as Custom Folder, Remove Custom Folder and Configure Custom Folders.

The shape that survived review, and why it is this shape:

- Two node kinds behind one interface. A folder that resolves on disk is
  a GrailsPsiDirectoryNode subclass, so its value is the PsiDirectory.
  That is what makes the node traversable: an AbstractTreeNode<String>
  puts no PSI_ELEMENT or VIRTUAL_FILE in the data context, and
  ProjectViewNodeVisitor.getContent answers null for it, so the visitor
  returns SKIP_CHILDREN even when the node's own contains() returns
  true -- Reveal and Select Opened File dead-end and New, Copy Path,
  Find in Files, Open In and Delete do nothing. A path that resolves to
  nothing keeps a separate lightweight placeholder and is the only
  AbstractTreeNode<String> left in the feature; it stays visible so a
  typo is removable from the settings page rather than invisible.
  GrailsCustomFolder exposes getConfiguredPath()/getNodeWeight(), so
  GrailsNodeComparator and the three actions need a single instanceof.

- One path base, the Grails application root, on both sides. Add used to
  store a path relative to Project.getBaseDir() while the provider
  resolved it against application.getRoot(), so in a multi-project build
  with the app in app/, adding app/docs stored "app/docs" and rendered a
  placeholder for app/app/docs. Both now go through
  findApplication(dir).getRoot(), and getBaseDir() no longer appears in
  plugin/src/main. A directory belonging to no Grails application is not
  offered at all, and a directory outside the application root has no
  path to store against that base.

- No absolute paths. The provider resolves a relative path against the
  application root and nothing else, and apply() rejects an absolute
  path, an escaping "..", and a path resolving outside the root,
  naming the row it came from. Validation normalizes the row before
  checking it, so a stray leading space does not buy a path the trimmed
  form would be refused. A stored path that stops resolving becomes a
  placeholder rather than disappearing. External directories stay a
  tracked follow-up in IMPROVEMENT-PLAN.md 2.8.

- The cap is a setting, not a constant, and it is applied only when the
  view is built. MAX_FOLDERS = 3 was applied when folders were saved, so
  lowering it would have deleted configuration. maxFolders is persisted
  global state (default 6, range 1-20), edited with a spinner; lowering
  it now changes what renders without touching what is stored. The four
  copies of the normalize/dedupe loop collapse into FolderPaths.dedupe
  and both MAX_FOLDERS constants are gone.

- Refreshes go through a message bus. Pane refreshes used to be direct
  GrailsProjectViewPanes.refresh calls from the services, so editing the
  global defaults left every other open project stale and
  FoldersChangedListener had no subscriber at all. A
  GrailsCustomFoldersRefreshListener project activity subscribes to the
  project topic, the new application topic and VFS_CHANGES, and
  coalesces them through one flag held per project: one Apply costs one
  rebuild per open project, and a build that creates build/ turns its
  placeholder into a real folder. The flag is read off the project
  rather than captured per execute() because postStartupActivity also
  runs under unit-test mode, which would otherwise give two registrations
  and two rebuilds for one change.

- The settings page lives at Languages & Frameworks > Grails, with no
  empty parent page, and the two text areas are scrollable one-line rows
  with a + button and a per-row remove. Any number of rows survives;
  the cap truncates only the preview and the rendered tree. Global
  defaults are validated on shape alone rather than against an
  application root, because each open project has its own root and a
  path that resolves in one need not resolve in another.

Supporting changes: the three actions read
PlatformCoreDataKeys.SELECTED_ITEMS rather than
getCurrentProjectViewPane().getSelectedPath(), so no update() touches
the Swing tree from its background thread; Add refuses a folder the
Grails view already renders, project or global; GrailsApplicationManager
starts its upward walk at the file itself when the file has no content
root, so Gradle's excluded build/ and .gradle/ resolve to their
application instead of to nothing; a failing view provider is logged as
an error rather than a warning.

Reveal is asserted through AbstractProjectViewPane.createVisitor, the
visitor the pane actually uses, rather than on the node's own contains()
-- which is what made the original test unable to fail, since the node
under test returned true. README.md, IMPROVEMENT-PLAN.md 2.8 and the
settings page state one rule; the claim that hidden directories are
filtered was checked against the platform's default Ignored Files and
Folders list and is false, so the docs were corrected rather than the
claim restated.

The feature is unreleased, so none of this reaches a user who was
already running it.

# Conflicts:
#	IMPROVEMENT-PLAN.md
#	README.md
#	plugin/src/main/java/org/apache/grails/intellij/plugin/actions/AddCustomFolderAction.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/actions/ConfigureCustomFoldersAction.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/actions/RemoveCustomFolderAction.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/config/FolderPaths.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersAppService.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersConfigurable.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersProjectService.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/projectView/impl/GrailsCustomFoldersNodeProvider.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/projectView/impl/GrailsNodeComparator.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/projectView/nodes/GrailsApplicationNode.java
#	plugin/src/main/java/org/apache/grails/intellij/plugin/projectView/nodes/GrailsCustomFolderNode.java
#	plugin/src/main/resources/META-INF/plugin.xml
#	plugin/src/test/java/org/apache/grails/intellij/plugin/actions/CustomFoldersActionTest.java
#	plugin/src/test/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersAppServiceTest.java
#	plugin/src/test/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersConfigurableTest.java
#	plugin/src/test/java/org/apache/grails/intellij/plugin/config/GrailsCustomFoldersProjectServiceTest.java
#	plugin/src/test/java/org/apache/grails/intellij/plugin/projectView/GrailsCustomFoldersPaneTest.java
#	plugin/src/test/java/org/apache/grails/intellij/plugin/projectView/impl/GrailsCustomFoldersNodeProviderTest.java

Report URL: https://github.com/apache/grails-intellij-plugin/actions/runs/38838760765

With regards,
GitHub Actions via GitBox