Skip to content

Strategy/Scala: route sbt 1.4+ with explicit DependencyTreePlugin to built-in command (TKT-15490)#1711

Draft
zlav wants to merge 5 commits into
masterfrom
fix-sbt-dependency-tree-html-routing
Draft

Strategy/Scala: route sbt 1.4+ with explicit DependencyTreePlugin to built-in command (TKT-15490)#1711
zlav wants to merge 5 commits into
masterfrom
fix-sbt-dependency-tree-html-routing

Conversation

@zlav
Copy link
Copy Markdown
Member

@zlav zlav commented May 12, 2026

Overview

On sbt 1.4+ projects that load DependencyTreePlugin via addDependencyTreePlugin (without the auto-loaded MiniDependencyTreePlugin), fossa analyze ran the lowercase task dependencyBrowseTreeHtml. Modern sbt only exposes the uppercase dependencyBrowseTreeHTML, so the task failed and deep-dependency analysis silently fell back to a poms-only graph.

The detection logic now distinguishes the legacy net.virtualvoid.sbt.graph.DependencyGraphPlugin (sbt < 1.4, lowercase task) from the modern sbt.plugins.DependencyTreePlugin (sbt 1.4+, uppercase task) and picks the right task name per kind. The built-in MiniDependencyTreePlugin path is unchanged and still preferred when present.

Acceptance criteria

fossa analyze produces a complete deep-dependency graph on sbt 1.4+ projects that enable addDependencyTreePlugin.

Testing plan

  • New unit test for the regression case (modern plugin alone → uppercase task).
  • New unit test for "both modern and legacy detected" (modern wins).
  • Existing Scala.PluginSpec detection cases still pass.
  • cabal test unit-tests --test-options="--match \"detectDependencyPlugins\"" — 7/7 pass.

Risks

hasDependencyPlugins now returns a DependencyPluginsDetected record instead of (Bool, Bool). One internal call site (Strategy.Scala.findProjects) updated in this PR.

Metrics

N/A.

References

