You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by pr...@apache.org on 2019/04/08 16:44:34 UTC

[geode] branch develop updated: GEODE-6383: All subprojects should opt into configuration. (#3403)

This is an automated email from the ASF dual-hosted git repository.

prhomberg pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/geode.git


The following commit(s) were added to refs/heads/develop by this push:
     new 63bd991  GEODE-6383: All subprojects should opt into configuration. (#3403)
63bd991 is described below

commit 63bd991444d3fe60272be01dc614c4e51569fcd7
Author: Patrick Rhomberg <pr...@pivotal.io>
AuthorDate: Mon Apr 8 09:44:23 2019 -0700

    GEODE-6383: All subprojects should opt into configuration. (#3403)
    
    * The collection of java.gradle, ide.gradle, spotless.gradle et al have been collected to standard-subproject-configuration.gradle.
    * This configuration is applied to every subproject to be consistent with previous behavior.  This will be audited and adjusted in GEODE-6611.
    * Several cross-subproject evaluation dependencies have been made explicit.
---
 boms/build.gradle                                  |   2 +
 boms/geode-all-bom/build.gradle                    |   4 +-
 boms/geode-client-bom/build.gradle                 |   2 +
 build.gradle                                       |  62 ++-
 extensions/build.gradle                            |   2 +
 extensions/geode-modules-assembly/build.gradle     |  10 +
 .../geode-modules-session-internal/build.gradle    |   2 +
 extensions/geode-modules-session/build.gradle      |   2 +
 extensions/geode-modules-test/build.gradle         |   2 +
 extensions/geode-modules-tomcat7/build.gradle      |   2 +
 extensions/geode-modules-tomcat8/build.gradle      |   2 +
 extensions/geode-modules-tomcat9/build.gradle      |   2 +
 extensions/geode-modules/build.gradle              |   2 +
 extensions/session-testing-war/build.gradle        |   3 +
 geode-assembly/build.gradle                        |  16 +-
 geode-assembly/geode-assembly-test/build.gradle    |   2 +
 geode-common/build.gradle                          |   2 +
 geode-concurrency-test/build.gradle                |   2 +
 geode-connectors/build.gradle                      |   2 +
 geode-core/build.gradle                            |   2 +
 geode-cq/build.gradle                              |   2 +
 geode-dunit/build.gradle                           |   2 +
 geode-experimental-driver/build.gradle             |   2 +
 geode-junit/build.gradle                           |   2 +
 geode-lucene/build.gradle                          |   2 +
 geode-lucene/geode-lucene-test/build.gradle        |   2 +
 geode-management/build.gradle                      |   2 +
 geode-memcached/build.gradle                       |   2 +
 geode-old-client-support/build.gradle              |   2 +
 geode-old-versions/build.gradle                    |   4 +
 geode-protobuf-messages/build.gradle               |   2 +
 geode-protobuf/build.gradle                        |   2 +
 geode-protobuf/geode-protobuf-test/build.gradle    |   2 +
 geode-pulse/build.gradle                           |   2 +
 geode-pulse/geode-pulse-test/build.gradle          |   3 +-
 geode-rebalancer/build.gradle                      |   2 +
 geode-redis/build.gradle                           |   2 +
 geode-wan/build.gradle                             |   2 +
 geode-web-api/build.gradle                         |   2 +
 geode-web-management/build.gradle                  |   2 +
 geode-web/build.gradle                             |   2 +
 gradle/code-analysis.gradle                        | 167 ++++-----
 gradle/dependency-resolution.gradle                |  97 +++--
 gradle/docker.gradle                               |  32 +-
 gradle/ide.gradle                                  |  94 +++--
 gradle/java.gradle                                 | 156 ++++----
 gradle/rat.gradle                                  |   2 +
 gradle/spotless.gradle                             | 218 +++++------
 gradle/standard-subproject-configuration.gradle    |  55 +++
 gradle/test.gradle                                 | 417 ++++++++++-----------
 {boms => static-analysis}/build.gradle             |   3 +-
 static-analysis/pmd-rules/build.gradle             |   3 +
 52 files changed, 761 insertions(+), 653 deletions(-)

diff --git a/boms/build.gradle b/boms/build.gradle
index 8f5c586..5c31f87 100644
--- a/boms/build.gradle
+++ b/boms/build.gradle
@@ -15,5 +15,7 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 jar.enabled = false
 
diff --git a/boms/geode-all-bom/build.gradle b/boms/geode-all-bom/build.gradle
index 041c890..ce91360 100644
--- a/boms/geode-all-bom/build.gradle
+++ b/boms/geode-all-bom/build.gradle
@@ -16,10 +16,12 @@
  */
 
 plugins {
-  id 'geode-dependency-constraints'
   id 'maven-publish'
 }
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+apply plugin: 'geode-dependency-constraints'
+
 apply from: "${project.projectDir}/../../gradle/publish.gradle"
 
 jar.enabled = false
diff --git a/boms/geode-client-bom/build.gradle b/boms/geode-client-bom/build.gradle
index 7530369..3a6a1a1 100644
--- a/boms/geode-client-bom/build.gradle
+++ b/boms/geode-client-bom/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: "io.spring.dependency-management"
 apply from: "${project.projectDir}/../../gradle/publish.gradle"
 
diff --git a/build.gradle b/build.gradle
index 6c64132..31f6909 100755
--- a/build.gradle
+++ b/build.gradle
@@ -37,6 +37,18 @@ buildscript {
 
 apply plugin: 'wrapper'
 apply plugin: 'nebula.facet'
+apply plugin: 'java-library'
+apply plugin: 'idea'
+apply plugin: 'eclipse'
+
+apply from: "${scriptDir}/lint.gradle"
+apply from: "${scriptDir}/resolve-dependencies.gradle"
+apply from: "${scriptDir}/sonar.gradle"
+apply from: "${scriptDir}/rat.gradle"
+
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+compileJava.options.encoding = 'UTF-8'
 
 wrapper {
   gradleVersion = minimumGradleVersion
@@ -62,36 +74,15 @@ allprojects {
   }
 }
 
-apply from: "${scriptDir}/java.gradle"
-apply from: "${scriptDir}/ide.gradle"
-apply from: "${scriptDir}/dependency-resolution.gradle"
-apply from: "${scriptDir}/test.gradle"
-apply from: "${scriptDir}/code-analysis.gradle"
-apply from: "${scriptDir}/sonar.gradle"
-apply from: "${scriptDir}/rat.gradle"
-apply from: "${scriptDir}/docker.gradle"
-apply from: "${scriptDir}/spotless.gradle"
-apply from: "${scriptDir}/lint.gradle"
-apply from: "${scriptDir}/resolve-dependencies.gradle"
-
-subprojects {
-  apply plugin: 'com.github.ben-manes.versions'
-}
+task combineReports(type: TestReport) {
+  description 'Combines the test reports.'
+  destinationDir = file "${rootProject.buildDir}/reports/combined"
 
-check.dependsOn rat
-
-task devBuild(dependsOn: [":assemble"]) {
-  description "A convenience target for a typical developer workflow: apply spotless and assemble all classes."
-  // spotless targets are not available until after evaluation.
-  subprojects {
-    afterEvaluate {
-      this.devBuild.dependsOn(project.spotlessApply)
-    }
+  doLast {
+    println "All test reports at ${rootProject.buildDir}/reports/combined"
   }
 }
 
-
-
 ext.readScmInfo = { proj ->
   // Attempt to read git information, or else return UNKNOWN
   try {
@@ -121,7 +112,7 @@ ext.readScmInfo = { proj ->
   }
 }
 
-task writeBuildInfo {
+tasks.register('writeBuildInfo') {
   def buildInfo = file "$buildDir/.buildinfo"
   def scmInfo = this.readScmInfo("geode-core")
 
@@ -135,6 +126,12 @@ task writeBuildInfo {
   }
 }
 
+tasks.register('devBuild') {
+  description "A convenience target for a typical developer workflow: apply spotless and assemble all classes."
+  dependsOn tasks.named('assemble')
+  // Each subproject injects its SpotlessApply as a dependency to this task in the standard config
+}
+
 tasks.register('generate') {
   group = 'Build'
   description = "Top-level target for all source generation. Helps IDE integration"
@@ -180,9 +177,8 @@ if (project.hasProperty('askpass')) {
   }
 }
 
-// Explicitly chain generic tasks -- composite builds do not cascade these tasks by default.
-['clean', 'check', 'test'].each { chainedTask ->
-  rootProject.tasks.named(chainedTask).configure {
-    dependsOn(subprojects*.tasks*.named(chainedTask))
-  }
-}
+gradle.taskGraph.whenReady({ graph ->
+  tasks.getByName('combineReports').reportOn rootProject.subprojects.collect {
+    it.tasks.withType(Test)
+  }.flatten()
+})
diff --git a/extensions/build.gradle b/extensions/build.gradle
index ae6f28c..9259044 100755
--- a/extensions/build.gradle
+++ b/extensions/build.gradle
@@ -14,3 +14,5 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
diff --git a/extensions/geode-modules-assembly/build.gradle b/extensions/geode-modules-assembly/build.gradle
index 13c9597..9019747 100644
--- a/extensions/geode-modules-assembly/build.gradle
+++ b/extensions/geode-modules-assembly/build.gradle
@@ -15,6 +15,16 @@
  * limitations under the License.
  */
 
+evaluationDependsOn(':extensions:geode-modules')
+evaluationDependsOn(':extensions:geode-modules-tomcat7')
+evaluationDependsOn(':extensions:geode-modules-tomcat8')
+evaluationDependsOn(':extensions:geode-modules-tomcat9')
+evaluationDependsOn(':extensions:geode-modules-session')
+evaluationDependsOn(':extensions:geode-modules-session-internal')
+  
+  
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 import org.apache.geode.gradle.plugins.DependencyConstraints
 import org.apache.tools.ant.filters.ReplaceTokens
 apply plugin: 'maven-publish'
diff --git a/extensions/geode-modules-session-internal/build.gradle b/extensions/geode-modules-session-internal/build.gradle
index c34190b..deca285 100644
--- a/extensions/geode-modules-session-internal/build.gradle
+++ b/extensions/geode-modules-session-internal/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 
 dependencies {
diff --git a/extensions/geode-modules-session/build.gradle b/extensions/geode-modules-session/build.gradle
index 76c386f..67f4821 100644
--- a/extensions/geode-modules-session/build.gradle
+++ b/extensions/geode-modules-session/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 
diff --git a/extensions/geode-modules-test/build.gradle b/extensions/geode-modules-test/build.gradle
index dd8da08..e992e64 100644
--- a/extensions/geode-modules-test/build.gradle
+++ b/extensions/geode-modules-test/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 
 dependencies {
diff --git a/extensions/geode-modules-tomcat7/build.gradle b/extensions/geode-modules-tomcat7/build.gradle
index ac1ac5b..f5ff7e9 100644
--- a/extensions/geode-modules-tomcat7/build.gradle
+++ b/extensions/geode-modules-tomcat7/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 
diff --git a/extensions/geode-modules-tomcat8/build.gradle b/extensions/geode-modules-tomcat8/build.gradle
index 243ff28..f6d62b8 100644
--- a/extensions/geode-modules-tomcat8/build.gradle
+++ b/extensions/geode-modules-tomcat8/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 
diff --git a/extensions/geode-modules-tomcat9/build.gradle b/extensions/geode-modules-tomcat9/build.gradle
index 757a3b1..280e530 100644
--- a/extensions/geode-modules-tomcat9/build.gradle
+++ b/extensions/geode-modules-tomcat9/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 
diff --git a/extensions/geode-modules/build.gradle b/extensions/geode-modules/build.gradle
index 50eeeb1..09ca34e 100644
--- a/extensions/geode-modules/build.gradle
+++ b/extensions/geode-modules/build.gradle
@@ -17,6 +17,8 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 
diff --git a/extensions/session-testing-war/build.gradle b/extensions/session-testing-war/build.gradle
index 67c4251..1e3e366 100644
--- a/extensions/session-testing-war/build.gradle
+++ b/extensions/session-testing-war/build.gradle
@@ -14,6 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: 'war'
 
 
diff --git a/geode-assembly/build.gradle b/geode-assembly/build.gradle
index 1a724a3..532b0fd 100755
--- a/geode-assembly/build.gradle
+++ b/geode-assembly/build.gradle
@@ -15,14 +15,24 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 import org.apache.geode.gradle.plugins.DependencyConstraints
 
 import java.nio.file.Paths
 
-evaluationDependsOn(":geode-core")
-evaluationDependsOn(":geode-protobuf-messages")
-
+// This project aggressively reaches into many other projects and must wait for those configurations
+// to be evaluated and resolved.  As a safeguard against this and to avoid having to explicitly 
+// re-list every geode-* here, we instead depend on every subproject of rootProject, excluding this
+// project itself.  Additionally, this project also aggressively inspects its own subprojects.
+// Evaluation depends on them all.
+evaluationDependsOnChildren()
+rootProject.subprojects.each { neighborProject ->
+  if (neighborProject != project) {
+    project.evaluationDependsOn(neighborProject.path)
+  }
+}
 apply plugin: 'distribution'
 apply from: "${rootDir}/${scriptDir}/publish.gradle"
 
diff --git a/geode-assembly/geode-assembly-test/build.gradle b/geode-assembly/geode-assembly-test/build.gradle
index f649b9c..aa02bb0 100755
--- a/geode-assembly/geode-assembly-test/build.gradle
+++ b/geode-assembly/geode-assembly-test/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 
 
diff --git a/geode-common/build.gradle b/geode-common/build.gradle
index 9bf17b1..4c39a58 100755
--- a/geode-common/build.gradle
+++ b/geode-common/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 dependencies {
diff --git a/geode-concurrency-test/build.gradle b/geode-concurrency-test/build.gradle
index 3ab10bb..9138536 100644
--- a/geode-concurrency-test/build.gradle
+++ b/geode-concurrency-test/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 dependencies {
diff --git a/geode-connectors/build.gradle b/geode-connectors/build.gradle
index b267982..6922a70 100644
--- a/geode-connectors/build.gradle
+++ b/geode-connectors/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 evaluationDependsOn(":geode-core")
 
 repositories {
diff --git a/geode-core/build.gradle b/geode-core/build.gradle
index d7e970b..2692bc5 100755
--- a/geode-core/build.gradle
+++ b/geode-core/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: 'antlr'
 apply plugin: 'me.champeau.gradle.jmh'
 apply from: "${project.projectDir}/../gradle/publish.gradle"
diff --git a/geode-cq/build.gradle b/geode-cq/build.gradle
index 84be17c..95dd93d 100644
--- a/geode-cq/build.gradle
+++ b/geode-cq/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-dunit/build.gradle b/geode-dunit/build.gradle
index 67906e3..0573e1b 100755
--- a/geode-dunit/build.gradle
+++ b/geode-dunit/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-experimental-driver/build.gradle b/geode-experimental-driver/build.gradle
index 0689dac..a673307 100644
--- a/geode-experimental-driver/build.gradle
+++ b/geode-experimental-driver/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-junit/build.gradle b/geode-junit/build.gradle
index 9e6a641..640df36 100755
--- a/geode-junit/build.gradle
+++ b/geode-junit/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-lucene/build.gradle b/geode-lucene/build.gradle
index 351f51e..b4313c3 100644
--- a/geode-lucene/build.gradle
+++ b/geode-lucene/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-lucene/geode-lucene-test/build.gradle b/geode-lucene/geode-lucene-test/build.gradle
index 51de6ee..32b8fbd 100644
--- a/geode-lucene/geode-lucene-test/build.gradle
+++ b/geode-lucene/geode-lucene-test/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 
 
diff --git a/geode-management/build.gradle b/geode-management/build.gradle
index fede2f3..1b12146 100755
--- a/geode-management/build.gradle
+++ b/geode-management/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 dependencies {
diff --git a/geode-memcached/build.gradle b/geode-memcached/build.gradle
index 4305b8b..ba5a8c6 100644
--- a/geode-memcached/build.gradle
+++ b/geode-memcached/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 dependencies {
diff --git a/geode-old-client-support/build.gradle b/geode-old-client-support/build.gradle
index dec4463..3293007 100644
--- a/geode-old-client-support/build.gradle
+++ b/geode-old-client-support/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-old-versions/build.gradle b/geode-old-versions/build.gradle
index 0a1d379..48c6338 100644
--- a/geode-old-versions/build.gradle
+++ b/geode-old-versions/build.gradle
@@ -17,10 +17,14 @@ import java.nio.file.Paths
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 project.ext.installs = new Properties()
 project.ext.versions = new Properties()
 
 subprojects {
+  apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
   def oldGeodeVersion = project.name
 
   boolean useTgz = (oldGeodeVersion >= "1.7.0")
diff --git a/geode-protobuf-messages/build.gradle b/geode-protobuf-messages/build.gradle
index 87d10e5..f0f9b5a 100644
--- a/geode-protobuf-messages/build.gradle
+++ b/geode-protobuf-messages/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 import org.apache.geode.gradle.plugins.DependencyConstraints
 
 buildscript {
diff --git a/geode-protobuf/build.gradle b/geode-protobuf/build.gradle
index 0f5323c..890a6ba 100644
--- a/geode-protobuf/build.gradle
+++ b/geode-protobuf/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-protobuf/geode-protobuf-test/build.gradle b/geode-protobuf/geode-protobuf-test/build.gradle
index 1e3bef7..07d550e 100644
--- a/geode-protobuf/geode-protobuf-test/build.gradle
+++ b/geode-protobuf/geode-protobuf-test/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 
 
 
diff --git a/geode-pulse/build.gradle b/geode-pulse/build.gradle
index 5cd6760..30fe0d1 100644
--- a/geode-pulse/build.gradle
+++ b/geode-pulse/build.gradle
@@ -14,6 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
 apply plugin: 'war'
 
 apply from: "${project.projectDir}/../gradle/publish.gradle"
diff --git a/geode-pulse/geode-pulse-test/build.gradle b/geode-pulse/geode-pulse-test/build.gradle
index a2f5b4d..26f7f62 100644
--- a/geode-pulse/geode-pulse-test/build.gradle
+++ b/geode-pulse/geode-pulse-test/build.gradle
@@ -15,8 +15,7 @@
  * limitations under the License.
  */
 
-
-
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
 
 dependencies {
   compile(platform(project(':boms:geode-all-bom')))
diff --git a/geode-rebalancer/build.gradle b/geode-rebalancer/build.gradle
index 8bc11bd..e74426d 100644
--- a/geode-rebalancer/build.gradle
+++ b/geode-rebalancer/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-redis/build.gradle b/geode-redis/build.gradle
index 9abfd75..b3d8595 100644
--- a/geode-redis/build.gradle
+++ b/geode-redis/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 dependencies {
diff --git a/geode-wan/build.gradle b/geode-wan/build.gradle
index 88ac3ac..3e2c0d5 100644
--- a/geode-wan/build.gradle
+++ b/geode-wan/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply from: "${project.projectDir}/../gradle/publish.gradle"
 
 
diff --git a/geode-web-api/build.gradle b/geode-web-api/build.gradle
index 402ef01..9c50089 100644
--- a/geode-web-api/build.gradle
+++ b/geode-web-api/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: 'war'
 
 apply from: "${project.projectDir}/../gradle/publish.gradle"
diff --git a/geode-web-management/build.gradle b/geode-web-management/build.gradle
index c0a1722..73433ea 100644
--- a/geode-web-management/build.gradle
+++ b/geode-web-management/build.gradle
@@ -13,6 +13,8 @@
  * the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: 'war'
 
 apply from: "${project.projectDir}/../gradle/publish.gradle"
diff --git a/geode-web/build.gradle b/geode-web/build.gradle
index 0f430e6..b006261 100644
--- a/geode-web/build.gradle
+++ b/geode-web/build.gradle
@@ -15,6 +15,8 @@
  * limitations under the License.
  */
 
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 apply plugin: 'war'
 
 apply from: "${project.projectDir}/../gradle/publish.gradle"
diff --git a/gradle/code-analysis.gradle b/gradle/code-analysis.gradle
index 7ce31e8..4e2086f 100644
--- a/gradle/code-analysis.gradle
+++ b/gradle/code-analysis.gradle
@@ -14,100 +14,99 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-subprojects {
-  if (project.hasProperty("staticAnalysis")) {
-    apply plugin: 'checkstyle'
-  
-    //Checkstyle configuration
-    configurations.checkstyle {
-      dependencies.all { dep ->
-        dep.transitive = true
-      }
+
+if (project.hasProperty("staticAnalysis")) {
+  apply plugin: 'checkstyle'
+
+  //Checkstyle configuration
+  configurations.checkstyle {
+    dependencies.all { dep ->
+      dep.transitive = true
     }
-  
-    //Findbugs configuration
-    apply plugin: 'findbugs'
-  
-    // Switch default Findbugs report to HTML for developers
-    def findbugsXmlEnabled = false
-    def findbugsHtmlEnabled = true
-  
-    // Provide ability to change report type to XML for ingesting into other ap
-    if ( project.hasProperty("findbugsXmlReport") ) {
-      findbugsXmlEnabled = true
-      findbugsHtmlEnabled = false
-    }
-  
-    configurations.findbugs {
-      dependencies.all { dep ->
-        dep.transitive = true
-      }
-      findbugs.effort = 'max'
-      findbugs.reportLevel = 'low'
+  }
+
+  //Findbugs configuration
+  apply plugin: 'findbugs'
+
+  // Switch default Findbugs report to HTML for developers
+  def findbugsXmlEnabled = false
+  def findbugsHtmlEnabled = true
+
+  // Provide ability to change report type to XML for ingesting into other ap
+  if (project.hasProperty("findbugsXmlReport")) {
+    findbugsXmlEnabled = true
+    findbugsHtmlEnabled = false
+  }
+
+  configurations.findbugs {
+    dependencies.all { dep ->
+      dep.transitive = true
     }
-  
-    tasks.withType(FindBugs) {
-      reports {
-        xml.enabled = findbugsXmlEnabled
-        html.enabled = findbugsHtmlEnabled
-      }
+    findbugs.effort = 'max'
+    findbugs.reportLevel = 'low'
+  }
+
+  tasks.withType(FindBugs) {
+    reports {
+      xml.enabled = findbugsXmlEnabled
+      html.enabled = findbugsHtmlEnabled
     }
   }
-  
-  // JaCoCo configuration
-  if (project.hasProperty("codeCoverage")) {
-    apply plugin: 'jacoco'
-  
-    configurations.jacocoAnt {
-      dependencies.all { dep ->
-        dep.transitive = true
-      }
+}
+
+// JaCoCo configuration
+if (project.hasProperty("codeCoverage")) {
+  apply plugin: 'jacoco'
+
+  configurations.jacocoAnt {
+    dependencies.all { dep ->
+      dep.transitive = true
     }
-  
-    task mergeIntegrationTestCoverage (type: JacocoMerge) {
-      description 'Merges Distributed and Integration test coverage results'
-  
-      destinationFile = file("${buildDir}/jacoco/mergedIntegrationTestCoverage.exec")
-      executionData = fileTree(dir: 'build/jacoco', include: [
+  }
+
+  task mergeIntegrationTestCoverage(type: JacocoMerge) {
+    description 'Merges Distributed and Integration test coverage results'
+
+    destinationFile = file("${buildDir}/jacoco/mergedIntegrationTestCoverage.exec")
+    executionData = fileTree(dir: 'build/jacoco', include: [
         '**/distributedTest.exec',
         '**/integrationTest.exec'
-      ])
-  
-    }
-  
-    jacocoTestReport {
-      reports {
-        csv.enabled false
-        sourceSets project.sourceSets.main
-        html.destination "${buildDir}/jacocoTestHtml"
-      }
+    ])
+
+  }
+
+  jacocoTestReport {
+    reports {
+      csv.enabled false
+      sourceSets project.sourceSets.main
+      html.destination "${buildDir}/jacocoTestHtml"
     }
-  
-    task jacocoIntegrationTestReport (type: JacocoReport) {
-      reports {
-        csv.enabled false
-        sourceSets project.sourceSets.main
-        html.destination "${buildDir}/jacocoIntegrationTestHtml"
-        executionData = fileTree(dir: 'build/jacoco', include: '**/integrationTest.exec')
-      }
+  }
+
+  task jacocoIntegrationTestReport(type: JacocoReport) {
+    reports {
+      csv.enabled false
+      sourceSets project.sourceSets.main
+      html.destination "${buildDir}/jacocoIntegrationTestHtml"
+      executionData = fileTree(dir: 'build/jacoco', include: '**/integrationTest.exec')
     }
-  
-    task jacocoDistributedTestReport (type: JacocoReport) {
-      reports {
-        csv.enabled false
-        sourceSets project.sourceSets.main
-        html.destination "${buildDir}/jacocoDistributedTestHtml"
-        executionData = fileTree(dir: 'build/jacoco', include: '**/distributedTest.exec')
-      }
+  }
+
+  task jacocoDistributedTestReport(type: JacocoReport) {
+    reports {
+      csv.enabled false
+      sourceSets project.sourceSets.main
+      html.destination "${buildDir}/jacocoDistributedTestHtml"
+      executionData = fileTree(dir: 'build/jacoco', include: '**/distributedTest.exec')
     }
-  
-    task jacocoOverallTestReport (type: JacocoReport) {
-      reports {
-        csv.enabled false
-        sourceSets project.sourceSets.main
-        html.destination "${buildDir}/jacocoOverallTestHtml"
-        executionData = fileTree(dir: 'build/jacoco', include: '**/*.exec')
-      }
+  }
+
+  task jacocoOverallTestReport(type: JacocoReport) {
+    reports {
+      csv.enabled false
+      sourceSets project.sourceSets.main
+      html.destination "${buildDir}/jacocoOverallTestHtml"
+      executionData = fileTree(dir: 'build/jacoco', include: '**/*.exec')
     }
   }
 }
diff --git a/gradle/dependency-resolution.gradle b/gradle/dependency-resolution.gradle
index 3c6a843..52c4188 100644
--- a/gradle/dependency-resolution.gradle
+++ b/gradle/dependency-resolution.gradle
@@ -14,69 +14,68 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-subprojects {
-  // Task to dump all dependencies of all projects, in a way
-  // that can be diffed before and after dependency changes
-  task dumpDependencies() {
-    doLast {
-      description "Dump all of the dependencies as a flat, sorted list"
 
-      project.configurations.each{ configuration ->
-        println( project.name + ":" + configuration.name )
-        println( '-------------------')
-        configuration.resolvedConfiguration.resolvedArtifacts.collect{dep -> dep.file.name}.unique().toSorted().each{dep ->
-          println(dep)
-        }
-        println()
+// Task to dump all dependencies of all projects, in a way
+// that can be diffed before and after dependency changes
+task dumpDependencies() {
+  doLast {
+    description "Dump all of the dependencies as a flat, sorted list"
+
+    project.configurations.each { configuration ->
+      println(project.name + ":" + configuration.name)
+      println('-------------------')
+      configuration.resolvedConfiguration.resolvedArtifacts.collect { dep -> dep.file.name }.unique().toSorted().each { dep ->
+        println(dep)
       }
+      println()
     }
   }
+}
 
-  //Task to find all of the jars in a compile task
-  //that are unused
-  task findUsage() {
-    doLast {
-      description "Find usages of a jar in the source code"
+//Task to find all of the jars in a compile task
+//that are unused
+task findUsage() {
+  doLast {
+    description "Find usages of a jar in the source code"
 
-      String jarName = System.getProperty("jar.name")
-      if(jar == null || jar == "")  {
-        println "You must specify a jar name: ./gradlew findUsage -Djar.name=commons-io"
-        return
-      }
-      FileTree sourceFiles = compileJava.source
-      FileCollection jars = compileJava.classpath
+    String jarName = System.getProperty("jar.name")
+    if (jar == null || jar == "") {
+      println "You must specify a jar name: ./gradlew findUsage -Djar.name=commons-io"
+      return
+    }
+    FileTree sourceFiles = compileJava.source
+    FileCollection jars = compileJava.classpath
 
-      File jar = jars.find{file -> file.name.contains(jarName)}
+    File jar = jars.find { file -> file.name.contains(jarName) }
 
-      FileTree jarContents = zipTree(jar)
-      Set packages = new HashSet()
-      jarContents.visit{file ->
-        if(!file.isDirectory() && !file.path.contains("META-INF")) {
-          packages.add(file.relativePath.parent.toString().replace('/', '.'))
-        }
+    FileTree jarContents = zipTree(jar)
+    Set packages = new HashSet()
+    jarContents.visit { file ->
+      if (!file.isDirectory() && !file.path.contains("META-INF")) {
+        packages.add(file.relativePath.parent.toString().replace('/', '.'))
       }
+    }
 
-      println("Packages")
-      println "========"
-      packages.each { p -> println p  }
+    println("Packages")
+    println "========"
+    packages.each { p -> println p }
 
-      println ""
-      println("Matches")
-      println "========"
-      sourceFiles.visit{ file ->
-        if(!file.isDirectory()) {
-          boolean matches = false
-          file.file.eachLine { line ->
+    println ""
+    println("Matches")
+    println "========"
+    sourceFiles.visit { file ->
+      if (!file.isDirectory()) {
+        boolean matches = false
+        file.file.eachLine { line ->
           def matcher = line =~ /^import (.*)\..*;/
-            if(matcher) {
-              def pack = matcher[0][1]
-              matches |= packages.contains(pack)
-            }
+          if (matcher) {
+            def pack = matcher[0][1]
+            matches |= packages.contains(pack)
           }
+        }
 
-          if(matches) {
-            println file.relativePath
-          }
+        if (matches) {
+          println file.relativePath
         }
       }
     }
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
index 6da2426..6ae216c 100644
--- a/gradle/docker.gradle
+++ b/gradle/docker.gradle
@@ -38,14 +38,16 @@
  *                       The default is 'root'.
  */
 
+apply plugin: 'com.github.pedjak.dockerized-test'
+
 
 if (project.hasProperty('parallelDunit')) {
   def pwd = System.getenv('PWD')
   def geodeDir = new File(pwd).getCanonicalPath()
-  ext.dunitDockerVolumes = ["${geodeDir}":geodeDir]
+  project.ext.dunitDockerVolumes = ["${geodeDir}":geodeDir]
 }
 
-def dockerConfig = {
+project.ext.dockerConfig = {
   maxParallelForks = dunitParallelForks.toInteger()
 
   docker {
@@ -133,23 +135,21 @@ def dockerConfig = {
     }
   }
 }
-subprojects {
-  apply plugin: 'com.github.pedjak.dockerized-test'
 
-  if (project.hasProperty('parallelDunit')) {
-    uiTest.configure(dockerConfig)
-    repeatUnitTest.configure(dockerConfig)
 
-    integrationTest.configure(dockerConfig)
-    repeatIntegrationTest.configure(dockerConfig)
+if (project.hasProperty('parallelDunit')) {
+  uiTest.configure(project.ext.dockerConfig)
+  repeatUnitTest.configure(project.ext.dockerConfig)
+
+  integrationTest.configure(project.ext.dockerConfig)
+  repeatIntegrationTest.configure(project.ext.dockerConfig)
 
-    distributedTest.configure(dockerConfig)
-    repeatDistributedTest.configure(dockerConfig)
+  distributedTest.configure(project.ext.dockerConfig)
+  repeatDistributedTest.configure(project.ext.dockerConfig)
 
-    upgradeTest.configure(dockerConfig)
-    repeatUpgradeTest.configure(dockerConfig)
+  upgradeTest.configure(project.ext.dockerConfig)
+  repeatUpgradeTest.configure(project.ext.dockerConfig)
 
-    acceptanceTest.configure(dockerConfig)
-    repeatAcceptanceTest.configure(dockerConfig)
-  }
+  acceptanceTest.configure(project.ext.dockerConfig)
+  repeatAcceptanceTest.configure(project.ext.dockerConfig)
 }
diff --git a/gradle/ide.gradle b/gradle/ide.gradle
index 13e30d2..70a2be2 100644
--- a/gradle/ide.gradle
+++ b/gradle/ide.gradle
@@ -15,65 +15,61 @@
  * limitations under the License.
  */
 import org.gradle.plugins.ide.eclipse.model.Container
-allprojects {
-  apply plugin: 'idea'
-  apply plugin: 'eclipse'
-}
 
-subprojects {
-  eclipse {
-    classpath {
-      defaultOutputDir = file('build-eclipse')
-      downloadSources = true
-      file {
-        whenMerged { classpath ->
-            // Remove the gradle output directories from the eclipse classpath.
-            // Unfortunately, using minusConfigurations does not work here, because
-            // it removes the entire geode-core project.
-            classpath.entries.removeAll { entry ->
-              (entry.path.contains('geode-core/build') ||
-              entry.path.contains('geode-web/build') ||
-              entry.path.contains('geode-assembly/build') ||
-              entry.path.contains('geode-dependencies.jar')) &&
-              !entry.path.contains('generated-resources') &&
-              !entry.path.contains('generated-src')
-            }
+apply plugin: 'idea'
+apply plugin: 'eclipse'
 
-            //By default, gradle adds the java 1.8 *execution environment*, which has access restrictions on
-            //things like Unsafe. Change it to a direct dependency on the workspace JDK
-            classpath.entries = classpath.entries.collect { entry ->
-              entry.path.contains('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE') ?
-                      new Container('org.eclipse.jdt.launching.JRE_CONTAINER') :
-                      entry
-            }
+eclipse {
+  classpath {
+    defaultOutputDir = file('build-eclipse')
+    downloadSources = true
+    file {
+      whenMerged { classpath ->
+        // Remove the gradle output directories from the eclipse classpath.
+        // Unfortunately, using minusConfigurations does not work here, because
+        // it removes the entire geode-core project.
+        classpath.entries.removeAll { entry ->
+          (entry.path.contains('geode-core/build') ||
+            entry.path.contains('geode-web/build') ||
+            entry.path.contains('geode-assembly/build') ||
+            entry.path.contains('geode-dependencies.jar')) &&
+            !entry.path.contains('generated-resources') &&
+            !entry.path.contains('generated-src')
+        }
+
+        //By default, gradle adds the java 1.8 *execution environment*, which has access restrictions on
+        //things like Unsafe. Change it to a direct dependency on the workspace JDK
+        classpath.entries = classpath.entries.collect { entry ->
+          entry.path.contains('org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE') ?
+            new Container('org.eclipse.jdt.launching.JRE_CONTAINER') :
+            entry
         }
-      }
-    }
-    // Several files have UTF-8 encoding and Eclipse running on Windows
-    // will have trouble unless we tell it to use UTF-8 encoding.
-    // This setting needs to go into the core.resources.prefs file,
-    // which the JDT script isn't set up to configure
-    eclipseJdt {
-      doLast {
-        File f = file('.settings/org.eclipse.core.resources.prefs')
-        f.write('eclipse.preferences.version=1\n')
-        f.append('encoding/<project>=utf-8')
       }
     }
   }
-
-  cleanEclipse {
+  // Several files have UTF-8 encoding and Eclipse running on Windows
+  // will have trouble unless we tell it to use UTF-8 encoding.
+  // This setting needs to go into the core.resources.prefs file,
+  // which the JDT script isn't set up to configure
+  eclipseJdt {
     doLast {
-      delete '.settings/org.eclipse.core.resources.prefs'
+      File f = file('.settings/org.eclipse.core.resources.prefs')
+      f.write('eclipse.preferences.version=1\n')
+      f.append('encoding/<project>=utf-8')
     }
   }
+}
 
-  tasks.eclipse.dependsOn(cleanEclipse)
-
-  idea {
-    module {
-      downloadSources = true
-    }
+cleanEclipse {
+  doLast {
+    delete '.settings/org.eclipse.core.resources.prefs'
   }
 }
 
+tasks.eclipse.dependsOn(cleanEclipse)
+
+idea {
+  module {
+    downloadSources = true
+  }
+}
diff --git a/gradle/java.gradle b/gradle/java.gradle
index 1a7aea3..c3898a4 100644
--- a/gradle/java.gradle
+++ b/gradle/java.gradle
@@ -16,109 +16,101 @@
  */
 import org.apache.geode.gradle.plugins.DependencyConstraints
 
-allprojects {
-  // There exist peculiarities surrounding our handling of ClassLoaders and cross-module resources,
-  // causing test failures if we apply the newer 'java-library' plugin.
-  if (project.name.endsWith("geode-all-bom")) {
-    // This anti-pattern is a workaround -- java-platform must be applied before java or java-library
-    // to avoid conflicts over redefining certain configurations.
-    // A better solution, per GEODE-6383, would be to refactor this file's configuration to be
-    // "opt in", rather than having the root project inject this configuration into all projects.
-    apply plugin: 'java-platform'
-  }
-  apply plugin: 'java-library'
-
-  sourceCompatibility = 1.8
-  targetCompatibility = 1.8
-  compileJava.options.encoding = 'UTF-8'
+if (project.name.endsWith("geode-all-bom")) {
+  // This anti-pattern is a workaround -- java-platform must be applied before java or java-library
+  // to avoid conflicts over redefining certain configurations.
+  // Evaluation as to whether java-platform should be applied at all is left to GEODE-6611.
+  apply plugin: 'java-platform'
 }
+apply plugin: 'java-library'
 
-subprojects {
+sourceCompatibility = 1.8
+targetCompatibility = 1.8
+compileJava.options.encoding = 'UTF-8'
 
-  dependencies {
-    // log4j-core has an annotation processor that is passed on the compile-classpath via geode-core and others.
-    // Fix Gradle warning here until we clean up our own classpath
-    annotationProcessor 'org.apache.logging.log4j:log4j-core:' + DependencyConstraints.get('log4j.version')
-  }
+dependencies {
+  // log4j-core has an annotation processor that is passed on the compile-classpath via geode-core and others.
+  // Fix Gradle warning here until we clean up our own classpath
+  annotationProcessor 'org.apache.logging.log4j:log4j-core:' + DependencyConstraints.get('log4j.version')
+}
 
-  String javaVersion = System.properties['java.version']
-  if (javaVersion.startsWith("1.8.0") && javaVersion.split("-")[0].split("_")[1].toInteger() < 121) {
-    throw new GradleException("Java version 1.8.0_121 or later required, but was " + javaVersion)
-  }
+String javaVersion = System.properties['java.version']
+if (javaVersion.startsWith("1.8.0") && javaVersion.split("-")[0].split("_")[1].toInteger() < 121) {
+  throw new GradleException("Java version 1.8.0_121 or later required, but was " + javaVersion)
+}
 
-  // apply compiler options
-  gradle.taskGraph.whenReady({ graph ->
-    tasks.withType(JavaCompile).each { javac ->
-      javac.configure {
-        sourceCompatibility '1.8'
-        targetCompatibility '1.8'
-        options.encoding = 'UTF-8'
-      }
-      javac.options.incremental = true
-      javac.options.fork = true
-      javac.options.forkOptions.with({
-        memoryMaximumSize = "768m"
-      })
-      if (project.hasProperty('compileJVM') && !compileJVM.trim().isEmpty()) {
-        javac.options.forkOptions.executable = compileJVM + "/bin/javac"
-      }
+// apply compiler options
+gradle.taskGraph.whenReady({ graph ->
+  tasks.withType(JavaCompile).each { javac ->
+    javac.configure {
+      sourceCompatibility '1.8'
+      targetCompatibility '1.8'
+      options.encoding = 'UTF-8'
+    }
+    javac.options.incremental = true
+    javac.options.fork = true
+    javac.options.forkOptions.with({
+      memoryMaximumSize = "768m"
+    })
+    if (project.hasProperty('compileJVM') && !compileJVM.trim().isEmpty()) {
+      javac.options.forkOptions.executable = compileJVM + "/bin/javac"
     }
-  })
+  }
+})
 
-  // apply default manifest
-  gradle.taskGraph.whenReady({ graph ->
-    tasks.withType(Jar).each { jar ->
-      jar.doFirst {
-        manifest {
-          attributes(
+// apply default manifest
+gradle.taskGraph.whenReady({ graph ->
+  tasks.withType(Jar).each { jar ->
+    jar.doFirst {
+      manifest {
+        attributes(
             "Manifest-Version": "1.0",
             "Created-By": System.getProperty("user.name"),
             "Title": rootProject.name,
             "Version": version,
             "Organization": productOrg
-          )
-        }
-      }
-      jar.metaInf {
-        from("$rootDir/LICENSE")
-        if (jar.source.filter({ it.name.contains('NOTICE') }).empty) {
-          from("$rootDir/NOTICE")
-        }
+        )
       }
     }
-  })
-
-  configurations {
-    testOutput {
-      extendsFrom testCompile
-      description 'a dependency that exposes test artifacts'
+    jar.metaInf {
+      from("$rootDir/LICENSE")
+      if (jar.source.filter({ it.name.contains('NOTICE') }).empty) {
+        from("$rootDir/NOTICE")
+      }
     }
   }
+})
 
-  // This ensures that javadoc and source jars also have any prefix paths stripped and will
-  // be created as libs/foo-sources.jar instead of libs/extensions/foo-sources.jar for example.
-  tasks.all { task ->
-    if (task instanceof Jar) {
-      baseName = project.name
-    }
+configurations {
+  testOutput {
+    extendsFrom testCompile
+    description 'a dependency that exposes test artifacts'
   }
+}
 
-  task jarTest(type: Jar, dependsOn: testClasses) {
-    description 'Assembles a jar archive of test classes.'
-    from sourceSets.test.output
-    classifier 'test'
+// This ensures that javadoc and source jars also have any prefix paths stripped and will
+// be created as libs/foo-sources.jar instead of libs/extensions/foo-sources.jar for example.
+tasks.all { task ->
+  if (task instanceof Jar) {
+    baseName = project.name
   }
+}
 
-  artifacts {
-    testOutput jarTest
-  }
+task jarTest(type: Jar, dependsOn: testClasses) {
+  description 'Assembles a jar archive of test classes.'
+  from sourceSets.test.output
+  classifier 'test'
+}
 
-  javadoc {
-    destinationDir = file("$buildDir/javadoc")
-    options.addStringOption('Xdoclint:none', '-quiet')
-    options.encoding = 'UTF-8'
-    exclude "**/internal/**"
+artifacts {
+  testOutput jarTest
+}
 
-    classpath += configurations.compileOnly
-  }
+javadoc {
+  destinationDir = file("$buildDir/javadoc")
+  options.addStringOption('Xdoclint:none', '-quiet')
+  options.encoding = 'UTF-8'
+  exclude "**/internal/**"
+
+  classpath += configurations.compileOnly
 }
diff --git a/gradle/rat.gradle b/gradle/rat.gradle
index 29014cc..e7b8795 100644
--- a/gradle/rat.gradle
+++ b/gradle/rat.gradle
@@ -183,3 +183,5 @@ rat {
     'geode-core/src/main/java/org/apache/geode/admin/jmx/internal/MX4JModelMBean.java'
   ]
 }
+
+check.dependsOn rat
diff --git a/gradle/spotless.gradle b/gradle/spotless.gradle
index 9f5e5e8..0211d0d 100644
--- a/gradle/spotless.gradle
+++ b/gradle/spotless.gradle
@@ -15,140 +15,142 @@
  * limitations under the License.
  */
 
+
 // When a custom step changes, we need to bump the value passed to the method
 //   bumpThisNumberIfACustomStepChanges
-// This has been historicaly easy to forget, however, and can cause failures in some rare cases.
+// This has been historically easy to forget, however, and can cause failures in some rare cases.
 // To safeguard against this, we instead use the (partial) md5 of this file as that method input.
-def thisFile = file("${scriptDir}/spotless.gradle")
+def thisFile = file("${rootDir}/${scriptDir}/spotless.gradle")
 def thisFileMd5 = thisFile.text.md5() as String
 def thisFileMd5Piece = thisFileMd5.substring(0, 8)
 def thisFileIntegerHash = Integer.parseUnsignedInt(thisFileMd5Piece, 16)
 logger.debug("Using partial md5 (${thisFileIntegerHash}) of file ${thisFile} as spotless bump.")
 
-subprojects {
-  apply plugin: "com.diffplug.gradle.spotless"
-  spotless {
-    lineEndings = 'unix'
-    java {
-      target project.fileTree(project.projectDir) {
-        include '**/*.java'
-        exclude '**/generated-src/**'
-        exclude '**/build/**'
-      }
+project.ext.set("spotless-file-hash", thisFileIntegerHash)
 
-      // As the method name suggests, bump this number if any of the below "custom" rules change.
-      // Spotless will not run on unchanged files unless this number changes.
-      bumpThisNumberIfACustomStepChanges(thisFileIntegerHash)
 
-      removeUnusedImports()
+apply plugin: "com.diffplug.gradle.spotless"
+spotless {
+  lineEndings = 'unix'
+  java {
+    target project.fileTree(project.projectDir) {
+      include '**/*.java'
+      exclude '**/generated-src/**'
+      exclude '**/build/**'
+    }
 
-      custom 'Remove commented-out import statements', {
-        it.replaceAll(/\n\/\/ import .*?;.*/, '')
-      }
-      custom 'Refuse wildcard imports', {
-        // Wildcard imports can't be resolved by spotless itself.
-        // This will require the developer themselves to adhere to best practices.
-        if (it =~ /\nimport .*\*;/) {
-          throw new AssertionError("Do not use wildcard imports.  'spotlessApply' cannot resolve this issue.")
-        }
-      }
-      custom 'Refuse Awaitility import', {
-        if(it =~ /import\s+(static\s+)?org.awaitility.Awaitility.*/) {
-          throw new AssertionError("Do not use Awaitility.await(). Use GeodeAwaitility.await() instead. 'spotlessApply' cannot resolve this issue.")
-        }
-      }
-      importOrderFile "${project(':geode-core').projectDir}/../etc/eclipseOrganizeImports.importorder"
-
-      custom 'Remove unhelpful javadoc stubs', {
-        // e.g., remove the following lines:
-        // "* @param paramName"
-        // "* @throws ExceptionType"
-        // "* @return returnType"'
-        // Multiline to allow anchors on newlines
-        it.replaceAll(/(?m)^ *\* *@(?:param|throws|return) *\w* *\n/, '')
+    // As the method name suggests, bump this number if any of the below "custom" rules change.
+    // Spotless will not run on unchanged files unless this number changes.
+    bumpThisNumberIfACustomStepChanges(project.ext.'spotless-file-hash')
+
+    removeUnusedImports()
+
+    custom 'Remove commented-out import statements', {
+      it.replaceAll(/\n\/\/ import .*?;.*/, '')
+    }
+    custom 'Refuse wildcard imports', {
+      // Wildcard imports can't be resolved by spotless itself.
+      // This will require the developer themselves to adhere to best practices.
+      if (it =~ /\nimport .*\*;/) {
+        throw new AssertionError("Do not use wildcard imports.  'spotlessApply' cannot resolve this issue.")
       }
-      custom 'Remove any empty Javadocs and block comments', {
-        // Matches any /** [...] */ or /* [...] */ that contains:
-        // (a) only whitespace
-        // (b) trivial information, such as "@param paramName" or @throws ExceptionType
-        //     without any additional information.  This information is implicit in the signature.
-        it.replaceAll(/\/\*+\s*\n(\s*\*\s*\n)*\s*\*+\/\s*\n/, '')
+    }
+    custom 'Refuse Awaitility import', {
+      if (it =~ /import\s+(static\s+)?org.awaitility.Awaitility.*/) {
+        throw new AssertionError("Do not use Awaitility.await(). Use GeodeAwaitility.await() instead. 'spotlessApply' cannot resolve this issue.")
       }
+    }
+    importOrderFile "${project(':geode-core').projectDir}/../etc/eclipseOrganizeImports.importorder"
+
+    custom 'Remove unhelpful javadoc stubs', {
+      // e.g., remove the following lines:
+      // "* @param paramName"
+      // "* @throws ExceptionType"
+      // "* @return returnType"'
+      // Multiline to allow anchors on newlines
+      it.replaceAll(/(?m)^ *\* *@(?:param|throws|return) *\w* *\n/, '')
+    }
+    custom 'Remove any empty Javadocs and block comments', {
+      // Matches any /** [...] */ or /* [...] */ that contains:
+      // (a) only whitespace
+      // (b) trivial information, such as "@param paramName" or @throws ExceptionType
+      //     without any additional information.  This information is implicit in the signature.
+      it.replaceAll(/\/\*+\s*\n(\s*\*\s*\n)*\s*\*+\/\s*\n/, '')
+    }
 
-      // Enforce style modifier order
-      custom 'Modifier ordering', {
-        def modifierRanking = [
-                "public": 1,
-                "protected": 2,
-                "private": 3,
-                "abstract": 4,
-                "default": 5,
-                "static": 6,
-                "final": 7,
-                "transient": 8,
-                "volatile": 9,
-                "synchronized": 10,
-                "native": 11,
-                "strictfp": 12]
-        // Find any instance of multiple modifiers. Lead with a non-word character to avoid
-        // accidental matching against for instance, "an alternative default value"
-        it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
-          // Do not replace the leading non-word character.  Identify the modifiers
-          it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
-            // Sort the modifiers according to the ranking above
-            it.split().sort({ modifierRanking[it] }).join(' ') + ' '
-          }
-          )
+    // Enforce style modifier order
+    custom 'Modifier ordering', {
+      def modifierRanking = [
+          "public"      : 1,
+          "protected"   : 2,
+          "private"     : 3,
+          "abstract"    : 4,
+          "default"     : 5,
+          "static"      : 6,
+          "final"       : 7,
+          "transient"   : 8,
+          "volatile"    : 9,
+          "synchronized": 10,
+          "native"      : 11,
+          "strictfp"    : 12]
+      // Find any instance of multiple modifiers. Lead with a non-word character to avoid
+      // accidental matching against for instance, "an alternative default value"
+      it.replaceAll(/\W(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
+        // Do not replace the leading non-word character.  Identify the modifiers
+        it.replaceAll(/(?:public |protected |private |abstract |default |static |final |transient |volatile |synchronized |native |strictfp ){2,}/, {
+          // Sort the modifiers according to the ranking above
+          it.split().sort({ modifierRanking[it] }).join(' ') + ' '
         }
         )
       }
+      )
+    }
 
 
-      // Notes on eclipse formatter version:
-      // 4.6.3 is consistent with existing / previous behavior.
-      // 4.7.1 works, but had different default whitespace rules, notably with mid-ternary linebreak.
-      // 4.7.2 exists but is currently incompatible with our style file, raising NPEs.
-
-      // The format file is relative to geode-core and not the root project as the root project would change
-      // if Geode and submodules are included as part of a different gradle project.
-      eclipse('4.6.3').configFile "${project(':geode-core').projectDir}/../etc/eclipse-java-google-style.xml"
-      trimTrailingWhitespace()
-      endWithNewline()
-    }
+    // Notes on eclipse formatter version:
+    // 4.6.3 is consistent with existing / previous behavior.
+    // 4.7.1 works, but had different default whitespace rules, notably with mid-ternary linebreak.
+    // 4.7.2 exists but is currently incompatible with our style file, raising NPEs.
 
-    groovyGradle {
-      target project.fileTree(project.projectDir) {
-        include '**/*.gradle'
-        exclude '**/generated-src/**'
-        exclude '**/build/**'
-      }
+    // The format file is relative to geode-core and not the root project as the root project would change
+    // if Geode and submodules are included as part of a different gradle project.
+    eclipse('4.6.3').configFile "${project(':geode-core').projectDir}/../etc/eclipse-java-google-style.xml"
+    trimTrailingWhitespace()
+    endWithNewline()
+  }
 
-      // As the method name suggests, bump this number if any of the below "custom" rules change.
-      // Spotless will not run on unchanged files unless this number changes.
-      bumpThisNumberIfACustomStepChanges(thisFileIntegerHash)
+  groovyGradle {
+    target project.fileTree(project.projectDir) {
+      include '**/*.gradle'
+      exclude '**/generated-src/**'
+      exclude '**/build/**'
+    }
 
-      custom 'Use single-quote in project directives.', {
-        it.replaceAll(/project\(":([^"]*)"\)/, 'project(\':$1\')')
-      }
+    // As the method name suggests, bump this number if any of the below "custom" rules change.
+    // Spotless will not run on unchanged files unless this number changes.
+    bumpThisNumberIfACustomStepChanges(project.ext.'spotless-file-hash')
 
-      custom 'Use parenthesis in single-line gradle dependency declarations.', {
-        it.replaceAll(/\n(\s*\S*(?:[cC]ompile|[rR]untime)(?:Only)?) (?!\()([^{\n]*)\n/, { original, declaration, dep ->
-          "\n${declaration}(${dep})\n"
-        })
-      }
+    custom 'Use single-quote in project directives.', {
+      it.replaceAll(/project\(":([^"]*)"\)/, 'project(\':$1\')')
+    }
 
-      custom 'Do not pad spaces before parenthesis in gradle dependency declaration.', {
-        it.replaceAll(/\n(\s*\S*(?:[cC]ompile|[rR]untime)(?:Only)?) +\(/, '\n$1(')
-      }
+    custom 'Use parenthesis in single-line gradle dependency declarations.', {
+      it.replaceAll(/\n(\s*\S*(?:[cC]ompile|[rR]untime)(?:Only)?) (?!\()([^{\n]*)\n/, { original, declaration, dep ->
+        "\n${declaration}(${dep})\n"
+      })
+    }
 
-      indentWithSpaces(2)
+    custom 'Do not pad spaces before parenthesis in gradle dependency declaration.', {
+      it.replaceAll(/\n(\s*\S*(?:[cC]ompile|[rR]untime)(?:Only)?) +\(/, '\n$1(')
     }
-  }
 
-  // If we add more languages to Spotless, add them to 'compileXYZ' trigger below
-  afterEvaluate {
-    // Not all projects are java projects.  findByName could return null, so use the null-safe ?. operator
-    project.tasks.findByName('compileJava')?.mustRunAfter(spotlessCheck)
-    project.tasks.findByName('compileJava')?.mustRunAfter(spotlessApply)
+    indentWithSpaces(2)
   }
 }
+
+// If we add more languages to Spotless, add them to 'compileXYZ' trigger below
+afterEvaluate {
+  // Not all projects are java projects.  findByName could return null, so use the null-safe ?. operator
+  project.tasks.findByName('compileJava')?.mustRunAfter(spotlessCheck)
+  project.tasks.findByName('compileJava')?.mustRunAfter(spotlessApply)
+}
diff --git a/gradle/standard-subproject-configuration.gradle b/gradle/standard-subproject-configuration.gradle
new file mode 100644
index 0000000..c881609
--- /dev/null
+++ b/gradle/standard-subproject-configuration.gradle
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+apply from: "${rootDir}/${scriptDir}/java.gradle"
+apply from: "${rootDir}/${scriptDir}/dependency-resolution.gradle"
+apply from: "${rootDir}/${scriptDir}/test.gradle"
+apply from: "${rootDir}/${scriptDir}/code-analysis.gradle"
+apply from: "${rootDir}/${scriptDir}/docker.gradle"
+apply from: "${rootDir}/${scriptDir}/spotless.gradle"
+apply from: "${rootDir}/${scriptDir}/ide.gradle"
+apply plugin: 'com.github.ben-manes.versions'
+
+// Within the configure block, 'project' refers to the task-owning project, in this case rootProject
+def thisProjectScoped = project
+
+['clean', 'check', 'test'].each { taskName ->
+  rootProject.tasks.named(taskName).configure {
+    dependsOn thisProjectScoped.tasks.named(taskName)
+  }
+}
+
+
+
+rootProject.tasks.named('classes').configure {
+  // This is a semi-lazy hook so that our test sources are compiled most of the time.
+  dependsOn(
+    [
+      thisProjectScoped.tasks.named('compileTestJava'),
+      thisProjectScoped.tasks.named('compileIntegrationTestJava'),
+      thisProjectScoped.tasks.named('compileDistributedTestJava'),
+      thisProjectScoped.tasks.named('compileAcceptanceTestJava'),
+      thisProjectScoped.tasks.named('compileUiTestJava'),
+      thisProjectScoped.tasks.named('compilePerformanceTestJava'),
+      thisProjectScoped.tasks.named('compileUpgradeTestJava'),
+    ]
+  )
+}
+
+rootProject.tasks.named('devBuild').configure {
+  dependsOn thisProjectScoped.tasks.named('spotlessApply')
+}
diff --git a/gradle/test.gradle b/gradle/test.gradle
index 9398dbe..b88cbd1 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -19,270 +19,239 @@ import org.apache.geode.gradle.plugins.DependencyConstraints
  * limitations under the License.
  */
 
-task combineReports(type: TestReport) {
-  description 'Combines the test reports.'
-  destinationDir = file "${rootProject.buildDir}/reports/combined"
-
-  doLast {
-    println "All test reports at ${rootProject.buildDir}/reports/combined"
-  }
+// This configuration might be safely removed once the CategoryWithParameterizedRunnerFactory
+// and associated classes are themselves removed, per GEODE-5606
+configurations {
+  apt
 }
 
-gradle.taskGraph.whenReady({ graph ->
-  tasks.getByName('combineReports').reportOn rootProject.subprojects.collect {
-    it.tasks.withType(Test)
-  }.flatten()
-})
-
+compileTestJava {
+  options.annotationProcessorPath = files(configurations['apt'])
+}
 
-subprojects { thisSubProject ->
-  // This configuration might be safely removed once the CategoryWithParameterizedRunnerFactory
-  // and associated classes are themselves removed, per GEODE-5606
-  configurations {
-    apt
+test {
+  doFirst {
+    TestPropertiesWriter.writeTestProperties(buildDir, name)
   }
-
-  compileTestJava {
-    options.annotationProcessorPath = files(configurations['apt'])
+  if (project.hasProperty('testMaxParallelForks')) {
+    maxParallelForks = Integer.parseUnsignedInt(project.testMaxParallelForks)
+  } else {
+    maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
   }
+}
 
-  test {
-    doFirst {
-      TestPropertiesWriter.writeTestProperties(buildDir, name)
-    }
-    if (thisSubProject.hasProperty('testMaxParallelForks')) {
-      maxParallelForks = Integer.parseUnsignedInt(thisSubProject.testMaxParallelForks)
-    } else {
-      maxParallelForks = Runtime.runtime.availableProcessors().intdiv(2) ?: 1
-    }
+apply plugin: 'nebula.facet'
+facets {
+  integrationTest {
+    testTaskName = 'integrationTest'
+    includeInCheckLifecycle = false
   }
-
-  apply plugin: 'nebula.facet'
-  facets {
-    integrationTest {
-      testTaskName = 'integrationTest'
-      includeInCheckLifecycle = false
-    }
-    distributedTest {
-      testTaskName = 'distributedTest'
-      includeInCheckLifecycle = false
-    }
-    performanceTest {
-      testTaskName = 'performanceTest'
-      includeInCheckLifecycle = false
-    }
-    acceptanceTest {
-      testTaskName = 'acceptanceTest'
-      includeInCheckLifecycle = false
-    }
-    uiTest {
-      testTaskName = 'uiTest'
-      includeInCheckLifecycle = false
-    }
-    upgradeTest {
-      testTaskName = 'upgradeTest'
-      includeInCheckLifecycle = false
-    }
+  distributedTest {
+    testTaskName = 'distributedTest'
+    includeInCheckLifecycle = false
   }
-
-  configurations {
-    testAnnotationProcessor.extendsFrom annotationProcessor
-    integrationTestAnnotationProcessor.extendsFrom annotationProcessor
-    distributedTestAnnotationProcessor.extendsFrom annotationProcessor
-    performanceTestAnnotationProcessor.extendsFrom annotationProcessor
-    acceptanceTestAnnotationProcessor.extendsFrom annotationProcessor
-    uiTestAnnotationProcessor.extendsFrom annotationProcessor
-    upgradeTestAnnotationProcessor.extendsFrom annotationProcessor
-    // Facets does not extend the new runtimeOnly configurations
-    integrationTestRuntimeOnly.extendsFrom(runtimeOnly)
-    distributedTestRuntimeOnly.extendsFrom(runtimeOnly)
-    performanceTestRuntimeOnly.extendsFrom(runtimeOnly)
-    acceptanceTestRuntimeOnly.extendsFrom(runtimeOnly)
-    uiTestRuntimeOnly.extendsFrom(runtimeOnly)
-    upgradeTestRuntimeOnly.extendsFrom(runtimeOnly)
+  performanceTest {
+    testTaskName = 'performanceTest'
+    includeInCheckLifecycle = false
   }
+  acceptanceTest {
+    testTaskName = 'acceptanceTest'
+    includeInCheckLifecycle = false
+  }
+  uiTest {
+    testTaskName = 'uiTest'
+    includeInCheckLifecycle = false
+  }
+  upgradeTest {
+    testTaskName = 'upgradeTest'
+    includeInCheckLifecycle = false
+  }
+}
 
-  dependencies {
-    // Do not add dependencies here that are not part of a custom configuration.
-    // Dependencies should be explicit in the relevant build.gradle files to keep our modules
-    //  as decoupled as possible.
+configurations {
+  testAnnotationProcessor.extendsFrom annotationProcessor
+  integrationTestAnnotationProcessor.extendsFrom annotationProcessor
+  distributedTestAnnotationProcessor.extendsFrom annotationProcessor
+  performanceTestAnnotationProcessor.extendsFrom annotationProcessor
+  acceptanceTestAnnotationProcessor.extendsFrom annotationProcessor
+  uiTestAnnotationProcessor.extendsFrom annotationProcessor
+  upgradeTestAnnotationProcessor.extendsFrom annotationProcessor
+  // Facets does not extend the new runtimeOnly configurations
+  integrationTestRuntimeOnly.extendsFrom(runtimeOnly)
+  distributedTestRuntimeOnly.extendsFrom(runtimeOnly)
+  performanceTestRuntimeOnly.extendsFrom(runtimeOnly)
+  acceptanceTestRuntimeOnly.extendsFrom(runtimeOnly)
+  uiTestRuntimeOnly.extendsFrom(runtimeOnly)
+  upgradeTestRuntimeOnly.extendsFrom(runtimeOnly)
+}
 
-    // This 'apt' configuration to be removed by GEODE-5606.
-    apt files("${rootProject.projectDir}/buildSrc/build/libs/buildSrc.jar")
-    apt('junit:junit:' + DependencyConstraints.get('junit.version')) {
-      transitive = false
-    }
+dependencies {
+  // Do not add dependencies here that are not part of a custom configuration.
+  // Dependencies should be explicit in the relevant build.gradle files to keep our modules
+  //  as decoupled as possible.
 
-    testRuntime('cglib:cglib:' + DependencyConstraints.get('cglib.version')) {
-      exclude module: 'org.apache.ant'
-    }
+  // This 'apt' configuration to be removed by GEODE-5606.
+  apt files("${rootProject.projectDir}/buildSrc/build/libs/buildSrc.jar")
+  apt('junit:junit:' + DependencyConstraints.get('junit.version')) {
+    transitive = false
   }
 
-  configure([integrationTest, distributedTest, performanceTest, acceptanceTest, uiTest,
-             upgradeTest]) {
-    forkEvery 1
-
-    doFirst {
-      TestPropertiesWriter.writeTestProperties(buildDir, name)
-    }
-    outputs.upToDateWhen { false }
+  testRuntime('cglib:cglib:' + DependencyConstraints.get('cglib.version')) {
+    exclude module: 'org.apache.ant'
   }
+}
 
-  configure([integrationTest, distributedTest, performanceTest]) {
-    useJUnit {
-      if (thisSubProject.hasProperty("testCategory")) {
-        includeCategories += thisSubProject.testCategory
-      }
-    }
+configure([integrationTest, distributedTest, performanceTest, acceptanceTest, uiTest,
+           upgradeTest]) {
+  forkEvery 1
+
+  doFirst {
+    TestPropertiesWriter.writeTestProperties(buildDir, name)
   }
+  outputs.upToDateWhen { false }
+}
 
-  if (thisSubProject.hasProperty("forceTest")) {
-    // All test facets already force rerun.  Only :test can be upToDate.
-    test {
-      outputs.upToDateWhen { false }
+configure([integrationTest, distributedTest, performanceTest]) {
+  useJUnit {
+    if (project.hasProperty("testCategory")) {
+      includeCategories += project.testCategory
     }
   }
+}
 
-  task repeatDistributedTest(type: RepeatTest) {
-    dependsOn { distributedTest.taskDependencies }
-    classpath = thisSubProject.sourceSets.distributedTest.runtimeClasspath
-    testClassesDirs = thisSubProject.sourceSets.distributedTest.output.classesDirs
+if (project.hasProperty("forceTest")) {
+  // All test facets already force rerun.  Only :test can be upToDate.
+  test {
+    outputs.upToDateWhen { false }
   }
+}
 
-  task repeatIntegrationTest(type: RepeatTest) {
-    dependsOn { integrationTest.taskDependencies }
-    classpath = thisSubProject.sourceSets.integrationTest.runtimeClasspath
-    testClassesDirs = thisSubProject.sourceSets.integrationTest.output.classesDirs
-  }
+task repeatDistributedTest(type: RepeatTest) {
+  dependsOn { distributedTest.taskDependencies }
+  classpath = project.sourceSets.distributedTest.runtimeClasspath
+  testClassesDirs = project.sourceSets.distributedTest.output.classesDirs
+}
 
-  task repeatAcceptanceTest(type: RepeatTest) {
-    dependsOn { acceptanceTest.taskDependencies }
-    classpath = thisSubProject.sourceSets.acceptanceTest.runtimeClasspath
-    testClassesDirs = thisSubProject.sourceSets.acceptanceTest.output.classesDirs
-  }
+task repeatIntegrationTest(type: RepeatTest) {
+  dependsOn { integrationTest.taskDependencies }
+  classpath = project.sourceSets.integrationTest.runtimeClasspath
+  testClassesDirs = project.sourceSets.integrationTest.output.classesDirs
+}
 
-  task repeatUpgradeTest(type: RepeatTest) {
-    dependsOn { upgradeTest.taskDependencies }
-    classpath = thisSubProject.sourceSets.upgradeTest.runtimeClasspath
-    testClassesDirs = thisSubProject.sourceSets.upgradeTest.output.classesDirs
-  }
+task repeatAcceptanceTest(type: RepeatTest) {
+  dependsOn { acceptanceTest.taskDependencies }
+  classpath = project.sourceSets.acceptanceTest.runtimeClasspath
+  testClassesDirs = project.sourceSets.acceptanceTest.output.classesDirs
+}
 
-  task repeatUnitTest(type: RepeatTest) {
-    dependsOn { test.taskDependencies }
-    // default classpath works for this one.
+task repeatUpgradeTest(type: RepeatTest) {
+  dependsOn { upgradeTest.taskDependencies }
+  classpath = project.sourceSets.upgradeTest.runtimeClasspath
+  testClassesDirs = project.sourceSets.upgradeTest.output.classesDirs
+}
+
+task repeatUnitTest(type: RepeatTest) {
+  dependsOn { test.taskDependencies }
+  // default classpath works for this one.
+}
+
+configure([integrationTest, distributedTest, performanceTest, acceptanceTest, uiTest, upgradeTest]) {
+  if (project.hasProperty('excludeTest')) {
+    exclude project.getProperty('excludeTest').split(',')
   }
+}
+
+configure([repeatDistributedTest, repeatIntegrationTest, repeatUpgradeTest, repeatUnitTest, repeatAcceptanceTest]) {
+  times = Integer.parseInt(repeat)
+  useJUnit {}
+  outputs.upToDateWhen { false }
 
-  configure([integrationTest, distributedTest, performanceTest, acceptanceTest, uiTest, upgradeTest]) {
-    if (thisSubProject.hasProperty('excludeTest')) {
-      exclude thisSubProject.getProperty('excludeTest').split(',')
+  if (project.hasProperty("failOnNoMatchingTests")) {
+    filter {
+      setFailOnNoMatchingTests(Boolean.valueOf(project.failOnNoMatchingTests))
     }
   }
+}
 
-  configure([repeatDistributedTest, repeatIntegrationTest, repeatUpgradeTest, repeatUnitTest, repeatAcceptanceTest]) {
-    times = Integer.parseInt(repeat)
-    useJUnit {}
-    outputs.upToDateWhen { false }
+// apply common test configuration
+gradle.taskGraph.whenReady({ graph ->
+  tasks.withType(Test).each { test ->
+    check.dependsOn test
+    test.configure {
+      onlyIf { !Boolean.getBoolean('skip.tests') }
+
+      def resultsDir = TestPropertiesWriter.testResultsDir(buildDir, test.name)
+      test.workingDir = resultsDir
 
-    if (thisSubProject.hasProperty("failOnNoMatchingTests")) {
-      filter {
-        setFailOnNoMatchingTests(Boolean.valueOf(thisSubProject.failOnNoMatchingTests))
+      reports.html.destination = file "$buildDir/reports/$name"
+      testLogging {
+        exceptionFormat = 'full'
       }
-    }
-  }
 
-  // apply common test configuration
-  gradle.taskGraph.whenReady({ graph ->
-    tasks.withType(Test).each { test ->
-      check.dependsOn test
-      test.configure {
-        onlyIf { !Boolean.getBoolean('skip.tests') }
-
-        def resultsDir = TestPropertiesWriter.testResultsDir(buildDir, test.name)
-        test.workingDir = resultsDir
-
-        reports.html.destination = file "$buildDir/reports/$name"
-        testLogging {
-          exceptionFormat = 'full'
-        }
-
-        maxHeapSize '768m'
-        jvmArgs = ['-XX:+HeapDumpOnOutOfMemoryError', '-ea']
-        if (thisSubProject.hasProperty('testJVMVer') && testJVMVer.toInteger() >= 9) {
-          jvmArgs += ["--add-opens", "java.xml/jdk.xml.internal=ALL-UNNAMED"]
-          jvmArgs += ["--add-opens", "java.base/jdk.internal.module=ALL-UNNAMED"]
-          jvmArgs += ["--add-opens", "java.base/java.lang.module=ALL-UNNAMED"]
-        }
-        if (thisSubProject.hasProperty('testJVM') && !testJVM.trim().isEmpty()) {
-          executable = "${testJVM}/bin/java"
-        }
-
-        systemProperty 'gemfire.DEFAULT_MAX_OPLOG_SIZE', '10'
-        systemProperty 'gemfire.disallowMcastDefaults', 'true'
-        systemProperty 'jline.terminal', 'jline.UnsupportedTerminal'
-        def logLevel = System.getProperty('log-level')
-        if (logLevel != null) {
-          systemProperty 'log-level', logLevel
-        }
-        def log4jLocation = System.getProperty('log4j.configurationFile')
-        if (log4jLocation != null) {
-          systemProperty 'log4j.configurationFile', log4jLocation
-        }
-
-        // The distributed tests seem to need to use /tmp directly,
-        // so exclude them from using the supplied temp directory.
-        if (!test.name.contains("distributed")) {
-          systemProperty 'java.io.tmpdir', System.getProperty('java.io.tmpdir')
-        }
-
-        def eol = System.getProperty('line.separator')
-        def progress = new File(resultsDir, "$test.name-progress.txt")
-        beforeTest { desc ->
-          def now = new Date().format('yyyy-MM-dd HH:mm:ss.SSS Z')
-          progress << "$now Starting test $desc.className $desc.name$eol"
-        }
-        afterTest { desc, result ->
-          def now = new Date().format('yyyy-MM-dd HH:mm:ss.SSS Z')
-          progress << "$now Completed test $desc.className $desc.name with result: ${result.resultType}$eol"
-        }
-
-        doFirst {
-          resultsDir.deleteDir()
-          resultsDir.mkdirs()
-        }
+      maxHeapSize '768m'
+      jvmArgs = ['-XX:+HeapDumpOnOutOfMemoryError', '-ea']
+      if (project.hasProperty('testJVMVer') && testJVMVer.toInteger() >= 9) {
+        jvmArgs += ["--add-opens", "java.xml/jdk.xml.internal=ALL-UNNAMED"]
+        jvmArgs += ["--add-opens", "java.base/jdk.internal.module=ALL-UNNAMED"]
+        jvmArgs += ["--add-opens", "java.base/java.lang.module=ALL-UNNAMED"]
+      }
+      if (project.hasProperty('testJVM') && !testJVM.trim().isEmpty()) {
+        executable = "${testJVM}/bin/java"
       }
-    }
-  })
 
-  acceptanceTest {
-    // Acceptance tests may reach out and run a gfsh command from the assembled gfsh.
-    // If the test JVM version is specified, we must have the correct JAVA_HOME set for gfsh to use.
-    // See also environment configuration for parallel testing in docker.gradle
-    if (thisSubProject.hasProperty('testJVM') && !testJVM.trim().isEmpty()) {
-      environment "JAVA_HOME", "${thisSubProject.testJVM}"
-    }
-  }
+      systemProperty 'gemfire.DEFAULT_MAX_OPLOG_SIZE', '10'
+      systemProperty 'gemfire.disallowMcastDefaults', 'true'
+      systemProperty 'jline.terminal', 'jline.UnsupportedTerminal'
+      def logLevel = System.getProperty('log-level')
+      if (logLevel != null) {
+        systemProperty 'log-level', logLevel
+      }
+      def log4jLocation = System.getProperty('log4j.configurationFile')
+      if (log4jLocation != null) {
+        systemProperty 'log4j.configurationFile', log4jLocation
+      }
 
+      // The distributed tests seem to need to use /tmp directly,
+      // so exclude them from using the supplied temp directory.
+      if (!test.name.contains("distributed")) {
+        systemProperty 'java.io.tmpdir', System.getProperty('java.io.tmpdir')
+      }
 
-  // Make precheckin task run all validation tests for checking in code.
-  task precheckin(dependsOn: [build, acceptanceTest, integrationTest, distributedTest, upgradeTest]) {
-    description 'Run this task before checking in code to validate changes. It runs tests beyond unitTest'
-  }
+      def eol = System.getProperty('line.separator')
+      def progress = new File(resultsDir, "$test.name-progress.txt")
+      beforeTest { desc ->
+        def now = new Date().format('yyyy-MM-dd HH:mm:ss.SSS Z')
+        progress << "$now Starting test $desc.className $desc.name$eol"
+      }
+      afterTest { desc, result ->
+        def now = new Date().format('yyyy-MM-dd HH:mm:ss.SSS Z')
+        progress << "$now Completed test $desc.className $desc.name with result: ${result.resultType}$eol"
+      }
 
-  tasks.withType(Test).plus([build, check]).each {
-    it.finalizedBy combineReports
-    combineReports.mustRunAfter it
+      doFirst {
+        resultsDir.deleteDir()
+        resultsDir.mkdirs()
+      }
+    }
   }
+})
 
-  rootProject.tasks.named('classes').configure {
-    // This is a semi-lazy hook so that the target "assemble" also assembles our test sources.
-    dependsOn([
-      thisSubProject.tasks.named('compileTestJava'),
-      thisSubProject.tasks.named('compileIntegrationTestJava'),
-      thisSubProject.tasks.named('compileDistributedTestJava'),
-      thisSubProject.tasks.named('compileAcceptanceTestJava'),
-      thisSubProject.tasks.named('compileUiTestJava'),
-      thisSubProject.tasks.named('compilePerformanceTestJava'),
-      thisSubProject.tasks.named('compileUpgradeTestJava'),
-    ])
+acceptanceTest {
+  // Acceptance tests may reach out and run a gfsh command from the assembled gfsh.
+  // If the test JVM version is specified, we must have the correct JAVA_HOME set for gfsh to use.
+  // See also environment configuration for parallel testing in docker.gradle
+  if (project.hasProperty('testJVM') && !testJVM.trim().isEmpty()) {
+    environment "JAVA_HOME", "${project.testJVM}"
   }
 }
+
+
+// Make precheckin task run all validation tests for checking in code.
+task precheckin(dependsOn: [build, acceptanceTest, integrationTest, distributedTest, upgradeTest]) {
+  description 'Run this task before checking in code to validate changes. It runs tests beyond unitTest'
+}
+
+tasks.withType(Test).plus([build, check]).each {
+  it.finalizedBy rootProject.tasks.combineReports
+  rootProject.tasks.combineReports.mustRunAfter it
+}
diff --git a/boms/build.gradle b/static-analysis/build.gradle
similarity index 91%
copy from boms/build.gradle
copy to static-analysis/build.gradle
index 8f5c586..9259044 100644
--- a/boms/build.gradle
+++ b/static-analysis/build.gradle
@@ -15,5 +15,4 @@
  * limitations under the License.
  */
 
-jar.enabled = false
-
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
diff --git a/static-analysis/pmd-rules/build.gradle b/static-analysis/pmd-rules/build.gradle
index 220121c..850a012 100644
--- a/static-analysis/pmd-rules/build.gradle
+++ b/static-analysis/pmd-rules/build.gradle
@@ -14,6 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+apply from: "${rootDir}/${scriptDir}/standard-subproject-configuration.gradle"
+
 dependencies {
     testCompile(group: 'net.sourceforge.pmd', name: 'pmd-test', version: '6.11.0')
     compile(group: 'net.sourceforge.pmd', name: 'pmd-java', version: '6.11.0')