diff --git a/changelog/@unreleased/pr-1151.v2.yml b/changelog/@unreleased/pr-1151.v2.yml new file mode 100644 index 000000000..84e808807 --- /dev/null +++ b/changelog/@unreleased/pr-1151.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: When palantir-java-format is applied to a repo, configure the intellij + project to auto-format on save. + links: + - https://github.com/palantir/gradle-baseline/pull/1151 diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineIdea.groovy b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineIdea.groovy index 07d5afe39..3f77c1f1a 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineIdea.groovy +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineIdea.groovy @@ -32,42 +32,28 @@ import org.gradle.plugins.ide.idea.GenerateIdeaProject import org.gradle.plugins.ide.idea.GenerateIdeaWorkspace import org.gradle.plugins.ide.idea.IdeaPlugin import org.gradle.plugins.ide.idea.model.IdeaModel +import org.gradle.plugins.ide.idea.model.ModuleDependency class BaselineIdea extends AbstractBaselinePlugin { + static SAVE_ACTIONS_PLUGIN_MINIMUM_VERSION = '1.9.0' + void apply(Project project) { this.project = project project.plugins.apply IdeaPlugin - IdeaModel ideaModuleModel = project.extensions.getByType(IdeaModel) - - project.afterEvaluate { - // Configure Idea project - IdeaModel ideaRootModel = project.rootProject.extensions.findByType(IdeaModel) - if (ideaRootModel) { - ideaRootModel.project.ipr.withXml { provider -> - def node = provider.asNode() - addCodeStyle(node) - addCopyright(node) - addCheckstyle(node) - addEclipseFormat(node) - addGit(node) - addInspectionProjectProfile(node) - addJavacSettings(node) - addGitHubIssueNavigation(node) - } - ideaRootModel.workspace.iws.withXml { provider -> - def node = provider.asNode() - setRunManagerWorkingDirectory(node) - addEditorSettings(node) - } - } - - // Configure Idea module - moveProjectReferencesToEnd(ideaModuleModel) + if (project == project.rootProject) { + applyToRootProject(project) + } else { + // Be defensive - it never makes sense to apply this project to only a subproject but not to the root. + project.rootProject.pluginManager.apply(BaselineIdea) } + // Configure Idea module + IdeaModel ideaModuleModel = project.extensions.getByType(IdeaModel) + moveProjectReferencesToEnd(ideaModuleModel) + // If someone renames a project, leftover {ipr,iml,ipr} files may still exist on disk and // confuse users, so we proactively clean them up. Intentionally using an Action to allow up-to-dateness. Action cleanup = new Action() { @@ -90,6 +76,42 @@ class BaselineIdea extends AbstractBaselinePlugin { project.getTasks().findByName("idea").doLast(cleanup) } + void applyToRootProject(Project project) { + // Configure Idea project + IdeaModel ideaRootModel = project.extensions.findByType(IdeaModel) + ideaRootModel.project.ipr.withXml { provider -> + Node node = provider.asNode() + addCodeStyle(node) + addCopyright(node) + addCheckstyle(node) + addEclipseFormat(node) + addGit(node) + addInspectionProjectProfile(node) + addJavacSettings(node) + addGitHubIssueNavigation(node) + } + + project.afterEvaluate { + ideaRootModel.workspace.iws.withXml { provider -> + Node node = provider.asNode() + setRunManagerWorkingDirectory(node) + addEditorSettings(node) + } + } + + // Suggest and configure the "save actions" plugin if Palantir Java Format is turned on. + // This plugin can only be applied to the root project, and it applied as a side-effect of applying + // 'com.palantir.java-format' to any subproject. + project.getPluginManager().withPlugin("com.palantir.java-format-idea") { + ideaRootModel.project.ipr.withXml { provider -> + Node node = provider.asNode() + configureSaveActions(node) + configureExternalDependencies(node) + } + configureSaveActionsForIntellijImport(project) + } + } + @CompileStatic static Spec isFile(File file) { { FileTreeElement details -> details.file == file } as Spec @@ -167,8 +189,8 @@ class BaselineIdea extends AbstractBaselinePlugin { """)) - def externalDependencies = matchOrCreateChild(node, 'component', [name: 'ExternalDependencies']) - matchOrCreateChild(externalDependencies, 'plugin', [id: 'EclipseCodeFormatter']) + def externalDependencies = GroovyXmlUtils.matchOrCreateChild(node, 'component', [name: 'ExternalDependencies']) + GroovyXmlUtils.matchOrCreateChild(externalDependencies, 'plugin', [id: 'EclipseCodeFormatter']) } private void addCheckstyle(node) { @@ -196,8 +218,8 @@ class BaselineIdea extends AbstractBaselinePlugin { """.stripIndent())) - def externalDependencies = matchOrCreateChild(node, 'component', [name: 'ExternalDependencies']) - matchOrCreateChild(externalDependencies, 'plugin', [id: 'CheckStyle-IDEA']) + def externalDependencies = GroovyXmlUtils.matchOrCreateChild(node, 'component', [name: 'ExternalDependencies']) + GroovyXmlUtils.matchOrCreateChild(externalDependencies, 'plugin', [id: 'CheckStyle-IDEA']) } /** @@ -216,7 +238,7 @@ class BaselineIdea extends AbstractBaselinePlugin { '''.stripIndent())) } - private void addInspectionProjectProfile(node) { + private static void addInspectionProjectProfile(node) { node.append(new XmlParser().parseText(""" @@ -231,7 +253,7 @@ class BaselineIdea extends AbstractBaselinePlugin { """.stripIndent())) } - private void addJavacSettings(node) { + private static void addJavacSettings(node) { node.append(new XmlParser().parseText("""