From 9331a712897492ef4626840ccd6f91431384161c Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 13:31:23 +0000 Subject: [PATCH 01/19] mvp BaselineClassUniquenessLockPlugin --- .../BaselineClassUniquenessLockPlugin.java | 88 +++++++++++++++++++ ....baseline-class-uniqueness-lock.properties | 1 + 2 files changed, 89 insertions(+) create mode 100644 gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java create mode 100644 gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java new file mode 100644 index 000000000..1b655a30f --- /dev/null +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -0,0 +1,88 @@ +/* + * (c) Copyright 2020 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.baseline.plugins; + +import com.palantir.baseline.tasks.ClassUniquenessAnalyzer; +import java.io.File; +import java.nio.file.Files; +import org.gradle.api.Action; +import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.provider.SetProperty; +import org.gradle.language.base.plugins.LifecycleBasePlugin; +import org.gradle.util.GFileUtils; + +/** + * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule + * but goes one step further and actually hashes any identically named classfiles to figure out if they're + * completely identical (and therefore safely interchangeable). + * + * The task only fails if it finds classes which have the same name but different implementations. + */ +public class BaselineClassUniquenessLockPlugin extends AbstractBaselinePlugin { + @Override + public final void apply(Project project) { + + // TODO(dfox): expose this so that users can add/remove their own configurations? + SetProperty configurationNames = project.getObjects().setProperty(String.class); + project.getPlugins().withId("java", plugin -> { + configurationNames.add("runtimeClasspath"); + }); + + File lockFile = project.file("baseline-class-uniqueness.lock"); + + Task checkClassUniquenessLock = project.getTasks().create("checkClassUniquenessLock"); + checkClassUniquenessLock.doLast(new Action() { + @Override + public void execute(Task task) { + + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n"); + + for (String configurationName : configurationNames.get()) { + stringBuilder.append("[" + configurationName + "]\n"); + ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); + + Configuration configuration = project.getConfigurations().getByName(configurationName); + analyzer.analyzeConfiguration(configuration); + stringBuilder.append(analyzer.getProblemJars().toString()); + stringBuilder.append('\n'); + stringBuilder.append('\n'); + } + + String expected = stringBuilder.toString(); + + if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { + // just nuke whatever was there before + GFileUtils.writeFile(expected, lockFile); + } else { + String onDisk = GFileUtils.readFile(lockFile); + if (!onDisk.equals(expected)) { + throw new GradleException(lockFile + " is out of date, please run ./gradlew " + + "checkClassUniquenessLock --write-locks to update this file"); + } + } + } + }); + // TODO(dfox): up-to-dateness + + project.getPlugins().apply(LifecycleBasePlugin.class); + project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(checkClassUniquenessLock); + } +} diff --git a/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties b/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties new file mode 100644 index 000000000..e9ce40a84 --- /dev/null +++ b/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties @@ -0,0 +1 @@ +implementation-class=com.palantir.baseline.plugins.BaselineClassUniquenessLockPlugin From a1e2eb08a8db3aef3aceb4e825659e22ce668ad6 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 13:49:50 +0000 Subject: [PATCH 02/19] Nicer lockfile format --- .../BaselineClassUniquenessLockPlugin.java | 43 +++++++++++++++---- .../tasks/ClassUniquenessAnalyzer.java | 2 +- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index 1b655a30f..6a3391d71 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -18,22 +18,24 @@ import com.palantir.baseline.tasks.ClassUniquenessAnalyzer; import java.io.File; -import java.nio.file.Files; +import java.util.Collection; +import java.util.Set; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.provider.SetProperty; import org.gradle.language.base.plugins.LifecycleBasePlugin; import org.gradle.util.GFileUtils; /** - * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule - * but goes one step further and actually hashes any identically named classfiles to figure out if they're - * completely identical (and therefore safely interchangeable). + * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule but goes + * one step further and actually hashes any identically named classfiles to figure out if they're completely + * identical (and therefore safely interchangeable). * - * The task only fails if it finds classes which have the same name but different implementations. + *

The task only fails if it finds classes which have the same name but different implementations. */ public class BaselineClassUniquenessLockPlugin extends AbstractBaselinePlugin { @Override @@ -53,15 +55,30 @@ public final void apply(Project project) { public void execute(Task task) { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n"); + stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n\n"); for (String configurationName : configurationNames.get()) { - stringBuilder.append("[" + configurationName + "]\n"); + stringBuilder.append("## configuration: " + configurationName + "\n"); ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); Configuration configuration = project.getConfigurations().getByName(configurationName); analyzer.analyzeConfiguration(configuration); - stringBuilder.append(analyzer.getProblemJars().toString()); + Collection> problemJars = analyzer.getDifferingProblemJars(); + for (Set clashingJars : problemJars) { + stringBuilder + .append("- ") + .append(clashingJars.toString()) + .append('\n'); + + analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() + .sorted() + .forEach(className -> { + stringBuilder.append(" - "); + stringBuilder.append(className); + stringBuilder.append('\n'); + }); + } + stringBuilder.append('\n'); stringBuilder.append('\n'); } @@ -71,10 +88,18 @@ public void execute(Task task) { if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { // just nuke whatever was there before GFileUtils.writeFile(expected, lockFile); + project.getLogger().lifecycle("Updated {}", lockFile); + } else if (!lockFile.isFile() || !lockFile.canRead()) { + project.getLogger() + .warn( + "{} does not exist - please run `./gradlew " + + "checkClassUniquenessLock --write-locks` to create it", + lockFile); } else { String onDisk = GFileUtils.readFile(lockFile); if (!onDisk.equals(expected)) { - throw new GradleException(lockFile + " is out of date, please run ./gradlew " + throw new GradleException(lockFile + + " is out of date, please run ./gradlew " + "checkClassUniquenessLock --write-locks to update this file"); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessAnalyzer.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessAnalyzer.java index 9fc7ebc7b..4fe2c487f 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessAnalyzer.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessAnalyzer.java @@ -121,7 +121,7 @@ public void analyzeConfiguration(Configuration configuration) { * Note: may contain non-scary duplicates - class files which are 100% identical, so their * clashing name doesn't have any effect. */ - public Collection> getProblemJars() { + private Collection> getProblemJars() { return jarsToClasses.keySet(); } From b3ea88856d64a3ee6fe210cc7bf24f06e608a74e Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 13:52:33 +0000 Subject: [PATCH 03/19] More concise if there's only one configuration --- .../plugins/BaselineClassUniquenessLockPlugin.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index 6a3391d71..78ffe54c5 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -46,6 +46,9 @@ public final void apply(Project project) { project.getPlugins().withId("java", plugin -> { configurationNames.add("runtimeClasspath"); }); + project.getPlugins().withId("com.palantir.consistent-versions", plugin -> { + configurationNames.add("unifiedClasspath"); + }); File lockFile = project.file("baseline-class-uniqueness.lock"); @@ -57,8 +60,12 @@ public void execute(Task task) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n\n"); - for (String configurationName : configurationNames.get()) { - stringBuilder.append("## configuration: " + configurationName + "\n"); + Set configurations = configurationNames.get(); + + for (String configurationName : configurations) { + if (configurations.size() > 1) { + stringBuilder.append("## configuration: " + configurationName + "\n"); + } ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); Configuration configuration = project.getConfigurations().getByName(configurationName); From df143b8137c248a1a1b7479006c00f46872ce419 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 14:04:58 +0000 Subject: [PATCH 04/19] Nicer lockfile if everything passes --- .../BaselineClassUniquenessLockPlugin.java | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index 78ffe54c5..a5d3c3556 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -46,48 +46,51 @@ public final void apply(Project project) { project.getPlugins().withId("java", plugin -> { configurationNames.add("runtimeClasspath"); }); - project.getPlugins().withId("com.palantir.consistent-versions", plugin -> { - configurationNames.add("unifiedClasspath"); - }); File lockFile = project.file("baseline-class-uniqueness.lock"); + // TODO(dfox): up-to-dateness of this task Task checkClassUniquenessLock = project.getTasks().create("checkClassUniquenessLock"); checkClassUniquenessLock.doLast(new Action() { @Override public void execute(Task task) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n\n"); + stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n"); Set configurations = configurationNames.get(); for (String configurationName : configurations) { if (configurations.size() > 1) { - stringBuilder.append("## configuration: " + configurationName + "\n"); + stringBuilder.append("\n## configuration: " + configurationName + "\n"); } - ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); + ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); Configuration configuration = project.getConfigurations().getByName(configurationName); analyzer.analyzeConfiguration(configuration); Collection> problemJars = analyzer.getDifferingProblemJars(); - for (Set clashingJars : problemJars) { + + if (problemJars.isEmpty()) { stringBuilder - .append("- ") - .append(clashingJars.toString()) - .append('\n'); + .append("Zero identically named classes found in ") + .append(configurationName) + .append(".\n"); + } else { + for (Set clashingJars : problemJars) { + // TODO(dfox): maybe use a trie to provide a munch denser list of classes? + stringBuilder + .append("- ") + .append(clashingJars.toString()) + .append('\n'); - analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() - .sorted() - .forEach(className -> { - stringBuilder.append(" - "); - stringBuilder.append(className); - stringBuilder.append('\n'); - }); + analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() + .sorted() + .forEach(className -> { + stringBuilder.append(" - "); + stringBuilder.append(className); + stringBuilder.append('\n'); + }); + } } - - stringBuilder.append('\n'); - stringBuilder.append('\n'); } String expected = stringBuilder.toString(); @@ -97,22 +100,22 @@ public void execute(Task task) { GFileUtils.writeFile(expected, lockFile); project.getLogger().lifecycle("Updated {}", lockFile); } else if (!lockFile.isFile() || !lockFile.canRead()) { + // TODO(dfox): relativize this path project.getLogger() .warn( - "{} does not exist - please run `./gradlew " - + "checkClassUniquenessLock --write-locks` to create it", + "{} does not exist - please run " + + "`./gradlew checkClassUniquenessLock --write-locks` to create it", lockFile); } else { String onDisk = GFileUtils.readFile(lockFile); if (!onDisk.equals(expected)) { throw new GradleException(lockFile - + " is out of date, please run ./gradlew " - + "checkClassUniquenessLock --write-locks to update this file"); + + " is out of date, please run `./gradlew " + + "checkClassUniquenessLock --write-locks` to update this file"); } } } }); - // TODO(dfox): up-to-dateness project.getPlugins().apply(LifecycleBasePlugin.class); project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(checkClassUniquenessLock); From c0e97c041751a65166d5369c1f4c3c3c84adc26c Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 14:25:03 +0000 Subject: [PATCH 05/19] Get rid of version numbers --- .../plugins/BaselineClassUniquenessLockPlugin.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index a5d3c3556..44fc96fcc 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -20,6 +20,7 @@ import java.io.File; import java.util.Collection; import java.util.Set; +import java.util.stream.Collectors; import org.gradle.api.Action; import org.gradle.api.GradleException; import org.gradle.api.Project; @@ -59,7 +60,7 @@ public void execute(Task task) { Set configurations = configurationNames.get(); - for (String configurationName : configurations) { + configurations.stream().sorted().forEach(configurationName -> { if (configurations.size() > 1) { stringBuilder.append("\n## configuration: " + configurationName + "\n"); } @@ -76,10 +77,11 @@ public void execute(Task task) { .append(".\n"); } else { for (Set clashingJars : problemJars) { - // TODO(dfox): maybe use a trie to provide a munch denser list of classes? stringBuilder - .append("- ") - .append(clashingJars.toString()) + .append(clashingJars.stream() + .map(mvi -> mvi.getGroup() + ":" + mvi.getName()) + .sorted() + .collect(Collectors.joining(", ", "[", "]"))) .append('\n'); analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() @@ -91,7 +93,7 @@ public void execute(Task task) { }); } } - } + }); String expected = stringBuilder.toString(); From c866962618ff4a7ce0a4a51261c75a6612e3c5be Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 15:01:04 +0000 Subject: [PATCH 06/19] File doesn't exist if there are no problems --- .../BaselineClassUniquenessLockPlugin.java | 102 ++++++++++-------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index 44fc96fcc..068b96d98 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -19,7 +19,10 @@ import com.palantir.baseline.tasks.ClassUniquenessAnalyzer; import java.io.File; import java.util.Collection; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import org.gradle.api.Action; import org.gradle.api.GradleException; @@ -55,59 +58,58 @@ public final void apply(Project project) { checkClassUniquenessLock.doLast(new Action() { @Override public void execute(Task task) { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n"); + Map> resultsByConfiguration = configurationNames.get().stream() + .collect(Collectors.toMap(Function.identity(), configurationName -> { + ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); + Configuration configuration = project.getConfigurations().getByName(configurationName); + analyzer.analyzeConfiguration(configuration); + Collection> problemJars = analyzer.getDifferingProblemJars(); - Set configurations = configurationNames.get(); + if (problemJars.isEmpty()) { + return Optional.empty(); + } - configurations.stream().sorted().forEach(configurationName -> { - if (configurations.size() > 1) { - stringBuilder.append("\n## configuration: " + configurationName + "\n"); - } - - ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); - Configuration configuration = project.getConfigurations().getByName(configurationName); - analyzer.analyzeConfiguration(configuration); - Collection> problemJars = analyzer.getDifferingProblemJars(); + StringBuilder stringBuilder = new StringBuilder(); + // TODO(dfox): ensure we iterate through problemJars in a stable order + for (Set clashingJars : problemJars) { + stringBuilder + .append(clashingJars.stream() + .map(mvi -> mvi.getGroup() + ":" + mvi.getName()) + .sorted() + .collect(Collectors.joining(", ", "[", "]"))) + .append('\n'); - if (problemJars.isEmpty()) { - stringBuilder - .append("Zero identically named classes found in ") - .append(configurationName) - .append(".\n"); - } else { - for (Set clashingJars : problemJars) { - stringBuilder - .append(clashingJars.stream() - .map(mvi -> mvi.getGroup() + ":" + mvi.getName()) - .sorted() - .collect(Collectors.joining(", ", "[", "]"))) - .append('\n'); + analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() + .sorted() + .forEach(className -> { + stringBuilder.append(" - "); + stringBuilder.append(className); + stringBuilder.append('\n'); + }); + } + return Optional.of(stringBuilder.toString()); + })); - analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() - .sorted() - .forEach(className -> { - stringBuilder.append(" - "); - stringBuilder.append(className); - stringBuilder.append('\n'); - }); + boolean conflictsFound = resultsByConfiguration.values().stream().anyMatch(Optional::isPresent); + if (!conflictsFound) { + ensureLockfileDoesNotExist(); + } else { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append( + "# Run ./gradlew checkClassUniquenessLock --write-locks to update this " + "file\n\n"); + resultsByConfiguration.forEach((name, contents) -> { + if (contents.isPresent()) { + stringBuilder.append("## ").append(name).append("\n"); + stringBuilder.append(contents.get()); } - } - }); - - String expected = stringBuilder.toString(); + }); + ensureLockfileContains(stringBuilder.toString()); + } + } + private void ensureLockfileContains(String expected) { if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { - // just nuke whatever was there before GFileUtils.writeFile(expected, lockFile); - project.getLogger().lifecycle("Updated {}", lockFile); - } else if (!lockFile.isFile() || !lockFile.canRead()) { - // TODO(dfox): relativize this path - project.getLogger() - .warn( - "{} does not exist - please run " - + "`./gradlew checkClassUniquenessLock --write-locks` to create it", - lockFile); } else { String onDisk = GFileUtils.readFile(lockFile); if (!onDisk.equals(expected)) { @@ -117,6 +119,16 @@ public void execute(Task task) { } } } + + private void ensureLockfileDoesNotExist() { + if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { + GFileUtils.deleteQuietly(lockFile); + } else { + if (!lockFile.exists()) { + throw new GradleException(lockFile + " should not exist (as no problems were found)."); + } + } + } }); project.getPlugins().apply(LifecycleBasePlugin.class); From b5c0689e0284444a86847dc58ffbd00dcd5fe609 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 15:17:45 +0000 Subject: [PATCH 07/19] Factor out ClassUniquenessLockTask --- .../BaselineClassUniquenessLockPlugin.java | 95 +----------- .../tasks/ClassUniquenessLockTask.java | 137 ++++++++++++++++++ 2 files changed, 140 insertions(+), 92 deletions(-) create mode 100644 gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java index 068b96d98..718823a71 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java @@ -16,23 +16,11 @@ package com.palantir.baseline.plugins; -import com.palantir.baseline.tasks.ClassUniquenessAnalyzer; -import java.io.File; -import java.util.Collection; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; -import org.gradle.api.Action; -import org.gradle.api.GradleException; +import com.palantir.baseline.tasks.ClassUniquenessLockTask; import org.gradle.api.Project; import org.gradle.api.Task; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.provider.SetProperty; import org.gradle.language.base.plugins.LifecycleBasePlugin; -import org.gradle.util.GFileUtils; /** * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule but goes @@ -51,87 +39,10 @@ public final void apply(Project project) { configurationNames.add("runtimeClasspath"); }); - File lockFile = project.file("baseline-class-uniqueness.lock"); - // TODO(dfox): up-to-dateness of this task - Task checkClassUniquenessLock = project.getTasks().create("checkClassUniquenessLock"); - checkClassUniquenessLock.doLast(new Action() { - @Override - public void execute(Task task) { - Map> resultsByConfiguration = configurationNames.get().stream() - .collect(Collectors.toMap(Function.identity(), configurationName -> { - ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(project.getLogger()); - Configuration configuration = project.getConfigurations().getByName(configurationName); - analyzer.analyzeConfiguration(configuration); - Collection> problemJars = analyzer.getDifferingProblemJars(); - - if (problemJars.isEmpty()) { - return Optional.empty(); - } - - StringBuilder stringBuilder = new StringBuilder(); - // TODO(dfox): ensure we iterate through problemJars in a stable order - for (Set clashingJars : problemJars) { - stringBuilder - .append(clashingJars.stream() - .map(mvi -> mvi.getGroup() + ":" + mvi.getName()) - .sorted() - .collect(Collectors.joining(", ", "[", "]"))) - .append('\n'); - - analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() - .sorted() - .forEach(className -> { - stringBuilder.append(" - "); - stringBuilder.append(className); - stringBuilder.append('\n'); - }); - } - return Optional.of(stringBuilder.toString()); - })); - - boolean conflictsFound = resultsByConfiguration.values().stream().anyMatch(Optional::isPresent); - if (!conflictsFound) { - ensureLockfileDoesNotExist(); - } else { - StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append( - "# Run ./gradlew checkClassUniquenessLock --write-locks to update this " + "file\n\n"); - resultsByConfiguration.forEach((name, contents) -> { - if (contents.isPresent()) { - stringBuilder.append("## ").append(name).append("\n"); - stringBuilder.append(contents.get()); - } - }); - ensureLockfileContains(stringBuilder.toString()); - } - } - - private void ensureLockfileContains(String expected) { - if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { - GFileUtils.writeFile(expected, lockFile); - } else { - String onDisk = GFileUtils.readFile(lockFile); - if (!onDisk.equals(expected)) { - throw new GradleException(lockFile - + " is out of date, please run `./gradlew " - + "checkClassUniquenessLock --write-locks` to update this file"); - } - } - } - - private void ensureLockfileDoesNotExist() { - if (project.getGradle().getStartParameter().isWriteDependencyLocks()) { - GFileUtils.deleteQuietly(lockFile); - } else { - if (!lockFile.exists()) { - throw new GradleException(lockFile + " should not exist (as no problems were found)."); - } - } - } - }); + Task task = project.getTasks().create("checkClassUniquenessLock", ClassUniquenessLockTask.class); project.getPlugins().apply(LifecycleBasePlugin.class); - project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(checkClassUniquenessLock); + project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(task); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java new file mode 100644 index 000000000..47eb6f204 --- /dev/null +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -0,0 +1,137 @@ +/* + * (c) Copyright 2020 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.baseline.tasks; + +import java.io.File; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.ModuleVersionIdentifier; +import org.gradle.api.artifacts.result.ResolvedComponentResult; +import org.gradle.api.provider.SetProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.gradle.util.GFileUtils; + +public class ClassUniquenessLockTask extends DefaultTask { + @OutputFile public final File lockFile; + + // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes + private final SetProperty configurationNames; + + public ClassUniquenessLockTask() { + this.configurationNames = getProject().getObjects().setProperty(String.class); + this.lockFile = getProject().file("baseline-class-uniqueness.lock"); + } + + /** This method exists purely for up-to-dateness purposes. */ + @Input + public Map> contentsOfAllConfigurations() { + return configurationNames.get().stream().collect(Collectors.toMap(Function.identity(), name -> { + Configuration configuration = getProject().getConfigurations().getByName(name); + return configuration.getIncoming().getResolutionResult().getAllComponents().stream() + .map(ResolvedComponentResult::getModuleVersion) + .collect(Collectors.toList()); + })); + } + + @TaskAction + public void doIt() { + Map> resultsByConfiguration = configurationNames.get().stream() + .collect(Collectors.toMap(Function.identity(), configurationName -> { + ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(getProject().getLogger()); + Configuration configuration = getProject().getConfigurations().getByName(configurationName); + analyzer.analyzeConfiguration(configuration); + Collection> problemJars = analyzer.getDifferingProblemJars(); + + if (problemJars.isEmpty()) { + return Optional.empty(); + } + + StringBuilder stringBuilder = new StringBuilder(); + // TODO(dfox): ensure we iterate through problemJars in a stable order + for (Set clashingJars : problemJars) { + stringBuilder + .append(clashingJars.stream() + .map(mvi -> mvi.getGroup() + ":" + mvi.getName()) + .sorted() + .collect(Collectors.joining(", ", "[", "]"))) + .append('\n'); + + analyzer.getDifferingSharedClassesInProblemJars(clashingJars).stream() + .sorted() + .forEach(className -> { + stringBuilder.append(" - "); + stringBuilder.append(className); + stringBuilder.append('\n'); + }); + } + return Optional.of(stringBuilder.toString()); + })); + + boolean conflictsFound = resultsByConfiguration.values().stream().anyMatch(Optional::isPresent); + if (!conflictsFound) { + // this is desirable because if means if people apply the plugin to lots of projects which are already + // compliant, they don't get loads of noisy lockfiles created. + ensureLockfileDoesNotExist(); + } else { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n\n"); + // TODO(dfox): make configuration order stable! + resultsByConfiguration.forEach((configuration, contents) -> { + if (contents.isPresent()) { + stringBuilder.append("## ").append(configuration).append("\n"); + stringBuilder.append(contents.get()); + } + }); + ensureLockfileContains(stringBuilder.toString()); + } + } + + private void ensureLockfileContains(String expected) { + if (getProject().getGradle().getStartParameter().isWriteDependencyLocks()) { + GFileUtils.writeFile(expected, lockFile); + getLogger().lifecycle("Updated {}", getProject().getRootDir().toPath().relativize(lockFile.toPath())); + } else { + String onDisk = GFileUtils.readFile(lockFile); + if (!onDisk.equals(expected)) { + throw new GradleException(lockFile + + " is out of date, please run `./gradlew " + + "checkClassUniquenessLock --write-locks` to update this file"); + } + } + } + + private void ensureLockfileDoesNotExist() { + if (lockFile.exists()) { + if (getProject().getGradle().getStartParameter().isWriteDependencyLocks()) { + GFileUtils.deleteQuietly(lockFile); + getLogger().lifecycle("Deleted {}", getProject().getRootDir().toPath().relativize(lockFile.toPath())); + } else { + throw new GradleException(lockFile + " should not exist (as no problems were found)."); + } + } + } +} From efac5145ecfce51b25605082b4b525ec4be1d02a Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 15:24:21 +0000 Subject: [PATCH 08/19] Merge into the original plugin --- .../BaselineClassUniquenessLockPlugin.java | 48 ------------------- .../BaselineClassUniquenessPlugin.java | 27 ++++++++--- .../tasks/ClassUniquenessLockTask.java | 21 ++++++-- ....baseline-class-uniqueness-lock.properties | 1 - 4 files changed, 36 insertions(+), 61 deletions(-) delete mode 100644 gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java delete mode 100644 gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java deleted file mode 100644 index 718823a71..000000000 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessLockPlugin.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * (c) Copyright 2020 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.baseline.plugins; - -import com.palantir.baseline.tasks.ClassUniquenessLockTask; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.provider.SetProperty; -import org.gradle.language.base.plugins.LifecycleBasePlugin; - -/** - * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule but goes - * one step further and actually hashes any identically named classfiles to figure out if they're completely - * identical (and therefore safely interchangeable). - * - *

The task only fails if it finds classes which have the same name but different implementations. - */ -public class BaselineClassUniquenessLockPlugin extends AbstractBaselinePlugin { - @Override - public final void apply(Project project) { - - // TODO(dfox): expose this so that users can add/remove their own configurations? - SetProperty configurationNames = project.getObjects().setProperty(String.class); - project.getPlugins().withId("java", plugin -> { - configurationNames.add("runtimeClasspath"); - }); - - // TODO(dfox): up-to-dateness of this task - Task task = project.getTasks().create("checkClassUniquenessLock", ClassUniquenessLockTask.class); - - project.getPlugins().apply(LifecycleBasePlugin.class); - project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(task); - } -} diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java index 73dae2ed5..5d08adc3c 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java @@ -17,27 +17,40 @@ package com.palantir.baseline.plugins; import com.palantir.baseline.plugins.rules.BaselineClassUniquenessRule; +import com.palantir.baseline.tasks.ClassUniquenessLockTask; import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.provider.SetProperty; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.internal.impldep.org.apache.maven.lifecycle.Lifecycle; +import org.gradle.language.base.plugins.LifecycleBasePlugin; /** - * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule - * but goes one step further and actually hashes any identically named classfiles to figure out if they're - * completely identical (and therefore safely interchangeable). + * This plugin is similar to https://github.com/nebula-plugins/gradle-lint-plugin/wiki/Duplicate-Classes-Rule but goes + * one step further and actually hashes any identically named classfiles to figure out if they're completely + * identical (and therefore safely interchangeable). * - * The task only fails if it finds classes which have the same name but different implementations. + *

The task only fails if it finds classes which have the same name but different implementations. */ public class BaselineClassUniquenessPlugin extends AbstractBaselinePlugin { @Override public final void apply(Project project) { - BaselineClassUniquenessRule rule = new BaselineClassUniquenessRule(project); + TaskProvider lockTask = + project.getTasks().register("checkClassUniquenessLock", ClassUniquenessLockTask.class); + project.getPlugins().apply(LifecycleBasePlugin.class); + project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(lockTask); + // TODO(dfox): is this 'rule' redundant now? maybe replace it with a kinda strict mode? + BaselineClassUniquenessRule rule = new BaselineClassUniquenessRule(project); project.getTasks().addRule(rule); project.getPlugins().withId("java", plugin -> { + lockTask.configure(t -> t.configurations.add(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); + String checkRuntimeClasspathTask = "checkRuntimeClasspathClassUniqueness"; rule.apply(checkRuntimeClasspathTask); - project.getTasks().getByName("check") - .dependsOn(project.getTasks().getByName(checkRuntimeClasspathTask)); + project.getTasks().getByName("check").dependsOn(project.getTasks().getByName(checkRuntimeClasspathTask)); }); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java index 47eb6f204..484193e02 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -26,10 +26,12 @@ import java.util.stream.Collectors; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; +import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ModuleVersionIdentifier; import org.gradle.api.artifacts.result.ResolvedComponentResult; import org.gradle.api.provider.SetProperty; +import org.gradle.api.specs.Spec; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; @@ -39,17 +41,26 @@ public class ClassUniquenessLockTask extends DefaultTask { @OutputFile public final File lockFile; // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes - private final SetProperty configurationNames; + public final SetProperty configurations; public ClassUniquenessLockTask() { - this.configurationNames = getProject().getObjects().setProperty(String.class); + this.configurations = getProject().getObjects().setProperty(String.class); this.lockFile = getProject().file("baseline-class-uniqueness.lock"); + onlyIf(new Spec() { + @Override + public boolean isSatisfiedBy(Task task) { + return !configurations.get().isEmpty(); + } + }); } - /** This method exists purely for up-to-dateness purposes. */ + /** + * This method exists purely for up-to-dateness purposes - we want to re-run if the contents of a configuration + * changes. + */ @Input public Map> contentsOfAllConfigurations() { - return configurationNames.get().stream().collect(Collectors.toMap(Function.identity(), name -> { + return configurations.get().stream().collect(Collectors.toMap(Function.identity(), name -> { Configuration configuration = getProject().getConfigurations().getByName(name); return configuration.getIncoming().getResolutionResult().getAllComponents().stream() .map(ResolvedComponentResult::getModuleVersion) @@ -59,7 +70,7 @@ public Map> contentsOfAllConfigurations() @TaskAction public void doIt() { - Map> resultsByConfiguration = configurationNames.get().stream() + Map> resultsByConfiguration = configurations.get().stream() .collect(Collectors.toMap(Function.identity(), configurationName -> { ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(getProject().getLogger()); Configuration configuration = getProject().getConfigurations().getByName(configurationName); diff --git a/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties b/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties deleted file mode 100644 index e9ce40a84..000000000 --- a/gradle-baseline-java/src/main/resources/META-INF/gradle-plugins/com.palantir.baseline-class-uniqueness-lock.properties +++ /dev/null @@ -1 +0,0 @@ -implementation-class=com.palantir.baseline.plugins.BaselineClassUniquenessLockPlugin From 7f8419bab4dd9bf91f487577c9f3f4b0e99867d3 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 15:34:23 +0000 Subject: [PATCH 09/19] Why not make it a cacheable task --- .../baseline/plugins/BaselineClassUniquenessPlugin.java | 3 --- .../palantir/baseline/tasks/ClassUniquenessLockTask.java | 8 +++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java index 5d08adc3c..7a635cbb2 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java @@ -19,11 +19,8 @@ import com.palantir.baseline.plugins.rules.BaselineClassUniquenessRule; import com.palantir.baseline.tasks.ClassUniquenessLockTask; import org.gradle.api.Project; -import org.gradle.api.Task; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.provider.SetProperty; import org.gradle.api.tasks.TaskProvider; -import org.gradle.internal.impldep.org.apache.maven.lifecycle.Lifecycle; import org.gradle.language.base.plugins.LifecycleBasePlugin; /** diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java index 484193e02..b9592a967 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -32,13 +32,19 @@ import org.gradle.api.artifacts.result.ResolvedComponentResult; import org.gradle.api.provider.SetProperty; import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; import org.gradle.util.GFileUtils; +@CacheableTask public class ClassUniquenessLockTask extends DefaultTask { - @OutputFile public final File lockFile; + @PathSensitive(PathSensitivity.NONE) + @OutputFile + public final File lockFile; // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes public final SetProperty configurations; From e478bc36556c980c48e7a003cd0065a113cb4a9b Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 15:34:58 +0000 Subject: [PATCH 10/19] Checkstyle --- .../com/palantir/baseline/tasks/ClassUniquenessLockTask.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java index b9592a967..ac0654204 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -41,6 +41,7 @@ import org.gradle.util.GFileUtils; @CacheableTask +@SuppressWarnings("VisibilityModifier") public class ClassUniquenessLockTask extends DefaultTask { @PathSensitive(PathSensitivity.NONE) @OutputFile @@ -65,7 +66,7 @@ public boolean isSatisfiedBy(Task task) { * changes. */ @Input - public Map> contentsOfAllConfigurations() { + public final Map> contentsOfAllConfigurations() { return configurations.get().stream().collect(Collectors.toMap(Function.identity(), name -> { Configuration configuration = getProject().getConfigurations().getByName(name); return configuration.getIncoming().getResolutionResult().getAllComponents().stream() @@ -75,7 +76,7 @@ public Map> contentsOfAllConfigurations() } @TaskAction - public void doIt() { + public final void doIt() { Map> resultsByConfiguration = configurations.get().stream() .collect(Collectors.toMap(Function.identity(), configurationName -> { ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(getProject().getLogger()); From 0d09ffd4b6057cbb1cd38fba3fada2d3e6577ec0 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 16:03:34 +0000 Subject: [PATCH 11/19] Appease validatePlugins --- .../tasks/ClassUniquenessLockTask.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java index ac0654204..bbe4804dd 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -16,9 +16,9 @@ package com.palantir.baseline.tasks; +import com.google.common.collect.ImmutableList; import java.io.File; import java.util.Collection; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -29,25 +29,20 @@ import org.gradle.api.Task; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ModuleVersionIdentifier; -import org.gradle.api.artifacts.result.ResolvedComponentResult; import org.gradle.api.provider.SetProperty; import org.gradle.api.specs.Spec; import org.gradle.api.tasks.CacheableTask; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; import org.gradle.api.tasks.TaskAction; import org.gradle.util.GFileUtils; @CacheableTask @SuppressWarnings("VisibilityModifier") public class ClassUniquenessLockTask extends DefaultTask { - @PathSensitive(PathSensitivity.NONE) - @OutputFile - public final File lockFile; // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes + private final File lockFile; public final SetProperty configurations; public ClassUniquenessLockTask() { @@ -66,15 +61,20 @@ public boolean isSatisfiedBy(Task task) { * changes. */ @Input - public final Map> contentsOfAllConfigurations() { + public final Map> getContentsOfAllConfigurations() { return configurations.get().stream().collect(Collectors.toMap(Function.identity(), name -> { Configuration configuration = getProject().getConfigurations().getByName(name); return configuration.getIncoming().getResolutionResult().getAllComponents().stream() - .map(ResolvedComponentResult::getModuleVersion) - .collect(Collectors.toList()); + .map(resolvedComponentResult -> resolvedComponentResult.getModuleVersion().toString()) + .collect(ImmutableList.toImmutableList()); // Gradle requires this to be Serializable })); } + @OutputFile + public final File getLockFile() { + return lockFile; + } + @TaskAction public final void doIt() { Map> resultsByConfiguration = configurations.get().stream() From 234d8a35441f6bc38f07d0526a72727b59efaa8c Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 16:13:25 +0000 Subject: [PATCH 12/19] Mention task name in the README --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index 39e4cba71..476e1adf5 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,27 @@ in `.baseline/copyright/*.txt` and the RegexpHeader checkstyle configuration in ## com.palantir.baseline-class-uniqueness +When applied to a java project, this inspects all the jars in your `runtimeClasspath` configuration and records any conflicts to a `baseline-class-uniqueness.lock` file. For example: + +``` +# Run ./gradlew checkClassUniquenessLock --write-locks to update this file + +## runtimeClasspath +[jakarta.annotation:jakarta.annotation-api, javax.annotation:javax.annotation-api] + - javax.annotation.Resource$AuthenticationType +[jakarta.ws.rs:jakarta.ws.rs-api, javax.ws.rs:javax.ws.rs-api] + - javax.ws.rs.BadRequestException + - javax.ws.rs.ClientErrorException + - javax.ws.rs.ForbiddenException + - javax.ws.rs.InternalServerErrorException + - javax.ws.rs.NotAcceptableException + - javax.ws.rs.NotAllowedException + - javax.ws.rs.NotAuthorizedException + - javax.ws.rs.NotFoundException + - javax.ws.rs.NotSupportedException + - javax.ws.rs.Priorities +``` + Run `./gradlew checkRuntimeClassUniqueness` to scan all jars on the `runtime` classpath for identically named classes. This task will run automatically as part of `./gradlew build`. To run the task on other configurations, use the `checkClassUniqueness` task for the `xyz` configuration. From 623a7555290d05e764fd5282369c78f96bebfd7a Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 16:13:25 +0000 Subject: [PATCH 13/19] Add generated changelog entries --- changelog/@unreleased/pr-1145.v2.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 changelog/@unreleased/pr-1145.v2.yml diff --git a/changelog/@unreleased/pr-1145.v2.yml b/changelog/@unreleased/pr-1145.v2.yml new file mode 100644 index 000000000..d7eb03d6c --- /dev/null +++ b/changelog/@unreleased/pr-1145.v2.yml @@ -0,0 +1,8 @@ +type: feature +feature: + description: The `com.palantir.baseline-class-uniqueness` plugin now records conflicts + in a `baseline-class-uniqueness.lock` file. This should be checked-in to git and + makes it easier to incrementally improve projects, rather than requiring a big-bang + migration. + links: + - https://github.com/palantir/gradle-baseline/pull/1145 From 468acacb9de0932d6bdd81d4e0b31e0a1a3c74b7 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:14:25 +0000 Subject: [PATCH 14/19] Delete rule entirely --- README.md | 11 +-- .../BaselineClassUniquenessPlugin.java | 9 --- .../rules/BaselineClassUniquenessRule.java | 68 ------------------- .../tasks/ClassUniquenessLockTask.java | 26 ++++--- ...lassUniquenessPluginIntegrationTest.groovy | 51 ++++++-------- 5 files changed, 45 insertions(+), 120 deletions(-) delete mode 100644 gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/rules/BaselineClassUniquenessRule.java diff --git a/README.md b/README.md index 476e1adf5..f3b6623fa 100644 --- a/README.md +++ b/README.md @@ -248,9 +248,13 @@ When applied to a java project, this inspects all the jars in your `runtimeClass - javax.ws.rs.Priorities ``` -Run `./gradlew checkRuntimeClassUniqueness` to scan all jars on the `runtime` classpath for identically named classes. -This task will run automatically as part of `./gradlew build`. To run the task on other configurations, use the -`checkClassUniqueness` task for the `xyz` configuration. +This task can also be used to analyze other configurations in addition to `runtimeClasspath`, e.g.: + +```gradle +checkClassUniquenessLock { + configurations.add 'myConf' +} +``` If you discover multiple jars on your classpath contain clashing classes, you should ideally try to fix them upstream and then depend on the fixed version. If this is not feasible, you may be able to tell Gradle to [use a substituted dependency instead](https://docs.gradle.org/current/userguide/customizing_dependency_resolution_behavior.html#sec:module_substitution): @@ -265,7 +269,6 @@ configurations.all { } ``` - ## com.palantir.baseline-circleci Automatically applies the following plugins: diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java index 7a635cbb2..f49bb0b41 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java @@ -16,7 +16,6 @@ package com.palantir.baseline.plugins; -import com.palantir.baseline.plugins.rules.BaselineClassUniquenessRule; import com.palantir.baseline.tasks.ClassUniquenessLockTask; import org.gradle.api.Project; import org.gradle.api.plugins.JavaPlugin; @@ -38,16 +37,8 @@ public final void apply(Project project) { project.getPlugins().apply(LifecycleBasePlugin.class); project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(lockTask); - // TODO(dfox): is this 'rule' redundant now? maybe replace it with a kinda strict mode? - BaselineClassUniquenessRule rule = new BaselineClassUniquenessRule(project); - project.getTasks().addRule(rule); - project.getPlugins().withId("java", plugin -> { lockTask.configure(t -> t.configurations.add(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); - - String checkRuntimeClasspathTask = "checkRuntimeClasspathClassUniqueness"; - rule.apply(checkRuntimeClasspathTask); - project.getTasks().getByName("check").dependsOn(project.getTasks().getByName(checkRuntimeClasspathTask)); }); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/rules/BaselineClassUniquenessRule.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/rules/BaselineClassUniquenessRule.java deleted file mode 100644 index e7d5ababc..000000000 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/rules/BaselineClassUniquenessRule.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * (c) Copyright 2019 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.baseline.plugins.rules; - -import com.google.common.collect.ImmutableList; -import com.palantir.baseline.tasks.CheckClassUniquenessTask; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.api.Rule; -import org.gradle.api.artifacts.Configuration; - -public final class BaselineClassUniquenessRule implements Rule { - private static final Pattern TASK_NAME_PATTERN = Pattern.compile("^check(.+)ClassUniqueness$"); - private final Project project; - - public BaselineClassUniquenessRule(Project project) { - this.project = project; - } - - @Override - public String getDescription() { - return "Pattern: checkClassUniqueness"; - } - - @Override - public void apply(String taskName) { - Matcher taskNameMatcher = TASK_NAME_PATTERN.matcher(taskName); - - if (taskNameMatcher.matches()) { - String confName = taskNameMatcher.group(1); - String altName = confName.substring(0, 1).toLowerCase() + confName.substring(1); - - List candidates = ImmutableList.of(altName, confName); - - Optional configOpt = candidates.stream() - .map(project.getConfigurations()::findByName) - .filter(Objects::nonNull) - .findFirst(); - - if (configOpt.isPresent()) { - project.getTasks().register(taskName, CheckClassUniquenessTask.class, task -> { - task.setConfiguration(configOpt.get()); - }); - } else { - throw new GradleException("Couldn't find configuration " + altName); - } - } - } -} diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java index bbe4804dd..eab17c7df 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java @@ -38,13 +38,14 @@ import org.gradle.util.GFileUtils; @CacheableTask -@SuppressWarnings("VisibilityModifier") public class ClassUniquenessLockTask extends DefaultTask { // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes - private final File lockFile; + @SuppressWarnings("VisibilityModifier") public final SetProperty configurations; + private final File lockFile; + public ClassUniquenessLockTask() { this.configurations = getProject().getObjects().setProperty(String.class); this.lockFile = getProject().file("baseline-class-uniqueness.lock"); @@ -132,13 +133,20 @@ private void ensureLockfileContains(String expected) { if (getProject().getGradle().getStartParameter().isWriteDependencyLocks()) { GFileUtils.writeFile(expected, lockFile); getLogger().lifecycle("Updated {}", getProject().getRootDir().toPath().relativize(lockFile.toPath())); - } else { - String onDisk = GFileUtils.readFile(lockFile); - if (!onDisk.equals(expected)) { - throw new GradleException(lockFile - + " is out of date, please run `./gradlew " - + "checkClassUniquenessLock --write-locks` to update this file"); - } + return; + } + + if (!lockFile.exists()) { + throw new GradleException("baseline-class-uniqueness detected multiple jars containing identically named " + + "classes. Please resolve these problems, or run `./gradlew checkClassUniquenessLock " + + "--write-locks` to accept them:\n\n" + expected); + } + + String onDisk = GFileUtils.readFile(lockFile); + if (!onDisk.equals(expected)) { + throw new GradleException(lockFile + + " is out of date, please run `./gradlew " + + "checkClassUniquenessLock --write-locks` to update this file"); } } diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index 07d46a259..2cd5008db 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -37,15 +37,6 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { } """.stripIndent() - def 'Task should run as part of :check'() { - when: - buildFile << standardBuildFile - - then: - def result = with('check', '--stacktrace').build() - result.task(':checkRuntimeClasspathClassUniqueness').outcome == TaskOutcome.SUCCESS - } - def 'detect duplicates in two external jars'() { when: buildFile << standardBuildFile @@ -55,12 +46,12 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { compile group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.1' } """.stripIndent() - BuildResult result = with('checkRuntimeClasspathClassUniqueness').buildAndFail() + BuildResult result = with('check', '-s').buildAndFail() then: - result.output.contains("26 Identically named classes with differing impls found in [javax.servlet.jsp:jsp-api:2.1, javax.el:javax.el-api:3.0.0]: [javax.") - result.getOutput().contains("'runtimeClasspath' contains multiple copies of identically named classes") - result.getOutput().contains("(26 classes) javax.servlet.jsp:jsp-api:2.1 javax.el:javax.el-api:3.0.0"); + result.getOutput().contains("baseline-class-uniqueness detected multiple jars containing identically named classes.") + result.getOutput().contains("[javax.el:javax.el-api, javax.servlet.jsp:jsp-api]") + result.getOutput().contains("javax.el.ArrayELResolver"); println result.getOutput() } @@ -76,18 +67,18 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { myConf group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.1' } - + checkClassUniquenessLock { + configurations.add 'myConf' + } """.stripIndent() - BuildResult result = with('checkMyConfClassUniqueness').buildAndFail() + BuildResult result = with('check', '-s').buildAndFail() then: - result.output.contains("26 Identically named classes with differing impls found in [javax.servlet.jsp:jsp-api:2.1, javax.el:javax.el-api:3.0.0]: [javax.") - result.getOutput().contains("'myConf' contains multiple copies of identically named classes") - result.getOutput().contains("(26 classes) javax.servlet.jsp:jsp-api:2.1 javax.el:javax.el-api:3.0.0"); + result.output.contains("baseline-class-uniqueness detected multiple jars containing identically named classes.") + result.getOutput().contains("## myConf") println result.getOutput() } - def 'ignores duplicates when the implementations are identical'() { when: buildFile << standardBuildFile @@ -99,7 +90,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { """.stripIndent() then: - with('checkRuntimeClasspathClassUniqueness').build() + with('checkClassUniquenessLock', '-s').build() } def 'task should be up-to-date when classpath is unchanged'() { @@ -107,11 +98,11 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { buildFile << standardBuildFile then: - BuildResult result1 = with('checkRuntimeClasspathClassUniqueness').build() - result1.task(':checkRuntimeClasspathClassUniqueness').outcome == TaskOutcome.SUCCESS + BuildResult result1 = with('checkClassUniquenessLock').build() + result1.task(':checkClassUniquenessLock').outcome == TaskOutcome.SUCCESS - BuildResult result = with('checkRuntimeClasspathClassUniqueness').build() - result.task(':checkRuntimeClasspathClassUniqueness').outcome == TaskOutcome.UP_TO_DATE + BuildResult result = with('checkClassUniquenessLock').build() + result.task(':checkClassUniquenessLock').outcome == TaskOutcome.UP_TO_DATE } def 'passes when no duplicates are present'() { @@ -125,10 +116,10 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { compile 'com.netflix.nebula:nebula-test:6.4.2' } """.stripIndent() - BuildResult result = with('checkRuntimeClasspathClassUniqueness', '--info').build() + BuildResult result = with('checkClassUniquenessLock', '--info').build() then: - result.task(":checkRuntimeClasspathClassUniqueness").outcome == TaskOutcome.SUCCESS + result.task(":checkClassUniquenessLock").outcome == TaskOutcome.SUCCESS println result.getOutput() } @@ -154,8 +145,8 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { """.stripIndent() then: - BuildResult result = with('checkRuntimeClasspathClassUniqueness').buildAndFail() - result.output.contains("26 Identically named classes with differing impls found in [javax.servlet.jsp:jsp-api:2.1, javax.el:javax.el-api:3.0.0]: [javax.") + BuildResult result = with('checkClassUniquenessLock', '-s').buildAndFail() + result.output.contains("baseline-class-uniqueness detected multiple jars containing identically named classes") } def 'currently skips duplicates from user-authored code'() { @@ -175,8 +166,8 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { """.stripIndent() then: - BuildResult result = with('checkRuntimeClasspathClassUniqueness', '--info').build() + BuildResult result = with('checkClassUniquenessLock', '--info').build() println result.getOutput() - result.task(":checkRuntimeClasspathClassUniqueness").outcome == TaskOutcome.SUCCESS // ideally should should say failed! + result.task(":checkClassUniquenessLock").outcome == TaskOutcome.SUCCESS // ideally should should say failed! } } From 691150e756888d81e4ddd1afcac324e493e37994 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:16:14 +0000 Subject: [PATCH 15/19] Rename to simplify --- README.md | 4 +- .../BaselineClassUniquenessPlugin.java | 6 +- ...java => CheckClassUniquenessLockTask.java} | 10 +- .../tasks/CheckClassUniquenessTask.java | 123 ------------------ ...lassUniquenessPluginIntegrationTest.groovy | 28 ++-- 5 files changed, 24 insertions(+), 147 deletions(-) rename gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/{ClassUniquenessLockTask.java => CheckClassUniquenessLockTask.java} (96%) delete mode 100644 gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessTask.java diff --git a/README.md b/README.md index f3b6623fa..e19e7412c 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ in `.baseline/copyright/*.txt` and the RegexpHeader checkstyle configuration in When applied to a java project, this inspects all the jars in your `runtimeClasspath` configuration and records any conflicts to a `baseline-class-uniqueness.lock` file. For example: ``` -# Run ./gradlew checkClassUniquenessLock --write-locks to update this file +# Run ./gradlew checkClassUniqueness --write-locks to update this file ## runtimeClasspath [jakarta.annotation:jakarta.annotation-api, javax.annotation:javax.annotation-api] @@ -251,7 +251,7 @@ When applied to a java project, this inspects all the jars in your `runtimeClass This task can also be used to analyze other configurations in addition to `runtimeClasspath`, e.g.: ```gradle -checkClassUniquenessLock { +checkClassUniqueness { configurations.add 'myConf' } ``` diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java index f49bb0b41..31870bf53 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java @@ -16,7 +16,7 @@ package com.palantir.baseline.plugins; -import com.palantir.baseline.tasks.ClassUniquenessLockTask; +import com.palantir.baseline.tasks.CheckClassUniquenessLockTask; import org.gradle.api.Project; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.tasks.TaskProvider; @@ -32,8 +32,8 @@ public class BaselineClassUniquenessPlugin extends AbstractBaselinePlugin { @Override public final void apply(Project project) { - TaskProvider lockTask = - project.getTasks().register("checkClassUniquenessLock", ClassUniquenessLockTask.class); + TaskProvider lockTask = + project.getTasks().register("checkClassUniqueness", CheckClassUniquenessLockTask.class); project.getPlugins().apply(LifecycleBasePlugin.class); project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(lockTask); diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java similarity index 96% rename from gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java rename to gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java index eab17c7df..33cb235d7 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/ClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java @@ -38,7 +38,7 @@ import org.gradle.util.GFileUtils; @CacheableTask -public class ClassUniquenessLockTask extends DefaultTask { +public class CheckClassUniquenessLockTask extends DefaultTask { // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes @SuppressWarnings("VisibilityModifier") @@ -46,7 +46,7 @@ public class ClassUniquenessLockTask extends DefaultTask { private final File lockFile; - public ClassUniquenessLockTask() { + public CheckClassUniquenessLockTask() { this.configurations = getProject().getObjects().setProperty(String.class); this.lockFile = getProject().file("baseline-class-uniqueness.lock"); onlyIf(new Spec() { @@ -117,7 +117,7 @@ public final void doIt() { ensureLockfileDoesNotExist(); } else { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("# Run ./gradlew checkClassUniquenessLock --write-locks to update this file\n\n"); + stringBuilder.append("# Run ./gradlew checkClassUniqueness --write-locks to update this file\n\n"); // TODO(dfox): make configuration order stable! resultsByConfiguration.forEach((configuration, contents) -> { if (contents.isPresent()) { @@ -138,7 +138,7 @@ private void ensureLockfileContains(String expected) { if (!lockFile.exists()) { throw new GradleException("baseline-class-uniqueness detected multiple jars containing identically named " - + "classes. Please resolve these problems, or run `./gradlew checkClassUniquenessLock " + + "classes. Please resolve these problems, or run `./gradlew checkClassUniqueness " + "--write-locks` to accept them:\n\n" + expected); } @@ -146,7 +146,7 @@ private void ensureLockfileContains(String expected) { if (!onDisk.equals(expected)) { throw new GradleException(lockFile + " is out of date, please run `./gradlew " - + "checkClassUniquenessLock --write-locks` to update this file"); + + "checkClassUniqueness --write-locks` to update this file"); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessTask.java deleted file mode 100644 index 63f780ba8..000000000 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessTask.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * (c) Copyright 2018 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.baseline.tasks; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collection; -import java.util.Comparator; -import java.util.Set; -import java.util.stream.Collectors; -import org.gradle.api.DefaultTask; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ModuleVersionIdentifier; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Classpath; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; - -@CacheableTask -public class CheckClassUniquenessTask extends DefaultTask { - - private Configuration configuration; - - public CheckClassUniquenessTask() { - setGroup("Verification"); - setDescription("Checks that the given configuration contains no identically named classes."); - } - - @Classpath - public final Configuration getConfiguration() { - return configuration; - } - - public final void setConfiguration(Configuration configuration) { - this.configuration = configuration; - } - - @TaskAction - public final void checkForDuplicateClasses() { - ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(getLogger()); - analyzer.analyzeConfiguration(getConfiguration()); - boolean success = analyzer.getDifferingProblemJars().isEmpty(); - writeResultFile(success); - - if (!success) { - analyzer.getDifferingProblemJars().forEach(problemJars -> { - Set differingClasses = analyzer.getDifferingSharedClassesInProblemJars(problemJars); - getLogger().error("{} Identically named classes with differing impls found in {}: {}", - differingClasses.size(), problemJars, differingClasses); - }); - - throw new IllegalStateException(String.format( - "'%s' contains multiple copies of identically named classes - " - + "this may cause different runtime behaviour depending on classpath ordering.\n" - + "To resolve this, try excluding one of the following jars:\n\n%s", - configuration.getName(), - formatSummary(analyzer) - )); - } - } - - private static String formatSummary(ClassUniquenessAnalyzer summary) { - Collection> allProblemJars = summary.getDifferingProblemJars(); - - int maxLength = allProblemJars.stream().flatMap(Set::stream) - .map(ModuleVersionIdentifier::toString) - .map(String::length) - .max(Comparator.naturalOrder()).get(); - String format = "%-" + (maxLength + 1) + "s"; - - StringBuilder builder = new StringBuilder(); - - allProblemJars.forEach(problemJars -> { - int count = summary.getDifferingSharedClassesInProblemJars(problemJars).size(); - String countColumn = String.format("\t%-14s", "(" + count + " classes) "); - builder.append(countColumn); - - String jars = problemJars.stream().map(jar -> String.format(format, jar)).collect(Collectors.joining()); - builder.append(jars); - - builder.append('\n'); - }); - - return builder.toString(); - } - - /** - * This only exists to convince gradle this task is incremental. - */ - @OutputFile - public final File getResultFile() { - return getProject().getBuildDir().toPath() - .resolve(Paths.get("uniqueClassNames", configuration.getName())) - .toFile(); - } - - private void writeResultFile(boolean success) { - try { - File result = getResultFile(); - Files.createDirectories(result.toPath().getParent()); - Files.write(result.toPath(), Boolean.toString(success).getBytes(StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException("Unable to write boolean result file", e); - } - } -} diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index 2cd5008db..9c799a6d5 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -44,7 +44,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { dependencies { compile group: 'javax.el', name: 'javax.el-api', version: '3.0.0' compile group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.1' - } + } """.stripIndent() BuildResult result = with('check', '-s').buildAndFail() @@ -66,8 +66,8 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { myConf group: 'javax.el', name: 'javax.el-api', version: '3.0.0' myConf group: 'javax.servlet.jsp', name: 'jsp-api', version: '2.1' } - - checkClassUniquenessLock { + + checkClassUniqueness { configurations.add 'myConf' } """.stripIndent() @@ -86,11 +86,11 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { dependencies { compile 'com.palantir.tritium:tritium-api:0.9.0' compile 'com.palantir.tritium:tritium-core:0.9.0' - } + } """.stripIndent() then: - with('checkClassUniquenessLock', '-s').build() + with('checkClassUniqueness', '-s').build() } def 'task should be up-to-date when classpath is unchanged'() { @@ -98,11 +98,11 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { buildFile << standardBuildFile then: - BuildResult result1 = with('checkClassUniquenessLock').build() - result1.task(':checkClassUniquenessLock').outcome == TaskOutcome.SUCCESS + BuildResult result1 = with('checkClassUniqueness').build() + result1.task(':checkClassUniqueness').outcome == TaskOutcome.SUCCESS - BuildResult result = with('checkClassUniquenessLock').build() - result.task(':checkClassUniquenessLock').outcome == TaskOutcome.UP_TO_DATE + BuildResult result = with('checkClassUniqueness').build() + result.task(':checkClassUniqueness').outcome == TaskOutcome.UP_TO_DATE } def 'passes when no duplicates are present'() { @@ -116,10 +116,10 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { compile 'com.netflix.nebula:nebula-test:6.4.2' } """.stripIndent() - BuildResult result = with('checkClassUniquenessLock', '--info').build() + BuildResult result = with('checkClassUniqueness', '--info').build() then: - result.task(":checkClassUniquenessLock").outcome == TaskOutcome.SUCCESS + result.task(":checkClassUniqueness").outcome == TaskOutcome.SUCCESS println result.getOutput() } @@ -145,7 +145,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { """.stripIndent() then: - BuildResult result = with('checkClassUniquenessLock', '-s').buildAndFail() + BuildResult result = with('checkClassUniqueness', '-s').buildAndFail() result.output.contains("baseline-class-uniqueness detected multiple jars containing identically named classes") } @@ -166,8 +166,8 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { """.stripIndent() then: - BuildResult result = with('checkClassUniquenessLock', '--info').build() + BuildResult result = with('checkClassUniqueness', '--info').build() println result.getOutput() - result.task(":checkClassUniquenessLock").outcome == TaskOutcome.SUCCESS // ideally should should say failed! + result.task(":checkClassUniqueness").outcome == TaskOutcome.SUCCESS // ideally should should say failed! } } From 72a5deebb91d6233f660befad337cd3c671e60da Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:20:03 +0000 Subject: [PATCH 16/19] Might as well just store configurations --- README.md | 2 +- .../plugins/BaselineClassUniquenessPlugin.java | 3 ++- .../tasks/CheckClassUniquenessLockTask.java | 14 ++++++-------- ...lineClassUniquenessPluginIntegrationTest.groovy | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e19e7412c..105376109 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ This task can also be used to analyze other configurations in addition to `runti ```gradle checkClassUniqueness { - configurations.add 'myConf' + configurations.add project.configurations.myConf } ``` diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java index 31870bf53..b57a4ce80 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/plugins/BaselineClassUniquenessPlugin.java @@ -38,7 +38,8 @@ public final void apply(Project project) { project.getTasks().getByName(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(lockTask); project.getPlugins().withId("java", plugin -> { - lockTask.configure(t -> t.configurations.add(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)); + lockTask.configure(t -> t.configurations.add( + project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME))); }); } } diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java index 33cb235d7..f88939b43 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java @@ -20,9 +20,9 @@ import java.io.File; import java.util.Collection; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; @@ -42,12 +42,12 @@ public class CheckClassUniquenessLockTask extends DefaultTask { // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes @SuppressWarnings("VisibilityModifier") - public final SetProperty configurations; + public final SetProperty configurations; private final File lockFile; public CheckClassUniquenessLockTask() { - this.configurations = getProject().getObjects().setProperty(String.class); + this.configurations = getProject().getObjects().setProperty(Configuration.class); this.lockFile = getProject().file("baseline-class-uniqueness.lock"); onlyIf(new Spec() { @Override @@ -63,10 +63,9 @@ public boolean isSatisfiedBy(Task task) { */ @Input public final Map> getContentsOfAllConfigurations() { - return configurations.get().stream().collect(Collectors.toMap(Function.identity(), name -> { - Configuration configuration = getProject().getConfigurations().getByName(name); + return configurations.get().stream().collect(Collectors.toMap(Configuration::getName, configuration -> { return configuration.getIncoming().getResolutionResult().getAllComponents().stream() - .map(resolvedComponentResult -> resolvedComponentResult.getModuleVersion().toString()) + .map(resolvedComponentResult -> Objects.toString(resolvedComponentResult.getModuleVersion())) .collect(ImmutableList.toImmutableList()); // Gradle requires this to be Serializable })); } @@ -79,9 +78,8 @@ public final File getLockFile() { @TaskAction public final void doIt() { Map> resultsByConfiguration = configurations.get().stream() - .collect(Collectors.toMap(Function.identity(), configurationName -> { + .collect(Collectors.toMap(Configuration::getName, configuration -> { ClassUniquenessAnalyzer analyzer = new ClassUniquenessAnalyzer(getProject().getLogger()); - Configuration configuration = getProject().getConfigurations().getByName(configurationName); analyzer.analyzeConfiguration(configuration); Collection> problemJars = analyzer.getDifferingProblemJars(); diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index 9c799a6d5..f88089282 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -68,7 +68,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { } checkClassUniqueness { - configurations.add 'myConf' + configurations.add project.configurations.myConf } """.stripIndent() BuildResult result = with('check', '-s').buildAndFail() From cc64ddbadb59d4c63a3934359fd89239dc3838fd Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:29:51 +0000 Subject: [PATCH 17/19] Check in an example of the lockfile --- ...lassUniquenessPluginIntegrationTest.groovy | 17 +++++++++-- .../baseline-class-uniqueness.expected.lock | 30 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index f88089282..61a727ecc 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -20,6 +20,7 @@ import java.nio.file.Files import java.util.stream.Stream import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.TaskOutcome +import org.gradle.util.GFileUtils class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { @@ -37,7 +38,9 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { } """.stripIndent() - def 'detect duplicates in two external jars'() { + def 'detect duplicates in two external jars, then --write-locks captures'() { + File lockfile = new File(projectDir, 'baseline-class-uniqueness.lock') + when: buildFile << standardBuildFile buildFile << """ @@ -52,7 +55,16 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { result.getOutput().contains("baseline-class-uniqueness detected multiple jars containing identically named classes.") result.getOutput().contains("[javax.el:javax.el-api, javax.servlet.jsp:jsp-api]") result.getOutput().contains("javax.el.ArrayELResolver"); - println result.getOutput() + !lockfile.exists() + + with("checkClassUniqueness", "--write-locks").build() + lockfile.exists() + + File expected = new File("src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock") + if (Boolean.getBoolean("recreate")) { + GFileUtils.writeFile(lockfile.text, expected) + } + lockfile.text == expected.text } def 'detect duplicates in two external jars in non-standard configuration'() { @@ -121,6 +133,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { then: result.task(":checkClassUniqueness").outcome == TaskOutcome.SUCCESS println result.getOutput() + !new File(projectDir, "baseline-class-uniqueness.lock").exists() } def 'should detect duplicates from transitive dependencies'() { diff --git a/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock b/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock new file mode 100644 index 000000000..3f5d716f8 --- /dev/null +++ b/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock @@ -0,0 +1,30 @@ +# Run ./gradlew checkClassUniqueness --write-locks to update this file + +## runtimeClasspath +[javax.el:javax.el-api, javax.servlet.jsp:jsp-api] + - javax.el.ArrayELResolver + - javax.el.BeanELResolver + - javax.el.BeanELResolver$BeanProperties + - javax.el.BeanELResolver$BeanProperty + - javax.el.CompositeELResolver + - javax.el.CompositeELResolver$CompositeIterator + - javax.el.ELContext + - javax.el.ELContextEvent + - javax.el.ELContextListener + - javax.el.ELException + - javax.el.ELResolver + - javax.el.ELUtil + - javax.el.ELUtil$1 + - javax.el.Expression + - javax.el.ExpressionFactory + - javax.el.FunctionMapper + - javax.el.ListELResolver + - javax.el.MapELResolver + - javax.el.MethodExpression + - javax.el.MethodInfo + - javax.el.MethodNotFoundException + - javax.el.PropertyNotFoundException + - javax.el.PropertyNotWritableException + - javax.el.ResourceBundleELResolver + - javax.el.ValueExpression + - javax.el.VariableMapper From f34a748050010b3e29ddf2590ba527da51c69b99 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:33:14 +0000 Subject: [PATCH 18/19] Include 'Danger!' in the lockfile --- README.md | 1 + .../baseline/tasks/CheckClassUniquenessLockTask.java | 6 +++++- .../BaselineClassUniquenessPluginIntegrationTest.groovy | 2 +- .../baseline/baseline-class-uniqueness.expected.lock | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 105376109..45e4e7b1b 100644 --- a/README.md +++ b/README.md @@ -230,6 +230,7 @@ in `.baseline/copyright/*.txt` and the RegexpHeader checkstyle configuration in When applied to a java project, this inspects all the jars in your `runtimeClasspath` configuration and records any conflicts to a `baseline-class-uniqueness.lock` file. For example: ``` +# Danger! Multiple jars contain identically named classes. This may cause different behaviour depending on classpath ordering. # Run ./gradlew checkClassUniqueness --write-locks to update this file ## runtimeClasspath diff --git a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java index f88939b43..7c37fe3e1 100644 --- a/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java +++ b/gradle-baseline-java/src/main/groovy/com/palantir/baseline/tasks/CheckClassUniquenessLockTask.java @@ -40,6 +40,10 @@ @CacheableTask public class CheckClassUniquenessLockTask extends DefaultTask { + private static final String HEADER = "# Danger! Multiple jars contain identically named classes. This may " + + "cause different behaviour depending on classpath ordering.\n" + + "# Run ./gradlew checkClassUniqueness --write-locks to update this file\n\n"; + // not marking this as an Input, because we want to re-run if the *contents* of a configuration changes @SuppressWarnings("VisibilityModifier") public final SetProperty configurations; @@ -115,7 +119,7 @@ public final void doIt() { ensureLockfileDoesNotExist(); } else { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("# Run ./gradlew checkClassUniqueness --write-locks to update this file\n\n"); + stringBuilder.append(HEADER); // TODO(dfox): make configuration order stable! resultsByConfiguration.forEach((configuration, contents) -> { if (contents.isPresent()) { diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index 61a727ecc..1a5d10e8f 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -61,7 +61,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { lockfile.exists() File expected = new File("src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock") - if (Boolean.getBoolean("recreate")) { + if (true || Boolean.getBoolean("recreate")) { GFileUtils.writeFile(lockfile.text, expected) } lockfile.text == expected.text diff --git a/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock b/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock index 3f5d716f8..666f6be9b 100644 --- a/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock +++ b/gradle-baseline-java/src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock @@ -1,3 +1,4 @@ +# Danger! Multiple jars contain identically named classes. This may cause different behaviour depending on classpath ordering. # Run ./gradlew checkClassUniqueness --write-locks to update this file ## runtimeClasspath From 8a17aecc9dc95a484b2114acf33d65099a18af32 Mon Sep 17 00:00:00 2001 From: Dan Fox Date: Tue, 7 Jan 2020 17:49:04 +0000 Subject: [PATCH 19/19] Don't always recreate --- .../BaselineClassUniquenessPluginIntegrationTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy index 1a5d10e8f..61a727ecc 100644 --- a/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy +++ b/gradle-baseline-java/src/test/groovy/com/palantir/baseline/BaselineClassUniquenessPluginIntegrationTest.groovy @@ -61,7 +61,7 @@ class BaselineClassUniquenessPluginIntegrationTest extends AbstractPluginTest { lockfile.exists() File expected = new File("src/test/resources/com/palantir/baseline/baseline-class-uniqueness.expected.lock") - if (true || Boolean.getBoolean("recreate")) { + if (Boolean.getBoolean("recreate")) { GFileUtils.writeFile(lockfile.text, expected) } lockfile.text == expected.text