From 3a4313edbc7c7c7fe6c07ffc995207e1975cac09 Mon Sep 17 00:00:00 2001 From: FinlayRJW <88376465+FinlayRJW@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:46:26 +0000 Subject: [PATCH] Require gradle-consitent-versions idea plugin for all projects using GCV (#1272) Require gradle-consitent-versions idea plugin for all projects using GCV --- build.gradle | 8 +++ changelog/@unreleased/pr-1272.v2.yml | 6 ++ gradle-consistent-versions-idea/build.gradle | 3 + .../versions/ConfigureIdeaPluginXml.groovy | 71 +++++++++++++++++++ settings.gradle | 2 + .../versions/ConsistentVersionsPlugin.java | 1 + .../RequireConsistentVersionsIdeaPlugin.java | 46 ++++++++++++ 7 files changed, 137 insertions(+) create mode 100644 changelog/@unreleased/pr-1272.v2.yml create mode 100644 gradle-consistent-versions-idea/build.gradle create mode 100644 gradle-consistent-versions-idea/src/main/groovy/com/palantir/gradle/versions/ConfigureIdeaPluginXml.groovy create mode 100644 src/main/java/com/palantir/gradle/versions/RequireConsistentVersionsIdeaPlugin.java diff --git a/build.gradle b/build.gradle index d3f61b7e..b808bdd3 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,7 @@ allprojects { } dependencies { + implementation project(':gradle-consistent-versions-idea') implementation 'com.google.guava:guava' implementation 'com.netflix.nebula:nebula-dependency-recommender' implementation 'com.palantir.gradle.failure-reports:gradle-failure-reports-exceptions' @@ -123,6 +124,13 @@ gradlePlugin { description = displayName tags.set(['versions']) } + requireConsistentVersionsIdeaPlugin { + id = 'com.palantir.consistent-versions-require-idea-plugin' + implementationClass = 'com.palantir.gradle.versions.RequireConsistentVersionsIdeaPlugin' + displayName = 'Plugin to ensure that the intellij plugin is added to the externalDependencies.xml.' + description = displayName + tags.set(['versions']) + } } } diff --git a/changelog/@unreleased/pr-1272.v2.yml b/changelog/@unreleased/pr-1272.v2.yml new file mode 100644 index 00000000..568000a9 --- /dev/null +++ b/changelog/@unreleased/pr-1272.v2.yml @@ -0,0 +1,6 @@ +type: improvement +improvement: + description: Require gradle-consitent-versions idea plugin for all projects using + GCV + links: + - https://github.com/palantir/gradle-consistent-versions/pull/1272 diff --git a/gradle-consistent-versions-idea/build.gradle b/gradle-consistent-versions-idea/build.gradle new file mode 100644 index 00000000..c1fcc833 --- /dev/null +++ b/gradle-consistent-versions-idea/build.gradle @@ -0,0 +1,3 @@ +apply plugin: 'java-gradle-plugin' +apply plugin: 'groovy' +apply plugin: 'com.palantir.external-publish-jar' diff --git a/gradle-consistent-versions-idea/src/main/groovy/com/palantir/gradle/versions/ConfigureIdeaPluginXml.groovy b/gradle-consistent-versions-idea/src/main/groovy/com/palantir/gradle/versions/ConfigureIdeaPluginXml.groovy new file mode 100644 index 00000000..d9d48935 --- /dev/null +++ b/gradle-consistent-versions-idea/src/main/groovy/com/palantir/gradle/versions/ConfigureIdeaPluginXml.groovy @@ -0,0 +1,71 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.gradle.versions + +import groovy.xml.XmlNodePrinter +import groovy.xml.XmlParser +import org.gradle.internal.impldep.com.google.common.collect.ImmutableMap +import org.xml.sax.SAXException + +import javax.xml.parsers.ParserConfigurationException +import java.nio.charset.StandardCharsets +import java.nio.file.Files + +class ConfigureIdeaPluginXml { + static void updateIdeaXmlFile(File configurationFile, String minVersion, boolean createIfAbsent) { + Node rootNode; + if (configurationFile.isFile()) { + try { + rootNode = new XmlParser().parse(configurationFile); + } catch (IOException | SAXException | ParserConfigurationException e) { + throw new RuntimeException("Couldn't parse existing configuration file: " + configurationFile, e); + } + } else { + if (!createIfAbsent) { + return; + } + rootNode = new Node(null, "project", ImmutableMap.of("version", "4")); + } + + configureExternalDependencies(rootNode, minVersion) + + try (BufferedWriter writer = Files.newBufferedWriter(configurationFile.toPath(), StandardCharsets.UTF_8); + PrintWriter printWriter = new PrintWriter(writer)) { + XmlNodePrinter nodePrinter = new XmlNodePrinter(printWriter); + nodePrinter.setPreserveWhitespace(true); + nodePrinter.print(rootNode); + } catch (IOException e) { + throw new RuntimeException("Failed to write back to configuration file: " + configurationFile, e); + } + } + + static void configureExternalDependencies(Node rootNode, String minVersion) { + def externalDependencies = matchOrCreateChild(rootNode, 'component', [name: 'ExternalDependencies']) + matchOrCreateChild(externalDependencies, 'plugin', [ 'id': 'gradle-consistent-versions' ], ['min-version' : minVersion]) + } + + private static Node matchOrCreateChild(Node base, String name, Map keyAttributes = [:], Map otherAttributes = [:]) { + Node node = base[name].find { it.attributes().entrySet().containsAll(keyAttributes.entrySet()) } as Node + if (Optional.ofNullable(node).isEmpty()) { + return base.appendNode(name, keyAttributes + otherAttributes) + } else { + node.attributes().clear() + node.attributes().putAll(keyAttributes + otherAttributes) + } + return node + } +} diff --git a/settings.gradle b/settings.gradle index 3b0b1e39..30c27141 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,3 +9,5 @@ buildscript { } apply plugin: 'com.palantir.jdks.settings' rootProject.name = 'gradle-consistent-versions' + +include 'gradle-consistent-versions-idea' diff --git a/src/main/java/com/palantir/gradle/versions/ConsistentVersionsPlugin.java b/src/main/java/com/palantir/gradle/versions/ConsistentVersionsPlugin.java index 51d7add5..0bb3b75e 100644 --- a/src/main/java/com/palantir/gradle/versions/ConsistentVersionsPlugin.java +++ b/src/main/java/com/palantir/gradle/versions/ConsistentVersionsPlugin.java @@ -32,6 +32,7 @@ public final void apply(Project project) { project.getPluginManager().apply(VersionsPropsPlugin.class); project.getPluginManager().apply(GetVersionPlugin.class); project.getPluginManager().apply(VersionsPropsIdeaPlugin.class); + project.getPluginManager().apply(RequireConsistentVersionsIdeaPlugin.class); project.allprojects(proj -> { proj.getPluginManager().withPlugin("java", _plugin -> { diff --git a/src/main/java/com/palantir/gradle/versions/RequireConsistentVersionsIdeaPlugin.java b/src/main/java/com/palantir/gradle/versions/RequireConsistentVersionsIdeaPlugin.java new file mode 100644 index 00000000..1d3c1bb2 --- /dev/null +++ b/src/main/java/com/palantir/gradle/versions/RequireConsistentVersionsIdeaPlugin.java @@ -0,0 +1,46 @@ +/* + * (c) Copyright 2024 Palantir Technologies Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.palantir.gradle.versions; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class RequireConsistentVersionsIdeaPlugin implements Plugin { + private static final Logger log = LoggerFactory.getLogger(RequireConsistentVersionsIdeaPlugin.class); + private static final String MIN_IDEA_PLUGIN_VERSION = "0.9.0"; + + @Override + public final void apply(Project project) { + + if (!Boolean.getBoolean("idea.active")) { + return; + } + + configureIntelliJImport(project); + } + + private static void configureIntelliJImport(Project project) { + // Note: we tried using 'org.jetbrains.gradle.plugin.idea-ext' and afterSync triggers, but these are currently + // very hard to manage as the tasks feel disconnected from the Sync operation, and you can't remove them once + // you've added them. For that reason, we accept that we have to resolve this configuration at + // configuration-time, but only do it when part of an IDEA import. + ConfigureIdeaPluginXml.updateIdeaXmlFile( + project.file(".idea/externalDependencies.xml"), MIN_IDEA_PLUGIN_VERSION, true); + } +}