Skip to content

[2.x] Fix global plugins not loaded #8638

Open
azdrojowa123 wants to merge 5 commits intosbt:developfrom
azdrojowa123:fix-global-plugins
Open

[2.x] Fix global plugins not loaded #8638
azdrojowa123 wants to merge 5 commits intosbt:developfrom
azdrojowa123:fix-global-plugins

Conversation

@azdrojowa123
Copy link
Copy Markdown
Contributor

Fixes #8600

@azdrojowa123 azdrojowa123 force-pushed the fix-global-plugins branch 2 times, most recently from 5994a6f to aabfeb2 Compare January 26, 2026 23:00
val builtin: Seq[Setting[?]] =
(thisProject :== project) +: (thisProjectRef :== ref) +: defineConfig
val settings = builtin ++ injectSettings.project ++ project.settings
val settings = builtin ++ project.settings ++ injectSettings.project
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure why this would fix the situation.
I wonder if the bug is elsewhere like

case User => machineWideUserSettings.cachedProjectLoaded(loadedPlugins.loader)
?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The logic behind this is that changing this order impacts how projectDescriptors is evaluated. The expression projectDescriptors ~= { _ ++ gp.descriptors } comes from injectSettings.project, so when it was placed before project.settings, it was overwritten (gp.descriptors is important because it contains the global plugins module).
The projectDescriptors value is then used in the csrExtraProjects task, which is later used for extra projects in lmcoursier.CoursierDependencyResolution#update.

I'm not 100% sure if this is correct, but while debugging, there was a difference between sbt 1.x and 2.x. Right after this change, the global plugins started being loaded.

However, I don't know why the dependency-management tests are failing on CI - locally they work.
Screenshot 2026-01-27 at 09 49 14

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm rerunning the failed test. Maybe they are just flaky.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I reran them yesterday a few times :( (the same failed each time).
So most likely something is wrong with the implementation or CI.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If we placed injectSettings.project afterwards, then would that mean that the settings that come from user-wide settings would take higher precedence over what's in the settings(...) in build.sbt file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It looks like it works this way even without changes from this PR (or maybe I misconfigured something).

In the project with sbt version that contains my fixes, when I set version := "2.0" at the very top of build.sbt, and in the sbt file in ~/.sbt/2 I added version := "1.0", the version for the root project was 1.0. When I put version := "2.0" specifically in the root project using settings(...), the version still showed as 1.0.

It behaves the same way in sbt RC8.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I managed to trigger the same exception locally as the one present on CI - I just ran updateSbtClassifiers task in a fresh project with the sbt version that includes the fixes.

Copy link
Copy Markdown
Contributor Author

@azdrojowa123 azdrojowa123 Jan 27, 2026

Choose a reason for hiding this comment

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

I see there's a difference between sbt 1.x and sbt 2.x in sbt.Classpaths.classifiersModuleTask - in sbt 2.x, pluginJars includes global plugin jar, whereas in sbt 1.x, it doesn't. I'll debug this issue further. The symptoms look similar to #8022.

azdrojowa123 added a commit to azdrojowa123/sbt that referenced this pull request Jan 28, 2026
val definitionClasspath = pluginData.definitionClasspath
val dependencyClasspath = pluginData.dependencyClasspath
val dependencyClasspath = config.globalPlugin match {
case Some(gp) => removeEntries(pluginData.dependencyClasspath, gp.data.internalClasspath)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I'm not 100% sure about this because GlobalPluginData#internalClasspath contains not only the exportedProducts but also the value from internalDependencyClasspath - maybe there's some use case where it's required to keep this in the dependencyClasspath.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

https://www.scala-sbt.org/1.x/docs/Plugins.html#Global+plugins

The $HOME/.sbt/1.0/plugins/ directory is treated as a global plugin definition project. It is a normal sbt project whose classpath is available to all sbt project definitions for that user as described above for per-project plugins.

If I'm reading it right, I think it's saying that the way sbt encodes "global plugin" is that we will first treat it as a standalone subproject. Then, we will pretend that user's metabuild (project/plugins.sbt) has a subproject dependency (aka internal dependency) to it.

Copy link
Copy Markdown
Contributor Author

@azdrojowa123 azdrojowa123 Jan 28, 2026

Choose a reason for hiding this comment

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

I see.

Do you have any idea for a test that would verify the dependency between the meta-build project and the "global plugin" project?
Even if I make changes, it would be good to have a test that fails with the current implementation.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When I first started sbt 2.x, I moved a bunch of scripted tests to project1 to comment them out. In there there's https://github.com/sbt/sbt/tree/develop/sbt-app/src/sbt-test/project1/global-plugin. Not sure if that currently works, but it might be related?

Copy link
Copy Markdown
Contributor Author

@azdrojowa123 azdrojowa123 Jan 28, 2026

Choose a reason for hiding this comment

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

Are the tests inside project1 not run on CI?
If yes, then I have to move my test ;p

^ thank you, this test is fine – it fails with my recent commit.

- `projectDescriptors ~=` from `InjectSettings.project` should go after `projectDescriptors :=`
sbt#8600

- `depsUpdated` was removed in PR sbt#8501, but it seems it's still necessary (e.g., for files inside the global plugins dir) in addition to `UpdateStats#stamp` as inputs for the cache
@azdrojowa123
Copy link
Copy Markdown
Contributor Author

azdrojowa123 commented Jan 29, 2026

On my local machine, the tests pass, but locally I have a different version without bin-SNAPSHOT.
Maybe some changes to handling binary versions for the current schema 2.0.0-RC8-bin-SNAPSHOT are needed.
I saw this comment also.

@eed3si9n
Copy link
Copy Markdown
Member

When the plugins are in $HOME/.sbt/2/plugins/user.sbt, the resolution happens correctly - tested on 2.0.0-M2, 2.0.0-RC6. On 2.0.0-RC6-bin-SNAPSHOT it does not resolve plugins from .sbt/2/plugins since the binary version is not 2 but full 2.0.0-RC6-bin-SNAPSHOT.

Do we also need to support a fallback to the full version path, e.g. first look at $HOME/.sbt/2/plugins/, then at $HOME/.sbt/2.0.0-RC6/plugins/? sbt 1.x does not seem to do such a fallback, loading the plugins only from the binary version folder.

ok, so it's just not possible or very difficult to work on global-plugin-related problems until we release 2.0.

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.

[2.x] *.sbt files in a global plugin directory are not loaded

2 participants