From 6b0f6e9f27f57624f392189610be388dcbac36c7 Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Thu, 6 Oct 2022 13:52:47 +0200 Subject: [PATCH] Apply Gradle Test Retry plugin The plugin is configured to detect flaky tests and retry them 3 times when running on the CI, but still reports failures. This will provide a standard way to detect flaky tests as failures and successful attempts are shown in the tests report. --- build.gradle | 2 +- buildSrc/README.md | 6 +- buildSrc/build.gradle | 7 ++- ...nsPlugin.java => CompilerConventions.java} | 10 ++-- .../build/ConventionsPlugin.java | 41 ++++++++++++++ .../build/TestConventions.java | 56 +++++++++++++++++++ gradle/spring-module.gradle | 2 +- 7 files changed, 112 insertions(+), 12 deletions(-) rename buildSrc/src/main/java/org/springframework/build/{compile/CompilerConventionsPlugin.java => CompilerConventions.java} (90%) create mode 100644 buildSrc/src/main/java/org/springframework/build/ConventionsPlugin.java create mode 100644 buildSrc/src/main/java/org/springframework/build/TestConventions.java diff --git a/build.gradle b/build.gradle index aa441632281..9e5378436f6 100644 --- a/build.gradle +++ b/build.gradle @@ -46,7 +46,7 @@ configure([rootProject] + javaProjects) { project -> apply plugin: "java" apply plugin: "java-test-fixtures" apply plugin: "checkstyle" - apply plugin: 'org.springframework.build.compile' + apply plugin: 'org.springframework.build.conventions' apply from: "${rootDir}/gradle/toolchains.gradle" apply from: "${rootDir}/gradle/ide.gradle" diff --git a/buildSrc/README.md b/buildSrc/README.md index cc8c3e58f3d..f101ed75f2d 100644 --- a/buildSrc/README.md +++ b/buildSrc/README.md @@ -5,9 +5,11 @@ They are declared in the `build.gradle` file in this folder. ## Build Conventions -### Compiler conventions +The `org.springframework.build.conventions` plugin applies all conventions to the Framework build: + +* Configuring the Java compiler, see `CompilerConventions` +* Configuring testing in the build with `TestConventions` -The `org.springframework.build.compile` plugin applies the Java compiler conventions to the build. ## Build Plugins diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 1d4b7700cbb..27dfb54fead 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -9,6 +9,7 @@ repositories { dependencies { implementation "me.champeau.gradle:japicmp-gradle-plugin:0.3.0" + implementation "org.gradle:test-retry-gradle-plugin:1.4.1" } gradlePlugin { @@ -17,9 +18,9 @@ gradlePlugin { id = "org.springframework.build.api-diff" implementationClass = "org.springframework.build.api.ApiDiffPlugin" } - compileConventionsPlugin { - id = "org.springframework.build.compile" - implementationClass = "org.springframework.build.compile.CompilerConventionsPlugin" + conventionsPlugin { + id = "org.springframework.build.conventions" + implementationClass = "org.springframework.build.ConventionsPlugin" } optionalDependenciesPlugin { id = "org.springframework.build.optional-dependencies" diff --git a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java similarity index 90% rename from buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java rename to buildSrc/src/main/java/org/springframework/build/CompilerConventions.java index 0942ffd4fd5..22d8ad5330b 100644 --- a/buildSrc/src/main/java/org/springframework/build/compile/CompilerConventionsPlugin.java +++ b/buildSrc/src/main/java/org/springframework/build/CompilerConventions.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.build.compile; +package org.springframework.build; import java.util.ArrayList; import java.util.Arrays; @@ -22,6 +22,7 @@ import java.util.List; import org.gradle.api.Plugin; import org.gradle.api.Project; +import org.gradle.api.plugins.JavaBasePlugin; import org.gradle.api.plugins.JavaLibraryPlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.tasks.compile.JavaCompile; @@ -33,7 +34,7 @@ import org.gradle.api.tasks.compile.JavaCompile; * @author Sam Brannen * @author Sebastien Deleuze */ -public class CompilerConventionsPlugin implements Plugin { +public class CompilerConventions { private static final List COMPILER_ARGS; @@ -58,9 +59,8 @@ public class CompilerConventionsPlugin implements Plugin { "-Xlint:-deprecation", "-Xlint:-unchecked")); } - @Override public void apply(Project project) { - project.getPlugins().withType(JavaLibraryPlugin.class, javaPlugin -> applyJavaCompileConventions(project)); + project.getPlugins().withType(JavaBasePlugin.class, javaPlugin -> applyJavaCompileConventions(project)); } /** diff --git a/buildSrc/src/main/java/org/springframework/build/ConventionsPlugin.java b/buildSrc/src/main/java/org/springframework/build/ConventionsPlugin.java new file mode 100644 index 00000000000..bcfc9641fce --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/build/ConventionsPlugin.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.build; + +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaBasePlugin; + +/** + * Plugin to apply conventions to projects that are part of Spring Framework's build. + * Conventions are applied in response to various plugins being applied. + * + * When the {@link JavaBasePlugin} is applied, the conventions in {@link TestConventions} + * are applied. + * When the {@link JavaBasePlugin} is applied, the conventions in {@link CompilerConventions} + * are applied. + * + * @author Brian Clozel + */ +public class ConventionsPlugin implements Plugin { + + @Override + public void apply(Project project) { + new TestConventions().apply(project); + new CompilerConventions().apply(project); + } +} diff --git a/buildSrc/src/main/java/org/springframework/build/TestConventions.java b/buildSrc/src/main/java/org/springframework/build/TestConventions.java new file mode 100644 index 00000000000..42f710cf783 --- /dev/null +++ b/buildSrc/src/main/java/org/springframework/build/TestConventions.java @@ -0,0 +1,56 @@ +/* + * Copyright 2002-2022 the original author or authors. + * + * 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 + * + * https://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 org.springframework.build; + +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaBasePlugin; +import org.gradle.api.tasks.testing.Test; +import org.gradle.testretry.TestRetryPlugin; +import org.gradle.testretry.TestRetryTaskExtension; + +/** + * Conventions that are applied in the presence of the {@link JavaBasePlugin}. When the + * plugin is applied: + *
    + *
  • The {@link TestRetryPlugin Test Retry} plugins is applied so that flaky tests + * are retried 3 times when running on the CI. + *
+ * + * @author Brian Clozel + * @author Andy Wilkinson + */ +class TestConventions { + + void apply(Project project) { + project.getPlugins().withType(JavaBasePlugin.class, (java) -> configureTestConventions(project)); + } + + private void configureTestConventions(Project project) { + project.getPlugins().apply(TestRetryPlugin.class); + project.getTasks().withType(Test.class, + (test) -> project.getPlugins().withType(TestRetryPlugin.class, (testRetryPlugin) -> { + TestRetryTaskExtension testRetry = test.getExtensions().getByType(TestRetryTaskExtension.class); + testRetry.getFailOnPassedAfterRetry().set(true); + testRetry.getMaxRetries().set(isCi() ? 3 : 0); + })); + } + + private boolean isCi() { + return Boolean.parseBoolean(System.getenv("CI")); + } + +} diff --git a/gradle/spring-module.gradle b/gradle/spring-module.gradle index 7628127cb5d..0bf7cccfc28 100644 --- a/gradle/spring-module.gradle +++ b/gradle/spring-module.gradle @@ -1,5 +1,5 @@ apply plugin: 'java-library' -apply plugin: 'org.springframework.build.compile' +apply plugin: 'org.springframework.build.conventions' apply plugin: 'org.springframework.build.optional-dependencies' // Uncomment the following for Shadow support in the jmhJar block. // Currently commented out due to ZipException: archive is not a ZIP archive