Checklist

  • I added tests for this PR's change.
  • If this PR introduced a user-visible change, I added documentation into docs/ (Changelog.md ## Unreleased).
  • N/A — no docs ToC change.
  • Changelog updated.
  • N/A — no .fossa.yml or fossa-deps schema changes.
  • N/A — no subcommand option changes.

… task

When a project explicitly enables `addDependencyTreePlugin` on sbt 1.4+,
fossa-cli detected `sbt.plugins.DependencyTreePlugin` and dispatched to
the same path used by the legacy `net.virtualvoid.sbt.graph.DependencyGraphPlugin`,
which runs the lowercase `dependencyBrowseTreeHtml` task. sbt 1.4+ only
exposes the uppercase `dependencyBrowseTreeHTML`, so the task failed and
the analyzer silently dropped deep dependencies.

Distinguish the two plugins at detection time and pick the correct task
casing per plugin.

TKT-15490 / ANE-2718.
@zlav
Copy link
Copy Markdown
Member Author

zlav commented May 13, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Review Change Stack

Walkthrough

This PR refactors Scala sbt plugin detection from boolean tuple results to structured types. New types DependencyTreePluginKind and DependencyPluginsDetected replace tuple returns in hasDependencyPlugins, detectDependencyPlugins, and genTreeJson. The detection logic now classifies plugins as modern or legacy with modern preference when both exist. A new mkDependencyBrowseTreeCmd helper maps plugin kinds to correct sbt task names (dependencyBrowseTreeHTML for modern, dependencyBrowseTreeHtml for legacy). The strategy layer imports and destructures the new record type, extracting the optional plugin kind and passing it to tree generation. Tests and fixtures are updated to validate the new behavior.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: routing sbt 1.4+ projects with explicit DependencyTreePlugin to the correct built-in command, with a reference to the issue tracker.
Description check ✅ Passed The PR description comprehensively covers all required template sections: overview, acceptance criteria, testing plan with specific test cases, risks, metrics, references with ticket links, and a completed checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix-sbt-dependency-tree-html-routing

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Strategy/Scala.hs (1)

206-212: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consider making context and error messages task-agnostic.

The context message on line 206 and error message on line 212 both hardcode dependencyBrowseTreeHTML, but with the new routing logic the actual task executed could be either dependencyBrowseTreeHTML (modern) or dependencyBrowseTreeHtml (legacy) depending on the detected plugin kind. While these messages appear in a code path that runs after tree JSON generation (and thus don't directly cause incorrect behavior), using a generic message like "Analyzing sbt dependencies using dependency tree JSON" would be more accurate and less confusing for users who might see the legacy task invoked.

📝 Suggested message updates
-analyzeWithDepTreeJson (ScalaProject _ treeJson closure) = context "Analyzing sbt dependencies using dependencyBrowseTreeHTML" $ do
+analyzeWithDepTreeJson (ScalaProject _ treeJson closure) = context "Analyzing sbt dependencies using dependency tree JSON" $ do
   treeJson' <-
     errCtx MissingFullDependencyPluginCtx $
       errHelp MissingFullDependencyPluginHelp $
         errDoc sbtDepsGraphPluginUrl $
           errDoc scalaFossaDocUrl $
-            fromMaybeText "Could not retrieve output from sbt dependencyBrowseTreeHTML" treeJson
+            fromMaybeText "Could not retrieve dependency tree JSON output from sbt" treeJson
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Strategy/Scala.hs` around lines 206 - 212, The context and error messages
in analyzeWithDepTreeJson (pattern ScalaProject _ treeJson closure) hardcode
dependencyBrowseTreeHTML which can be either dependencyBrowseTreeHTML or
dependencyBrowseTreeHtml; update the context string and the fromMaybeText error
message to be task-agnostic (e.g., "Analyzing sbt dependencies using dependency
tree JSON" and "Could not retrieve output from sbt dependency tree JSON") so
they accurately reflect either modern or legacy task execution while still
referencing treeJson/ScalaProject/analyzeWithDepTreeJson to locate the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/Strategy/Scala.hs`:
- Around line 206-212: The context and error messages in analyzeWithDepTreeJson
(pattern ScalaProject _ treeJson closure) hardcode dependencyBrowseTreeHTML
which can be either dependencyBrowseTreeHTML or dependencyBrowseTreeHtml; update
the context string and the fromMaybeText error message to be task-agnostic
(e.g., "Analyzing sbt dependencies using dependency tree JSON" and "Could not
retrieve output from sbt dependency tree JSON") so they accurately reflect
either modern or legacy task execution while still referencing
treeJson/ScalaProject/analyzeWithDepTreeJson to locate the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro

Run ID: f374c435-f539-45fd-b422-6fda86503657

📥 Commits

Reviewing files that changed from the base of the PR and between ae690f8 and fe7b09d.

📒 Files selected for processing (4)
  • Changelog.md
  • src/Strategy/Scala.hs
  • src/Strategy/Scala/Plugin.hs
  • test/Scala/PluginSpec.hs

zlav and others added 3 commits May 12, 2026 17:23
The context label and error text mentioned dependencyBrowseTreeHTML, but
the routing change can also pick the legacy dependencyBrowseTreeHtml task.
Reword to "dependency tree JSON" so the message is correct in both cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
`sbt plugins` lists user-disabled plugins (`disablePlugins(...)`) with
a ": disabled in <scope>" suffix. The pre-existing substring match on
the bare FQCN counted those as present, which routed `findProjects`
to a task the active plugin set does not provide — same shape as the
TKT-15490 regression, different trigger.

Detection now requires "<FQCN>: enabled in" verbatim. Fixtures cover
the two disabled cases (mini disabled, modern disabled), both
expected to classify as Nothing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant