# The IDEA Plugin

version 9.8.0-milestone-2

The IDEA plugin generates files that are used by IntelliJ IDEA, thus making it possible to open the project from IDEA (`File` - `Open Project`). Both external dependencies (including associated source and Javadoc files) and project dependencies are considered.

| If you simply want to load a Gradle project into IntelliJ IDEA, then use the IDE’s import facility. You do not need to apply this plugin to import your project into IDEA, although if you do, the import will take account of any extra IDEA configuration you have that doesn’t directly modify the generated files — see the Configuration section for more details.

What exactly the IDEA plugin generates depends on which other plugins are used:

Always

  Generates an IDEA module file. Also generates an IDEA project and workspace file if the project is the root project.

Java Plugin

  Additionally adds Java configuration to the IDEA module and project files.

One focus of the IDEA plugin is to be open to customization. The plugin provides a standardized set of hooks for adding and removing content from the generated files.

## Usage

To use the IDEA plugin, include this in your build script:

Example 1. Using the IDEA plugin
build.gradle.kts

    plugins {
        idea
    }

build.gradle

    plugins {
        id 'idea'
    }

The IDEA plugin adds a number of tasks to your project. The `idea` task generates an IDEA module file for the project. When the project is the root project, the `idea` task also generates an IDEA project and workspace. The IDEA project includes modules for each of the projects in the Gradle build.

The IDEA plugin also adds an `openIdea` task when the project is the root project. This task generates the IDEA configuration files and opens the result in IDEA. This means you can simply run `./gradlew openIdea` from the root project to generate and open the IDEA project in one convenient step.

The IDEA plugin also adds a `cleanIdea` task to the project. This task deletes the generated files, if present.

## Tasks

| The tasks listed in this section are deprecated and will be removed in Gradle 10. Modern versions of IntelliJ IDEA import Gradle projects directly via its built-in Gradle integration without needing these generated files. The rest of the plugin — including the `idea { …​ }` DSL for customizing how the IDE understands your project — is not deprecated and continues to be consumed by IntelliJ IDEA during Gradle import. See the upgrade guide for details.

The IDEA plugin adds the tasks shown below to a project. Notice that the `clean` task does not depend on the `cleanIdeaWorkspace` task. This is because the workspace typically contains a lot of user specific temporary data and it is not desirable to manipulate it outside IDEA.

`idea`

  Depends on: `ideaProject`, `ideaModule`, `ideaWorkspace`

  Generates all IDEA configuration files

`openIdea`

  Depends on: `idea`

  Generates all IDEA configuration files and opens the project in IDEA

`cleanIdea` — Delete

  Depends on: `cleanIdeaProject`, `cleanIdeaModule`

  Removes all IDEA configuration files

`cleanIdeaProject` — Delete

  Removes the IDEA project file

`cleanIdeaModule` — Delete

  Removes the IDEA module file

`cleanIdeaWorkspace` — Delete

  Removes the IDEA workspace file

`ideaProject` — GenerateIdeaProject

  Generates the `.ipr` file. This task is only added to the root project.

`ideaModule` — GenerateIdeaModule

  Generates the `.iml` file

`ideaWorkspace` — GenerateIdeaWorkspace

  Generates the `.iws` file. This task is only added to the root project.

## Configuration

The plugin adds some configuration options that allow to customize the IDEA project and module files that it generates. These take the form of both model properties and lower-level mechanisms that modify the generated files directly. For example, you can add source and resource directories, as well as inject your own fragments of XML. The former type of configuration is honored by IDEA’s import facility, whereas the latter is not.

Here are the configuration properties you can use:

`idea` — IdeaModel

  Top level element that enables configuration of the idea plugin in a DSL-friendly fashion

`idea.project` — IdeaProject

  Allows configuring project information

`idea.module` — IdeaModule

  Allows configuring module information

`idea.workspace` — IdeaWorkspace

  Allows configuring the workspace XML

Follow the links to the types for examples of using these configuration properties.

## Customizing the generated files

The IDEA plugin provides hooks and behavior for customizing the generated content in a more controlled and detailed way. In addition, the `withXml` hook is the only practical way to modify the workspace file because its corresponding domain object is essentially empty.

| The techniques we discuss in this section don’t work with IDEA’s import facility

The tasks recognize existing IDEA files and merge them with the generated content.

### Merging

Sections of existing IDEA files that are also the target of generated content will be amended or overwritten, depending on the particular section. The remaining sections will be left as-is.

#### Disabling merging with a complete overwrite

To completely rewrite existing IDEA files, execute a clean task together with its corresponding generation task, like “gradle cleanIdea idea” (in that order). If you want to make this the default behavior, add “tasks.idea.dependsOn(cleanIdea)” to your build script. This makes it unnecessary to execute the clean task explicitly.

This strategy can also be used for individual files that the plugin would generate. For instance, this can be done for the “.iml” file with “gradle cleanIdeaModule ideaModule”.

### Hooking into the generation lifecycle

The plugin provides objects modeling the sections of the metadata files that are generated by Gradle. The generation lifecycle is as follows:

1. The file is read; or a default version provided by Gradle is used if it does not exist

