diff --git a/Changelog.md b/Changelog.md index 432dfb6a8..e4dd21ffe 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,9 @@ # FOSSA CLI Changelog +## Unreleased + +- Scala/sbt: Route projects using `addDependencyTreePlugin` (sbt 1.4+) to the correct `dependencyBrowseTreeHTML` task, restoring deep dependencies. ([#1711](https://github.com/fossas/fossa-cli/pull/1711)) + ## 3.17.11 - Conan: Handle list-valued license in make_fossa_deps_conan ([#1719](https://github.com/fossas/fossa-cli/pull/1719)). diff --git a/src/Strategy/Scala.hs b/src/Strategy/Scala.hs index 6b85919f4..dbcd3278f 100644 --- a/src/Strategy/Scala.hs +++ b/src/Strategy/Scala.hs @@ -60,7 +60,7 @@ import Strategy.Maven.Pom.PomFile (RawPom (rawPomArtifact, rawPomGroup, rawPomVe import Strategy.Maven.Pom.Resolver (buildGlobalClosure) import Strategy.Scala.Common (mkSbtCommand) import Strategy.Scala.Errors (FailedToListProjects (FailedToListProjects), MaybeWithoutDependencyTreeTask (..), MissingFullDependencyPlugin (..), sbtDepsGraphPluginUrl, scalaFossaDocUrl) -import Strategy.Scala.Plugin (genTreeJson, hasDependencyPlugins) +import Strategy.Scala.Plugin (DependencyPluginsDetected (..), genTreeJson, hasDependencyPlugins) import Strategy.Scala.SbtDependencyTree (SbtArtifact (SbtArtifact), analyze, sbtDepTreeCmd) import Strategy.Scala.SbtDependencyTreeJson qualified as TreeJson import Types ( @@ -161,10 +161,10 @@ findProjects = walkWithFilters' $ \dir _ files -> do . context ("Listing sbt projects at " <> pathToText dir) $ genPoms dir - (miniDepPlugin, depPlugin) <- hasDependencyPlugins dir - case (projectsRes, miniDepPlugin, depPlugin) of + DependencyPluginsDetected{hasMiniDependencyTreePlugin, dependencyTreePlugin} <- hasDependencyPlugins dir + case (projectsRes, hasMiniDependencyTreePlugin, dependencyTreePlugin) of (Nothing, _, _) -> pure ([], WalkSkipAll) - (Just projects, False, False) -> pure ([SbtTargets Nothing [] projects], WalkSkipAll) + (Just projects, False, Nothing) -> pure ([SbtTargets Nothing [] projects], WalkSkipAll) (Just projects, True, _) -> do -- project is using miniature dependency tree plugin, -- which is included by default with sbt 1.4+ @@ -184,9 +184,13 @@ findProjects = walkWithFilters' $ \dir _ files -> do (True, _) -> pure ([SbtTargets Nothing [] projects], WalkSkipAll) (_, Just _) -> pure ([SbtTargets depTreeStdOut [] projects], WalkSkipAll) (_, _) -> pure ([], WalkSkipAll) - (Just projects, False, True) -> do - -- project is explicitly configured to use dependency-tree-plugin - treeJSONs <- recover $ genTreeJson dir + (Just projects, False, Just pluginKind) -> do + -- project is explicitly configured to use dependency-tree-plugin. + -- The casing of the dependencyBrowseTree task differs between the + -- modern (sbt 1.4+) DependencyTreePlugin and the legacy + -- net.virtualvoid sbt-dependency-graph plugin; pluginKind selects + -- the right one. See TKT-15490 / ANE-2718. + treeJSONs <- recover $ genTreeJson pluginKind dir pure ([SbtTargets Nothing (fromMaybe [] treeJSONs) projects], WalkSkipAll) analyzeWithPoms :: (Has Diagnostics sig m) => ScalaProject -> m DependencyResults @@ -199,13 +203,13 @@ analyzeWithPoms (ScalaProject _ _ closure) = context "Analyzing sbt dependencies } analyzeWithDepTreeJson :: (Has ReadFS sig m, Has Diagnostics sig m) => ScalaProject -> m DependencyResults -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 projectGraph <- TreeJson.analyze treeJson' pure $ DependencyResults diff --git a/src/Strategy/Scala/Plugin.hs b/src/Strategy/Scala/Plugin.hs index d921b1781..bd7641ff7 100644 --- a/src/Strategy/Scala/Plugin.hs +++ b/src/Strategy/Scala/Plugin.hs @@ -4,10 +4,13 @@ module Strategy.Scala.Plugin ( hasDependencyPlugins, detectDependencyPlugins, genTreeJson, + DependencyTreePluginKind (..), + DependencyPluginsDetected (..), ) where import Control.Effect.Diagnostics (Diagnostics, fatalText) import Control.Effect.Stack (context) +import Data.List (find) import Data.Maybe (mapMaybe) import Data.String.Conversion (ConvertUtf8 (decodeUtf8), toString) import Data.Text (Text) @@ -22,45 +25,112 @@ import Effect.Exec ( import Path (Abs, Dir, File, Path, mkRelFile, parent, parseAbsFile, ()) import Strategy.Scala.Common (mkSbtCommand) +-- | Which non-mini dependency-tree plugin (if any) the project has installed. +-- +-- The two plugins differ in the casing of their @dependencyBrowseTree@ task. +-- See 'mkDependencyBrowseTreeCmd' for the command names. +data DependencyTreePluginKind + = -- | @sbt.plugins.DependencyTreePlugin@. Built into sbt 1.4+ and enabled + -- explicitly via @addDependencyTreePlugin@ in @plugins.sbt@. Provides the + -- uppercase @dependencyBrowseTreeHTML@ task. + ModernDependencyTreePlugin + | -- | @net.virtualvoid.sbt.graph.DependencyGraphPlugin@. The third-party + -- @sbt-dependency-graph@ plugin used on sbt < 1.4. Provides the lowercase + -- @dependencyBrowseTreeHtml@ task. + LegacyDependencyGraphPlugin + deriving (Eq, Ord, Show) + +-- | What the @sbt plugins@ output told us about dependency-tree plugins. +data DependencyPluginsDetected = DependencyPluginsDetected + { hasMiniDependencyTreePlugin :: Bool + , dependencyTreePlugin :: Maybe DependencyTreePluginKind + } + deriving (Eq, Ord, Show) + -- | Returns list of plugins used by sbt. -- Ref: https://www.scala-sbt.org/1.x/docs/Plugins.html getPlugins :: Command getPlugins = mkSbtCommand "plugins" --- | Returns (hasMiniDependencyTreePlugin, hasDependencyTreePlugin) by running sbt plugins. -hasDependencyPlugins :: (Has Exec sig m, Has Diagnostics sig m) => Path Abs Dir -> m (Bool, Bool) +-- | Detect which dependency-tree plugins are loaded by running @sbt plugins@. +hasDependencyPlugins :: (Has Exec sig m, Has Diagnostics sig m) => Path Abs Dir -> m DependencyPluginsDetected hasDependencyPlugins projectDir = do stdoutText <- (TextLazy.toStrict . decodeUtf8) <$> context "Identifying plugins" (execThrow projectDir getPlugins) pure $ detectDependencyPlugins stdoutText --- | Detect dependency plugins from sbt plugins output. --- Returns (hasMiniDependencyTreePlugin, hasDependencyTreePlugin). -detectDependencyPlugins :: Text -> (Bool, Bool) +-- | Classify dependency-tree plugins from the @sbt plugins@ output. +-- +-- The plugin names mapped here: +-- +-- * @sbt.plugins.MiniDependencyTreePlugin@ — bundled with sbt 1.4+, gives +-- us the @dependencyTree@ task used by 'Strategy.Scala.SbtDependencyTree'. +-- * @sbt.plugins.DependencyTreePlugin@ — opt-in on sbt 1.4+ via +-- @addDependencyTreePlugin@. Provides the uppercase +-- @dependencyBrowseTreeHTML@ task. +-- * @net.virtualvoid.sbt.graph.DependencyGraphPlugin@ — third-party plugin +-- used on sbt < 1.4. Provides the lowercase @dependencyBrowseTreeHtml@ +-- task. +-- +-- @sbt plugins@ groups its output into per-project @Enabled plugins in +-- \:@ sections, listing one bare plugin FQCN per indented line, +-- followed by a trailing @Plugins that are loaded to the build but not enabled +-- in any subprojects:@ section. A plugin the user disabled via +-- @disablePlugins(...)@ moves into that trailing section. We therefore search +-- only the text *before* that marker, so a disabled (loaded-but-not-enabled) +-- plugin is not mistaken for an active one. +-- +-- The plugin FQCN appears on its own line with no @: enabled in@ suffix. An +-- earlier attempt to anchor detection on such a suffix matched nothing in real +-- sbt output, which silently dropped deep dependencies and fell back to poms +-- (regressed TKT-15490). See @test/Scala/PluginSpec.hs@ for fixtures captured +-- from actual @sbt -batch -no-colors plugins@ runs. +-- +-- When both modern and legacy non-mini plugins are present we prefer the +-- modern one (sbt 1.4+ wins) since legacy plugin presence on a modern sbt +-- typically means the user has both kinds of declarations in their build. +detectDependencyPlugins :: Text -> DependencyPluginsDetected detectDependencyPlugins stdoutText = - ( Text.count ".MiniDependencyTreePlugin" stdoutText > 0 - , Text.count ".DependencyTreePlugin" stdoutText > 0 - || Text.count "net.virtualvoid.sbt.graph.DependencyGraphPlugin" stdoutText > 0 -- sbt < 1.4 - ) + DependencyPluginsDetected + { hasMiniDependencyTreePlugin = enabled "sbt.plugins.MiniDependencyTreePlugin" + , dependencyTreePlugin = snd <$> find (enabled . fst) treePlugins + } + where + enabledSection = fst $ Text.breakOn notEnabledMarker stdoutText + notEnabledMarker = "Plugins that are loaded to the build but not enabled" + enabled name = name `Text.isInfixOf` enabledSection + treePlugins = + [ ("sbt.plugins.DependencyTreePlugin", ModernDependencyTreePlugin) + , ("net.virtualvoid.sbt.graph.DependencyGraphPlugin", LegacyDependencyGraphPlugin) + ] --- | Generates Dependency Trees. --- Ref: https://github.com/sbt/sbt/blob/master/main/src/main/scala/sbt/plugins/DependencyTreeSettings.scala#L101 --- --- This command unlike 'dependencyBrowseTree', does not open --- the browser when executed. +-- | The sbt task that writes @tree.html@/@tree.json@ alongside its dependency +-- output. Plugin name vs task casing: -- --- It writes following files in target directory: --- ./tree.json --- ./tree.html --- ./tree.data.js +-- * 'ModernDependencyTreePlugin' (sbt 1.4+, @addDependencyTreePlugin@) → +-- @dependencyBrowseTreeHTML@. +-- * 'LegacyDependencyGraphPlugin' (sbt < 1.4, @sbt-dependency-graph@) → +-- @dependencyBrowseTreeHtml@. -- --- This command is only used when the plugin is installed explicitly, i.e. sbt < 1.4. --- Newer versions of sbt will use the built-in dependency graph plugin. -mkDependencyBrowseTreeHTMLCmd :: Command -mkDependencyBrowseTreeHTMLCmd = mkSbtCommand "dependencyBrowseTreeHtml" +-- Picking the wrong casing produces an sbt error like +-- @[error] Not a valid command: dependencyBrowseTreeHTML@ which surfaces to +-- the user as "Could not retrieve output from sbt dependencyBrowseTreeHTML". +-- That regression (CLI 3.8.30) is tracked under TKT-15490 / ANE-2718. +mkDependencyBrowseTreeCmd :: DependencyTreePluginKind -> Command +mkDependencyBrowseTreeCmd ModernDependencyTreePlugin = mkSbtCommand "dependencyBrowseTreeHTML" +mkDependencyBrowseTreeCmd LegacyDependencyGraphPlugin = mkSbtCommand "dependencyBrowseTreeHtml" -genTreeJson :: (Has Exec sig m, Has Diagnostics sig m) => Path Abs Dir -> m [Path Abs File] -genTreeJson projectDir = do - stdoutBL <- context "Generating dependency tree html" $ execThrow projectDir mkDependencyBrowseTreeHTMLCmd +-- | Generates dependency trees by invoking the appropriate +-- @dependencyBrowseTree*@ task. Unlike @dependencyBrowseTree@, this does not +-- open a browser when executed. +-- +-- It writes the following files in the target directory: +-- +-- * @./tree.json@ +-- * @./tree.html@ +-- * @./tree.data.js@ +genTreeJson :: (Has Exec sig m, Has Diagnostics sig m) => DependencyTreePluginKind -> Path Abs Dir -> m [Path Abs File] +genTreeJson pluginKind projectDir = do + stdoutBL <- context "Generating dependency tree html" $ execThrow projectDir (mkDependencyBrowseTreeCmd pluginKind) -- stdout for "sbt dependencyBrowseTreeHTML" looks like: -- - diff --git a/test/Scala/PluginSpec.hs b/test/Scala/PluginSpec.hs index 61cf94447..45a847eec 100644 --- a/test/Scala/PluginSpec.hs +++ b/test/Scala/PluginSpec.hs @@ -5,7 +5,11 @@ module Scala.PluginSpec ( ) where import Data.Text (Text) -import Strategy.Scala.Plugin (detectDependencyPlugins) +import Strategy.Scala.Plugin ( + DependencyPluginsDetected (..), + DependencyTreePluginKind (..), + detectDependencyPlugins, + ) import Test.Hspec ( Spec, describe, @@ -14,97 +18,210 @@ import Test.Hspec ( ) import Text.RawString.QQ (r) +-- The fixtures below mirror the real layout of @sbt -batch -no-colors plugins@: +-- per-project "Enabled plugins in :" sections list one bare plugin +-- FQCN per indented line, and a trailing "Plugins that are loaded to the build +-- but not enabled in any subprojects:" section lists the rest. There is no +-- ": enabled in " suffix in real output. The sbt 1.9.8 fixtures +-- (default, addDependencyTreePlugin, disabled-mini) are verbatim captures from +-- fossas/scala3-example-project; the remainder follow the same layout. spec :: Spec spec = do describe "detectDependencyPlugins" $ do - it "should detect MiniDependencyTreePlugin (sbt 1.4+ built-in)" $ do - detectDependencyPlugins sbt14BuiltinOnly `shouldBe` (True, False) + -- Regression guard for TKT-15490: this is the verbatim `sbt plugins` + -- output for fossas/scala3-example-project (sbt 1.9.8, no plugins.sbt). + -- The built-in MiniDependencyTreePlugin must be detected so the deep + -- `dependencyTree` path runs. A prior refactor anchored detection on a + -- non-existent ": enabled in" suffix, returned False here, and + -- silently fell back to generated poms (Partial graph). + it "detects the built-in MiniDependencyTreePlugin (sbt 1.9.8, no plugins.sbt)" $ do + detectDependencyPlugins sbt198DefaultBuiltin + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = True, dependencyTreePlugin = Nothing} - it "should detect explicit DependencyTreePlugin" $ do - detectDependencyPlugins sbtExplicitPluginOnly `shouldBe` (False, True) + -- Real sbt 1.9.8 output with `addDependencyTreePlugin` in project/plugins.sbt + -- (the customer setup from TKT-15490). sbt enables the explicit + -- DependencyTreePlugin alongside the built-in MiniDependencyTreePlugin. + it "detects MiniDependencyTreePlugin and modern DependencyTreePlugin together (addDependencyTreePlugin)" $ do + detectDependencyPlugins sbt198AddDependencyTreePlugin + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = True, dependencyTreePlugin = Just ModernDependencyTreePlugin} - it "should detect legacy net.virtualvoid plugin" $ do - detectDependencyPlugins sbtLegacyVirtualvoidPlugin `shouldBe` (False, True) + -- sbt < 1.4 with the third-party net.virtualvoid sbt-dependency-graph + -- plugin. MiniDependencyTreePlugin does not exist before sbt 1.4, so it is + -- absent; routing must dispatch to the legacy lowercase task. + it "detects the legacy net.virtualvoid plugin (sbt-dependency-graph)" $ do + detectDependencyPlugins sbtLegacyVirtualvoidPlugin + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Just LegacyDependencyGraphPlugin} - -- TKT-14742: When both plugins present, findProjects should prefer MiniDependencyTreePlugin - it "should detect both plugins when MiniDependencyTreePlugin AND explicit plugin present" $ do - detectDependencyPlugins sbt14WithExplicitPlugin `shouldBe` (True, True) + -- TKT-15490 routing guard: when the modern DependencyTreePlugin is enabled + -- but MiniDependencyTreePlugin is not, findProjects routes to genTreeJson, + -- which must select the uppercase `dependencyBrowseTreeHTML` task. The + -- classification must be Modern (not Legacy lowercase). + it "classifies a modern DependencyTreePlugin with no MiniDependencyTreePlugin as Modern" $ do + detectDependencyPlugins sbtModernWithoutMini + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Just ModernDependencyTreePlugin} - it "should detect no plugins when neither is present" $ do - detectDependencyPlugins sbtNoPlugins `shouldBe` (False, False) + -- If a build somehow enables both the modern and legacy plugin, prefer the + -- modern one — on sbt 1.4+ the legacy lowercase task is unavailable. + it "prefers modern DependencyTreePlugin when both modern and legacy are enabled" $ do + detectDependencyPlugins sbtBothModernAndLegacy + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Just ModernDependencyTreePlugin} --- sbt 1.4+ with only built-in plugin -sbt14BuiltinOnly :: Text -sbt14BuiltinOnly = - [r|[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 11.0.21) -[info] loading global plugins from /Users/test/.sbt/1.0/plugins -[info] loading project definition from /Users/test/project/project + it "detects no dependency-tree plugins when none are enabled" $ do + detectDependencyPlugins sbtNoPlugins + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Nothing} + + -- `disablePlugins(MiniDependencyTreePlugin)` moves the plugin into the + -- trailing "loaded to the build but not enabled in any subprojects" + -- section. This is a verbatim sbt 1.9.8 capture; detection must not treat + -- it as active. An unanchored substring match (the pre-refactor behavior) + -- would wrongly count it. + it "ignores a MiniDependencyTreePlugin listed as loaded-but-not-enabled" $ do + detectDependencyPlugins sbt198DisabledMini + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Nothing} + + it "ignores a modern DependencyTreePlugin listed as loaded-but-not-enabled" $ do + detectDependencyPlugins sbtDisabledModern + `shouldBe` DependencyPluginsDetected{hasMiniDependencyTreePlugin = False, dependencyTreePlugin = Nothing} + +-- Verbatim `sbt -batch -no-colors plugins` output for fossas/scala3-example-project +-- (sbt 1.9.8, no project/plugins.sbt). +sbt198DefaultBuiltin :: Text +sbt198DefaultBuiltin = + [r|[info] welcome to sbt 1.9.8 (Homebrew Java 24.0.1) +[info] loading project definition from /private/tmp/scala3-example-project/project [info] loading settings for project root from build.sbt ... -[info] set current project to test-project (in build file:/Users/test/project/) -[info] In file:/Users/test/project/ -[info] sbt.plugins.CorePlugin: enabled in root -[info] sbt.plugins.IvyPlugin: enabled in root -[info] sbt.plugins.JvmPlugin: enabled in root -[info] sbt.plugins.MiniDependencyTreePlugin: enabled in root -[info] sbt.plugins.SemanticdbPlugin: enabled in root +[info] set current project to scala3-example-project (in build file:/private/tmp/scala3-example-project/) +In build /private/tmp/scala3-example-project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.Giter8TemplatePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JUnitXmlReportPlugin + sbt.plugins.JvmPlugin + sbt.plugins.MiniDependencyTreePlugin + sbt.plugins.SemanticdbPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.ScriptedPlugin + sbt.plugins.SbtPlugin |] --- sbt < 1.4 with explicit addDependencyTreePlugin -sbtExplicitPluginOnly :: Text -sbtExplicitPluginOnly = - [r|[info] welcome to sbt 1.3.13 (Eclipse Adoptium Java 11.0.21) -[info] loading global plugins from /Users/test/.sbt/1.0/plugins -[info] loading project definition from /Users/test/project/project +-- Verbatim sbt 1.9.8 output with `addDependencyTreePlugin` added to +-- project/plugins.sbt (the TKT-15490 customer setup). +sbt198AddDependencyTreePlugin :: Text +sbt198AddDependencyTreePlugin = + [r|[info] welcome to sbt 1.9.8 (Homebrew Java 24.0.1) +[info] loading project definition from /private/tmp/scala3-example-project/project [info] loading settings for project root from build.sbt ... -[info] set current project to test-project (in build file:/Users/test/project/) -[info] In file:/Users/test/project/ -[info] sbt.plugins.CorePlugin: enabled in root -[info] sbt.plugins.IvyPlugin: enabled in root -[info] sbt.plugins.JvmPlugin: enabled in root -[info] sbt.plugins.DependencyTreePlugin: enabled in root +[info] set current project to scala3-example-project (in build file:/private/tmp/scala3-example-project/) +In build /private/tmp/scala3-example-project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.DependencyTreePlugin + sbt.plugins.Giter8TemplatePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JUnitXmlReportPlugin + sbt.plugins.JvmPlugin + sbt.plugins.MiniDependencyTreePlugin + sbt.plugins.SemanticdbPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.ScriptedPlugin + sbt.plugins.SbtPlugin |] --- sbt < 1.4 with legacy net.virtualvoid plugin +-- sbt < 1.4 with the legacy net.virtualvoid sbt-dependency-graph plugin. sbtLegacyVirtualvoidPlugin :: Text sbtLegacyVirtualvoidPlugin = [r|[info] welcome to sbt 1.2.8 (Eclipse Adoptium Java 11.0.21) -[info] loading global plugins from /Users/test/.sbt/1.0/plugins -[info] loading project definition from /Users/test/project/project -[info] loading settings for project root from build.sbt ... [info] set current project to test-project (in build file:/Users/test/project/) -[info] In file:/Users/test/project/ -[info] sbt.plugins.CorePlugin: enabled in root -[info] sbt.plugins.IvyPlugin: enabled in root -[info] sbt.plugins.JvmPlugin: enabled in root -[info] net.virtualvoid.sbt.graph.DependencyGraphPlugin: enabled in root +In build /Users/test/project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JvmPlugin + net.virtualvoid.sbt.graph.DependencyGraphPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.plugins.SbtPlugin |] --- TKT-14742: sbt 1.4+ with BOTH built-in and explicit plugin -sbt14WithExplicitPlugin :: Text -sbt14WithExplicitPlugin = +-- Modern DependencyTreePlugin enabled with MiniDependencyTreePlugin disabled +-- (`disablePlugins(MiniDependencyTreePlugin)` alongside addDependencyTreePlugin). +sbtModernWithoutMini :: Text +sbtModernWithoutMini = + [r|[info] welcome to sbt 1.11.5 (Eclipse Adoptium Java 17.0.10) +[info] set current project to test-project (in build file:/Users/test/project/) +In build /Users/test/project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.DependencyTreePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JvmPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.plugins.MiniDependencyTreePlugin +|] + +-- A pathological build that enables both the modern and the legacy plugin. +sbtBothModernAndLegacy :: Text +sbtBothModernAndLegacy = [r|[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 11.0.21) -[info] loading global plugins from /Users/test/.sbt/1.0/plugins -[info] loading project definition from /Users/test/project/project -[info] loading settings for project root from build.sbt ... [info] set current project to test-project (in build file:/Users/test/project/) -[info] In file:/Users/test/project/ -[info] sbt.plugins.CorePlugin: enabled in root -[info] sbt.plugins.IvyPlugin: enabled in root -[info] sbt.plugins.JvmPlugin: enabled in root -[info] sbt.plugins.MiniDependencyTreePlugin: enabled in root -[info] sbt.plugins.DependencyTreePlugin: enabled in root -[info] sbt.plugins.SemanticdbPlugin: enabled in root +In build /Users/test/project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.DependencyTreePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JvmPlugin + net.virtualvoid.sbt.graph.DependencyGraphPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.plugins.SbtPlugin |] sbtNoPlugins :: Text sbtNoPlugins = [r|[info] welcome to sbt 1.9.7 (Eclipse Adoptium Java 11.0.21) -[info] loading global plugins from /Users/test/.sbt/1.0/plugins -[info] loading project definition from /Users/test/project/project +[info] set current project to test-project (in build file:/Users/test/project/) +In build /Users/test/project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JvmPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.plugins.SbtPlugin +|] + +-- Verbatim sbt 1.9.8 output with `disablePlugins(sbt.plugins.MiniDependencyTreePlugin)` +-- on the root project. The plugin appears only in the trailing not-enabled +-- section. +sbt198DisabledMini :: Text +sbt198DisabledMini = + [r|[info] welcome to sbt 1.9.8 (Homebrew Java 24.0.1) +[info] loading project definition from /private/tmp/scala3-example-project/project [info] loading settings for project root from build.sbt ... +[info] set current project to scala3-example-project (in build file:/private/tmp/scala3-example-project/) +In build /private/tmp/scala3-example-project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.Giter8TemplatePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JUnitXmlReportPlugin + sbt.plugins.JvmPlugin + sbt.plugins.SemanticdbPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.ScriptedPlugin + sbt.plugins.MiniDependencyTreePlugin + sbt.plugins.SbtPlugin +|] + +-- Modern DependencyTreePlugin disabled via disablePlugins; it appears only in +-- the trailing not-enabled section, so routing must not target its task. +sbtDisabledModern :: Text +sbtDisabledModern = + [r|[info] welcome to sbt 1.11.5 (Eclipse Adoptium Java 17.0.10) [info] set current project to test-project (in build file:/Users/test/project/) -[info] In file:/Users/test/project/ -[info] sbt.plugins.CorePlugin: enabled in root -[info] sbt.plugins.IvyPlugin: enabled in root -[info] sbt.plugins.JvmPlugin: enabled in root +In build /Users/test/project/: + Enabled plugins in root: + sbt.plugins.CorePlugin + sbt.plugins.IvyPlugin + sbt.plugins.JvmPlugin +Plugins that are loaded to the build but not enabled in any subprojects: + sbt.plugins.DependencyTreePlugin |]