/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the "Elastic License * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side * Public License v 1"; you may not use this file except in compliance with, at * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ import com.avast.gradle.dockercompose.tasks.ComposePull import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import org.elasticsearch.gradle.DistributionDownloadPlugin import org.elasticsearch.gradle.Version import org.elasticsearch.gradle.VersionProperties import org.elasticsearch.gradle.internal.ResolveAllDependencies import org.elasticsearch.gradle.internal.checks.ValidateBuildGradleScriptsTask import org.elasticsearch.gradle.util.GradleUtils import groovy.xml.XmlParser; import groovy.xml.XmlNodePrinter; import java.nio.file.Files import static java.nio.file.StandardCopyOption.REPLACE_EXISTING import static org.elasticsearch.gradle.util.GradleUtils.maybeConfigure buildscript { repositories { mavenCentral() } } plugins { id 'lifecycle-base' id 'elasticsearch.docker-support' id 'elasticsearch.internal-distribution-download' id 'elasticsearch.jdk-download' id 'elasticsearch.global-build-info' id 'elasticsearch.build-complete' id 'elasticsearch.build-scan' id 'elasticsearch.runtime-jdk-provision' id 'elasticsearch.ide' id 'elasticsearch.forbidden-dependencies' id 'elasticsearch.local-distribution' id 'elasticsearch.fips' id 'elasticsearch.internal-testclusters' id 'elasticsearch.run' id 'elasticsearch.run-ccs' id 'elasticsearch.repositories' id 'elasticsearch.release-tools' id 'elasticsearch.versions' id 'elasticsearch.internal-flakiness-resolve' id 'com.gradleup.nmcp.aggregation' id 'elasticsearch.dra-maven-aggregation' } version = VersionProperties.elasticsearch /** * Here we package and aggregation zip file containing all maven artifacts we want to * publish to maven central. * The aggregation is done by picking all projects that have the elasticsearch.publish plugin applied, * indicating the artifact is meant for beeing published to maven central. * */ nmcpAggregation { // nmcp 1.6.x strips the non-required `.sha256` checksums by default. Keep publishing them // for now so the aggregation layout matches what we produced with nmcp 0.1.x. publishAllChecksums = true // Elasticsearch has multiple subprojects that share the same (leaf) name. nmcp 1.4.3+ rejects // this by default because it can confuse aggregation dependency resolution; none of the duplicates // contribute publications, so opt out of the check. allowDuplicateProjectNames = true } def nmcpConsumerConfiguration = configurations.named('nmcpAggregation') allprojects { publishedProject -> publishedProject.pluginManager.withPlugin('maven-publish') { rootProject.dependencies.add(nmcpConsumerConfiguration.name, rootProject.dependencies.project(path: publishedProject.path)) } } tasks.named('nmcpZipAggregation').configure { // put this in a place that works well with our DRA infrastructure archiveFileName.unset(); archiveBaseName.set("elasticsearch-maven-aggregation") archiveVersion.set(VersionProperties.elasticsearch) destinationDirectory.set(layout.buildDirectory.dir("distributions")); dependsOn gradle.includedBuild('build-tools').task(':nmcpZipAllPublications') from(zipTree("build-tools/build/nmcp/zip/allPublications.zip")) } /** * This is a convenient method for declaring test artifact dependencies provided by the internal * test artifact plugin. It replaces basically the longer dependency notation with explicit capability * declaration like this: * * testImplementation(project(xpackModule('repositories-metering-api'))) { * capabilities { * requireCapability("org.elasticsearch.gradle:repositories-metering-api-test-artifacts") * } * } * * */ class StepExpansion { String templatePath List versions String variable } class ListExpansion { List versions String variable } // Filters out intermediate patch releases to reduce the load of CI testing def filterIntermediatePatches = { List versions -> versions.groupBy { "${it.major}.${it.minor}" }.values().collect { it.max() } } tasks.register("updateCIBwcVersions") { def writeVersions = { File file, List versions -> file.text = "" file << "BWC_VERSION:\n" versions.each { file << " - \"$it\"\n" } } def writeBuildkitePipeline = { String outputFilePath, String pipelineTemplatePath, List listExpansions, List stepExpansions = [] -> def outputFile = file(outputFilePath) def pipelineTemplate = file(pipelineTemplatePath) def pipeline = pipelineTemplate.text listExpansions.each { expansion -> def listString = "[" + expansion.versions.collect { "\"${it}\"" }.join(", ") + "]" pipeline = pipeline.replaceAll('\\$' + expansion.variable, listString) } stepExpansions.each { expansion -> def steps = "" expansion.versions.each { steps += "\n" + file(expansion.templatePath).text.replaceAll('\\$BWC_VERSION', it.toString()) } pipeline = pipeline.replaceAll(' *\\$' + expansion.variable, steps) } outputFile.text = "# This file is auto-generated. See ${pipelineTemplatePath}\n" + pipeline } // Writes a Buildkite pipelime from a template, and replaces a variable with an array of versions // Useful for writing a list of versions in a matrix configuration def expandList = { String outputFilePath, String pipelineTemplatePath, String variable, List versions -> writeBuildkitePipeline(outputFilePath, pipelineTemplatePath, [new ListExpansion(versions: versions, variable: variable)]) } // Writes a Buildkite pipeline from a template, and replaces $BWC_STEPS with a list of steps, one for each version // Useful when you need to configure more versions than are allowed in a matrix configuration def expandBwcSteps = { String outputFilePath, String pipelineTemplatePath, String stepTemplatePath, List versions -> writeBuildkitePipeline( outputFilePath, pipelineTemplatePath, [], [new StepExpansion(templatePath: stepTemplatePath, versions: versions, variable: "BWC_STEPS")] ) } doLast { writeVersions(file(".ci/bwcVersions"), filterIntermediatePatches(buildParams.bwcVersions.indexCompatible)) writeVersions(file(".ci/snapshotBwcVersions"), filterIntermediatePatches(buildParams.bwcVersions.unreleasedIndexCompatible)) expandList( ".buildkite/pipelines/intake.yml", ".buildkite/pipelines/intake.template.yml", "BWC_LIST", filterIntermediatePatches(buildParams.bwcVersions.unreleasedIndexCompatible) ) expandList( ".buildkite/pipelines/periodic-fwc.yml", ".buildkite/pipelines/periodic-fwc.template.yml", "FWC_LIST", buildParams.bwcVersions.released.findAll { it.major == VersionProperties.elasticsearchVersion.major && it.minor == VersionProperties.elasticsearchVersion.minor } ) writeBuildkitePipeline( ".buildkite/pipelines/periodic.yml", ".buildkite/pipelines/periodic.template.yml", [ new ListExpansion(versions: filterIntermediatePatches(buildParams.bwcVersions.unreleasedIndexCompatible), variable: "BWC_LIST"), ], [ new StepExpansion( templatePath: ".buildkite/pipelines/periodic.bwc.template.yml", versions: filterIntermediatePatches(buildParams.bwcVersions.indexCompatible), variable: "BWC_STEPS" ), ] ) writeBuildkitePipeline( ".buildkite/pipelines/periodic-java-ea.yml", ".buildkite/pipelines/periodic-java-ea.template.yml", [ new ListExpansion(versions: filterIntermediatePatches(buildParams.bwcVersions.unreleasedIndexCompatible), variable: "BWC_LIST"), ], [ new StepExpansion( templatePath: ".buildkite/pipelines/periodic-java-ea.bwc.template.yml", versions: filterIntermediatePatches(buildParams.bwcVersions.indexCompatible), variable: "BWC_STEPS" ), ] ) expandBwcSteps( ".buildkite/pipelines/periodic-packaging.yml", ".buildkite/pipelines/periodic-packaging.template.yml", ".buildkite/pipelines/periodic-packaging.bwc.template.yml", filterIntermediatePatches(buildParams.bwcVersions.indexCompatible) ) } } tasks.register("verifyVersions") { def verifyCiYaml = { File file, List versions -> String ciYml = file.text versions.each { if (ciYml.contains("\"$it\"\n") == false) { throw new Exception("${file} is outdated, run `./gradlew updateCIBwcVersions` and check in the results") } } } doLast { if (gradle.startParameter.isOffline()) { throw new GradleException("Must run in online mode to verify versions") } // Read the list from maven central. // Fetch the metadata and parse the xml into Version instances because it's more straight forward here // rather than bwcVersion ( VersionCollection ). new URL('https://repo1.maven.org/maven2/org/elasticsearch/elasticsearch/maven-metadata.xml').openStream().withStream { s -> buildParams.bwcVersions.compareToAuthoritative( new XmlParser().parse(s) .versioning.versions.version .collect { it.text() }.findAll { it ==~ /\d+\.\d+\.\d+/ } .collect { Version.fromString(it) } ) } verifyCiYaml(file(".ci/bwcVersions"), filterIntermediatePatches(buildParams.bwcVersions.indexCompatible)) verifyCiYaml(file(".ci/snapshotBwcVersions"), buildParams.bwcVersions.unreleasedIndexCompatible) // Make sure backport bot config file is up to date JsonNode backportConfig = new ObjectMapper().readTree(file(".backportrc.json")) buildParams.bwcVersions.forPreviousUnreleased { unreleasedVersion -> boolean valid = backportConfig.get("targetBranchChoices").elements().any { branchChoice -> if (branchChoice.isObject()) { return branchChoice.get("name").textValue() == unreleasedVersion.branch } else { return branchChoice.textValue() == unreleasedVersion.branch } } if (valid == false) { throw new GradleException("No branch choice exists for development branch ${unreleasedVersion.branch} in .backportrc.json.") } } String versionMapping = backportConfig.get("branchLabelMapping").fields().find { it.value.textValue() == 'main' }.key String expectedMapping = "^v${versions.elasticsearch.replaceAll('-SNAPSHOT', '')}\$" if (versionMapping != expectedMapping) { throw new GradleException( "Backport label mapping for branch 'main' is '${versionMapping}' but should be " + "'${expectedMapping}'. Update .backportrc.json." ) } } } def generateUpgradeCompatibilityFile = tasks.register("generateUpgradeCompatibilityFile") { def outputFile = project.layout.buildDirectory.file("rolling-upgrade-compatible-${VersionProperties.elasticsearch}.json") def rollingUpgradeCompatibleVersions = buildParams.bwcVersions.wireCompatible - VersionProperties.elasticsearchVersion inputs.property("rollingUpgradeCompatibleVersions", rollingUpgradeCompatibleVersions) outputs.file(outputFile) doLast { def versionsString = rollingUpgradeCompatibleVersions.collect { "\"${it.toString()}\"" }.join(', ') outputFile.get().asFile.write("""{"rolling_upgrade_compatible_versions" : [${versionsString}]}""") } } def upgradeCompatibilityZip = tasks.register("upgradeCompatibilityZip", Zip) { archiveFile.set(project.layout.buildDirectory.file("distributions/rolling-upgrade-compatible-${VersionProperties.elasticsearch}.zip")) from(generateUpgradeCompatibilityFile) } def isCiSplitTask = { String taskName -> taskName.startsWith("checkPart") || taskName.startsWith("releaseTestCheck") || taskName == 'functionalTests' || taskName == 'checkBuildLogic' } // TODO: This flag existed as a mechanism to disable bwc tests during a backport. It is no // longer used for that purpose, but instead a way to run only functional tests. We should // rework the functionalTests task to be more explicit about which tasks it wants to run // so that that this flag is no longer needed. boolean bwc_tests_enabled = true if (project.gradle.startParameter.taskNames.any(isCiSplitTask)) { // Disable BWC tests for split CI tasks and platform support tests as it's expected that this will run on its own check. bwc_tests_enabled = false } allprojects { // We disable this plugin for now till we shaked out the issues we see // e.g. see https://github.com/elastic/elasticsearch/issues/72169 // apply plugin:'elasticsearch.internal-test-rerun' ext.bwc_tests_enabled = bwc_tests_enabled tasks.register('resolveAllDependencies', ResolveAllDependencies) { def ignoredPrefixes = [DistributionDownloadPlugin.ES_DISTRO_CONFIG_PREFIX, "jdbcDriver"] configs = project.configurations.matching { config -> ignoredPrefixes.any { config.name.startsWith(it) } == false } if (project.path == ':') { resolveJavaToolChain = true } project.pluginManager.withPlugin('elasticsearch.mrjar') { // ensure we implicitly resolve all jdks needed from the java toolchain resolution println "Configuring resolveAllDependencies to depend on JavaCompile tasks for project ${project.path} because it applies the mrjar plugin" dependsOn project.getTasks().withType(JavaCompile.class) } // we run the packer script for all active branches. so we should be able to skip bwc here if (project.path.startsWith(":distribution:bwc:")) { dependsOn project.tasks.matching { it.name == 'buildBwcLinuxTar' } } if (project.path.contains("fixture")) { dependsOn tasks.withType(ComposePull) } if (project.path.contains(":distribution:docker")) { enabled = false } if (project.path.contains(":libs:cli")) { // ensure we resolve p2 dependencies for the spotless eclipse formatter dependsOn "spotlessJavaCheck" } } ext.withReleaseBuild = { Closure config -> if (buildParams.snapshotBuild == false) { config.call() } } def splitForCI = { proj, partString -> proj.tasks.register("check$partString") { dependsOn 'check' withReleaseBuild { dependsOn 'assemble' } } proj.tasks.addRule("Pattern: v#bwcTest$partString") { name -> if (name.endsWith("#bwcTest$partString")) { proj.project.getTasks().register(name) { task -> task.dependsOn(proj.tasks.named { tskName -> tskName == (name - partString) }) } } } proj.tasks.register("bcUpgradeTest$partString") { dependsOn tasks.matching { it.name == 'bcUpgradeTest' } withReleaseBuild { dependsOn 'assemble' } } } plugins.withId('lifecycle-base') { if (project.path.startsWith(":x-pack:")) { if (project.path.contains("security") || project.path.contains(":ml")) { splitForCI(project, "Part4") } else if (project.path.contains(":esql-datasource") || project.path.contains(":esql-core")) { splitForCI(project, "Part5") } else if (project.path.contains(":esql:qa") && project.path.contains("multi-node")) { splitForCI(project, "Part5") } else if (project.path.contains(":esql:qa")) { splitForCI(project, "Part3") } else if (project.path.contains(":eql") || project.path.contains(":sql") || project.path.contains(":transform") || project.path.contains("multi-node") || project.path.contains(":inference")) { splitForCI(project, "Part5") } else if (project.path.contains("ql")) { splitForCI(project, "Part3") } else if (project.path == ":x-pack:plugin") { splitForCI(project, "Part1") } else { splitForCI(project, "Part2") } } else if (project.path.startsWith(":qa:") || project.path.startsWith(":test:")) { splitForCI(project, "Part6") } else if (project.path.startsWith(":libs:")) { splitForCI(project, "Part6") } else { splitForCI(project, "Part1") } tasks.register('functionalTests') { dependsOn 'check' withReleaseBuild { dependsOn 'assemble' } } } /* * Remove assemble/dependenciesInfo on all qa projects because we don't * need to publish artifacts for them. */ if (project.name.equals('qa') || project.path.contains(':qa:')) { maybeConfigure(project.tasks, 'assemble') { it.enabled = false } maybeConfigure(project.tasks, 'dependenciesInfo') { it.enabled = false } } project.afterEvaluate { // Ensure similar tasks in dependent projects run first. The projectsEvaluated here is // important because, while dependencies.all will pickup future dependencies, // it is not necessarily true that the task exists in both projects at the time // the dependency is added. if (project.path == ':test:framework') { // :test:framework:test cannot run before and after :server:test return } tasks.matching { it.name.equals('integTest') }.configureEach { integTestTask -> integTestTask.mustRunAfter tasks.matching { it.name.equals("test") } } } } tasks.named("updateDaemonJvm") { def myPlatforms = [ BuildPlatformFactory.of( org.gradle.platform.Architecture.AARCH64, org.gradle.platform.OperatingSystem.MAC_OS ), BuildPlatformFactory.of( org.gradle.platform.Architecture.AARCH64, org.gradle.platform.OperatingSystem.LINUX ), BuildPlatformFactory.of( org.gradle.platform.Architecture.X86_64, org.gradle.platform.OperatingSystem.LINUX ), BuildPlatformFactory.of( org.gradle.platform.Architecture.X86_64, org.gradle.platform.OperatingSystem.WINDOWS ), BuildPlatformFactory.of( org.gradle.platform.Architecture.AARCH64, org.gradle.platform.OperatingSystem.WINDOWS ), // anyone still using x86 osx? BuildPlatformFactory.of( org.gradle.platform.Architecture.X86_64, org.gradle.platform.OperatingSystem.MAC_OS ) ] toolchainPlatforms.set(myPlatforms) languageVersion = JavaLanguageVersion.of(21) vendor = JvmVendorSpec.ADOPTIUM } tasks.register("verifyBwcTestsEnabled") { doLast { if (bwc_tests_enabled == false) { throw new GradleException('Bwc tests are disabled. They must be re-enabled after completing backcompat behavior backporting.') } } } tasks.register("branchConsistency") { description = 'Ensures this branch is internally consistent. For example, that versions constants match released versions.' group = 'Verification' dependsOn ":verifyVersions", ":verifyBwcTestsEnabled" } tasks.named("wrapper").configure { distributionType = 'BIN' def minimumGradleVersionFile = project.file('build-tools-internal/src/main/resources/minimumGradleVersion') doLast { // copy wrapper properties file to build-tools-internal to allow seamless idea integration def file = new File("build-tools-internal/gradle/wrapper/gradle-wrapper.properties") Files.copy(getPropertiesFile().toPath(), file.toPath(), REPLACE_EXISTING) // copy wrapper properties file to plugins/examples to allow seamless idea integration def examplePluginsWrapperProperties = new File("plugins/examples/gradle/wrapper/gradle-wrapper.properties") Files.copy(getPropertiesFile().toPath(), examplePluginsWrapperProperties.toPath(), REPLACE_EXISTING) // Update build-tools to reflect the Gradle upgrade // TODO: we can remove this once we have tests to make sure older versions work. minimumGradleVersionFile.text = gradleVersion println "Updated minimum Gradle Version" } } gradle.projectsEvaluated { // Having the same group and name for distinct projects causes Gradle to consider them equal when resolving // dependencies leading to hard to debug failures. Run a check across all project to prevent this from happening. // see: https://github.com/gradle/gradle/issues/847 Map coordsToProject = [:] project.allprojects.forEach { p -> String coords = "${p.group}:${p.name}" if (false == coordsToProject.putIfAbsent(coords, p)) { throw new GradleException( "Detected that two projects: ${p.path} and ${coordsToProject[coords].path} " + "have the same name and group: ${coords}. " + "This doesn't currently work correctly in Gradle, see: " + "https://github.com/gradle/gradle/issues/847" ) } } } tasks.named("validateChangelogs").configure { def triggeredTaskNames = gradle.startParameter.taskNames onlyIf { triggeredTaskNames.any(isCiSplitTask) == false } } tasks.named("precommit") { dependsOn gradle.includedBuild('build-tools').task(':precommit') dependsOn gradle.includedBuild('build-tools-internal').task(':precommit') } tasks.named("checkPart1").configure { } tasks.register("validateBuildGradleScripts", ValidateBuildGradleScriptsTask).configure { scriptFiles.from(fileTree(project.layout.settingsDirectory) { include "**/build.gradle" exclude "**/build/**" // Fixture build scripts under test resources model external repositories rather than this repository's build logic. exclude "**/src/**/resources/**" exclude ".gradle/**" }) ignore.set([ 'cross-project-dereference': [ 'distribution/archives/integ-test-zip/build.gradle', 'distribution/build.gradle', 'distribution/docker/build.gradle', 'distribution/tools/plugin-cli/bc/build.gradle', 'docs/build.gradle', 'qa/remote-clusters/build.gradle', 'qa/smoke-test-plugins/build.gradle', 'server/build.gradle', 'x-pack/plugin/ml/qa/native-multi-node-tests/build.gradle', 'x-pack/plugin/security/build.gradle', 'x-pack/plugin/sql/qa/server/build.gradle', 'x-pack/plugin/sql/sql-cli/build.gradle', 'x-pack/qa/smoke-test-plugins/build.gradle', 'x-pack/qa/smoke-test-plugins-ssl/build.gradle', ], 'distribution-closure-assignment': [ 'distribution/build.gradle::6', ], // Measured on main ff3ed1ce5a62. Counts are direct model references, not action counts. 'execution-closure-project-reference': [ 'build.gradle::6', 'docs/build.gradle::1', // Temporary until #164877 merges. 'modules/lang-painless/build.gradle::4', 'qa/vector/build.gradle::1', 'x-pack/plugin/esql-datasource-orc/qa/build.gradle::1', // Temporary until #164877 merges. 'x-pack/plugin/stack/build.gradle::4', // Temporary until #164877 merges. ], ]) } tasks.register("checkBuildLogic").configure { dependsOn gradle.includedBuild('build-tools').task(':check') dependsOn gradle.includedBuild('build-tools-internal').task(':check') dependsOn tasks.named("validateBuildGradleScripts") } [ releaseTestCheckEsqlEngine: [ ':x-pack:plugin:esql', ':x-pack:plugin:esql:compute', ':x-pack:plugin:esql:compute:ann', ':x-pack:plugin:esql:compute:gen', ':x-pack:plugin:esql:compute:test', ':x-pack:plugin:esql:profile-schema', ':x-pack:plugin:esql:qa:testFixtures', ':x-pack:plugin:esql:tools', ':x-pack:plugin:esql-core', ], // The ESQL QA suite is sharded so no job exceeds the CI timeout. The three heaviest, // independently-growing workloads are kept apart: // Qa1: single-node's csvSpecTests (~1h 10m) run in isolation. // Qa2: mixed-cluster runs the spec/yaml suites once per supported BWC version. // Qa3: single-node's REST tests plus the remaining lightweight QA projects. releaseTestCheckEsqlQa1: [ // Explicit task path — the loop appends :releaseTestCheck only for plain project paths. ':x-pack:plugin:esql:qa:server:single-node:releaseTestCheckCsvSpec', ], releaseTestCheckEsqlQa2: [ ':x-pack:plugin:esql:qa:server:mixed-cluster', ':x-pack:plugin:esql:qa:server:multi-node', ':x-pack:plugin:esql:qa:security', ], releaseTestCheckEsqlQa3: [ ':x-pack:plugin:esql:qa:action', ':x-pack:plugin:esql:qa:server', // Explicit task path — runs only the REST variants (csvSpecTests runs in its own Qa1 job). ':x-pack:plugin:esql:qa:server:single-node:releaseTestCheckRest', ':x-pack:plugin:esql:qa:server:multi-clusters', ], releaseTestCheckEsqlDatasourceCore: [ ':x-pack:plugin:esql-datasource-azure', ':x-pack:plugin:esql-datasource-brotli', ':x-pack:plugin:esql-datasource-bzip2', ':x-pack:plugin:esql-datasource-compression-libs', ':x-pack:plugin:esql-datasource-csv', ':x-pack:plugin:esql-datasource-gcs', ':x-pack:plugin:esql-datasource-grpc', ':x-pack:plugin:esql-datasource-gzip', ':x-pack:plugin:esql-datasource-http', ':x-pack:plugin:esql-datasource-iceberg', ':x-pack:plugin:esql-datasource-lz4', ':x-pack:plugin:esql-datasource-ndjson', ':x-pack:plugin:esql-datasource-netty-commons', ':x-pack:plugin:esql-datasource-orc', ], releaseTestCheckEsqlDatasourceQa: [ ':x-pack:plugin:esql-datasource-csv:qa', ':x-pack:plugin:esql-datasource-iceberg:qa', ':x-pack:plugin:esql-datasource-ndjson:qa', ':x-pack:plugin:esql-datasource-orc:qa', ':x-pack:plugin:esql-datasource-parquet', ':x-pack:plugin:esql-datasource-parquet:qa', ':x-pack:plugin:esql-datasource-snappy', ':x-pack:plugin:esql-datasource-zstd', ], ].each { taskName, taskPaths -> tasks.register(taskName) { group = 'Verification' description = "Runs ${taskName} tasks." // Plain project paths get :releaseTestCheck appended; explicit task paths are used as-is. dependsOn taskPaths.collect { path -> path.contains(':releaseTestCheck') ? path : "${path}:releaseTestCheck" } } } tasks.named("assemble").configure { dependsOn gradle.includedBuild('build-tools').task(':assemble') } tasks.register("buildReleaseArtifacts").configure { group = 'build' description = 'Builds all artifacts required for release manager' dependsOn allprojects.findAll { it.path.startsWith(':distribution:docker') == false && it.path.startsWith(':ml-cpp') == false && it.path.startsWith(':distribution:bwc') == false && it.path.startsWith(':test:fixture') == false } .collect { GradleUtils.findByName(it.tasks, 'assemble') } .findAll { it != null } dependsOn upgradeCompatibilityZip } tasks.register("spotlessApply").configure { dependsOn gradle.includedBuild('build-tools').task(':spotlessApply') dependsOn gradle.includedBuild('build-tools').task(':reaper:spotlessApply') dependsOn gradle.includedBuild('build-tools-internal').task(':spotlessApply') }