2. The `beforeMerged` hook is executed with a domain object representing the existing file

3. The existing content is merged with the configuration inferred from the Gradle build or defined explicitly in the idea DSL

4. The `whenMerged` hook is executed with a domain object representing contents of the file to be persisted

5. The `withXml` hook is executed with a raw representation of the XML that will be persisted

6. The final XML is persisted

The following are the domain objects used for each of the model types:

IdeaProject

  - `beforeMerged { Project arg -> …​ }`

  - `whenMerged { Project arg -> …​ }`

  - `withXml { XmlProvider arg -> …​ }`

IdeaModule

  - `beforeMerged { Module arg -> …​ }`

  - `whenMerged { Module arg -> …​ }`

  - `withXml { XmlProvider arg -> …​ }`

IdeaWorkspace

  - `beforeMerged { Workspace arg -> …​ }`

  - `whenMerged { Workspace arg -> …​ }`

  - `withXml { XmlProvider arg -> …​ }`

#### Partial rewrite of existing content

A "complete rewrite" causes all existing content to be discarded, thereby losing any changes made directly in the IDE. The `beforeMerged` hook makes it possible to overwrite just certain parts of the existing content. The following example removes all existing dependencies from the `Module` domain object:

build.gradle.kts

    import org.gradle.plugins.ide.idea.model.Module

    idea.module.iml {
        beforeMerged(Action<Module> {
            dependencies.clear()
        })
    }

build.gradle

    idea.module.iml {
        beforeMerged { module ->
            module.dependencies.clear()
        }
    }

The resulting module file will only contain Gradle-generated dependency entries, but not any other dependency entries that may have been present in the original file. (In the case of dependency entries, this is also the default behavior.) Other sections of the module file will be either left as-is or merged. The same could be done for the module paths in the project file:

build.gradle.kts

    import org.gradle.plugins.ide.idea.model.Project

    idea.project.ipr {
        beforeMerged(Action<Project> {
            modulePaths.clear()
        })
    }

build.gradle

    idea.project.ipr {
        beforeMerged { project ->
            project.modulePaths.clear()
        }
    }

#### Modifying the fully populated domain objects

The `whenMerged` hook allows you to manipulate the fully populated domain objects. Often this is the preferred way to customize IDEA files. Here is how you would export all the dependencies of an IDEA module:

build.gradle.kts

    import org.gradle.plugins.ide.idea.model.Module
    import org.gradle.plugins.ide.idea.model.ModuleDependency

    idea.module.iml {
        whenMerged(Action<Module> {
            dependencies.forEach {
                (it as ModuleDependency).isExported = true
            }
        })
    }

build.gradle

    idea.module.iml {
        whenMerged { module ->
            module.dependencies*.exported = true
        }
    }

#### Modifying the XML representation

The `withXml` hook allows you to manipulate the in-memory XML representation just before the file gets written to disk. Although Groovy’s XML support and Kotlin’s extension functions make up for a lot, this approach is less convenient than manipulating the domain objects. In return, you get total control over the generated file, including sections not modeled by the domain objects.

build.gradle.kts

    import org.w3c.dom.Element

    idea.project.ipr {
        withXml(Action<XmlProvider> {
            fun Element.firstElement(predicate: (Element.() -> Boolean)) =
                childNodes
                    .run { (0 until length).map(::item) }
                    .filterIsInstance<Element>()
                    .first { it.predicate() }

            asElement()
                .firstElement { tagName == "component" && getAttribute("name") == "VcsDirectoryMappings" }
                .firstElement { tagName == "mapping" }
                .setAttribute("vcs", "Git")
        })
    }

build.gradle

    idea.project.ipr {
        withXml { provider ->
            provider.node.component
                    .find { it.@name == 'VcsDirectoryMappings' }
                    .mapping.@vcs = 'Git'
        }
    }

## Identifying additional test directories

When using this plugin together with the Java plugin, after adding additional source sets you may wish to inform IDEA when they contain test source rather than production source, so that the IDE can treat the directories appropriately. This can be accomplished by using this plugin’s `Module` block.

build.gradle.kts

    sourceSets {
        create("intTest") {
            java {
                setSrcDirs(listOf("src/integration"))
            }
        }
    }

    idea {
        module {
            testSources.from(sourceSets["intTest"].java.srcDirs)
        }
    }

build.gradle

    sourceSets {
        intTest {
            java {
                srcDirs = ['src/integration']
            }
        }
    }

    idea {
        module {
            testSources.from(sourceSets.intTest.java.srcDirs)
        }
    }

| When working with the JVM Test Suite Plugin, test sources will be automatically identified correctly.

## Further things to consider

The paths of dependencies in the generated IDEA files are absolute. If you manually define a path variable pointing to the Gradle dependency cache, IDEA will automatically replace the absolute dependency paths with this path variable. You can configure this path variable via the “idea.pathVariables” property, so that it can do a proper merge without creating duplicates.

| The `idea.pathVariables` property is deprecated and will be removed in Gradle 10, along with the generated-file tasks described above. Modern versions of IntelliJ IDEA import Gradle projects directly and do not rely on these generated files.