A Gradle plugin and IntelliJ plugin that make managing settings.gradle(.kts)
for large projects easier:
- Moves your
include
directives out ofsettings.gradle(.kts)
into a flat text file - Inspired by tools like Focus and dependency-explorer, this plugin lets you easily load subsets of your project into the IDE
- Only loads the minimum required list of projects required to run your requested build tasks
Apply the plugin in settings.gradle(.kts)
:
plugins {
id 'com.fueledbycaffeine.spotlight'
}
Remove any include
statements:
// get rid of these!
include ':app'
include ':feature'
Move the included project declarations to gradle/all-projects.txt
:app
:feature-a
:feature-b
# items may be commented out like this
To load a subset of your project in the IDE, list the projects you want to work on in gradle/ide-projects.txt
:
:feature-a
...
On next sync, only :feature-a
and other projects you choose will be be loaded. The transitive dependencies of these target projects are also loaded (because sync will fail otherwise), but you do not need to identify them yourself. The plugin statically parses your build.gradle(.kts)
files at the start of the build to determine the dependency graph.
Spotlight will infer the projects necessary to include in the build from the task request list and the project directory (specified with the -p
/--project-dir
flags).
For example, running ./gradlew :help
will only add the root project. Running something like ./gradlew :example:assemble
will only add the projects required by the dependency graph of :example
.
When the -p
/--project-dir
flag is used, Spotlight will expand the list of child projects at the specified directory and add the projects required by their dependency graphs to the build. This enables you to run something like ./gradlew -p example check
in a subdirectory.
It is not uncommon for a conventions plugin setup to add a default set of utilities/testing project dependencies to each project in a build. By default, Spotlight is not able to detect these implicit dependencies added to your projects by other build logic or plugins because those do not appear in your buildscripts.
A config file option is provided to configure some pattern matching rules based on project paths or buildscript contents to implicitly add other projects:
// gradle/spotlight-rules.json
[
// Add :tsunami-sea as a dependency to all projects with a path matching ":rotoscope:.*"
// The pattern strings are regexes
{
"type": "project-path-match-rule",
"pattern": ":rotoscope:.*",
"includedProjects": [":tsunami-sea"]
},
// Add :eternal-blue to any project applying the `com.example.android` convention plugin
{
"type": "buildscript-match-rule",
"pattern": "id 'com.example.android'",
"includedProjects": [
":eternal-blue",
":singles-collection" // multiple includes can be given for a pattern
]
}
]
Implicit rules apply to all Gradle invocations (sync and task execution).
If you are using the buildscript-utils
package by itself, you can read this rules list using the SpotlightRulesList
class.
By default, Spotlight attempts to do a basic "strict" mapping of any type-safe project accessors used to project path. This assumes that your project paths are all lowercased and use kebab-case for naming convention.
If your project does not follow this convention and can't be updated to follow it, you can enable full mapping of type-safe accessors:
// settings.gradle(.kts)
import com.fueledbycaffeine.spotlight.dsl.TypeSafeAccessorInference
spotlight {
typeSafeAccessorInference TypeSafeAccessorInference.FULL
}
Important
Enabling FULL
type-safe accessor inference mode captures all-projects.txt
in Gradle's configuration cache, and you will have a lower hit rate as a result.
Tip
If your project does not use type-safe project accessors at all, you can disable this inference entirely with DISABLED
mode.
Unlike Focus, which configures your gradle project to select which projects get synced using the :createFocusSettings
task provided by the plugin, Spotlight relies on parsing of your buildscripts with regexes to compute the dependency graph, which is much faster.
Spotlight does not include any Gradle tasks to manage your all-projects.txt
or ide-projects.txt
lists, and instead relies on external tooling (IDE plugin, shell command) to avoid invoking Gradle.
dependency-explorer runs completely outside Gradle, and users must rerun the build graph query whenever their dependency graph changes to avoid errors during IDE sync. Both dependency-explorer
and Spotlight use similar approaches for parsing the build graph, but Spotlight just does it automatically inside a settings plugin.
This plugin assumes you have a "nice" Gradle build that doesn't do cross-project configuration. Please read "Herding Elephants" and "Stampeding Elephants" for more thoughts on this topic.
Dependency declarations in buildscripts must be formatted to each be on a single line. The following example would not be parsed by the regexes used:
dependencies {
implementation(
project(
':feature-a'
)
)
}
The projectDir
for projects listed in all-projects.txt
cannot be relocated because the list of all your projects is now a flat text file and not a dynamic script.
You can still add include
s to settings.gradle(.kts)
in your build outside of this plugin.