org.gradle.configurationcache.ConfigurationCacheDependencyResolutionIntegrationTest.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.gradle.configurationcache
import org.gradle.integtests.resolve.transform.ArtifactTransformTestFixture
import org.gradle.test.fixtures.server.http.HttpServer
import org.gradle.test.fixtures.server.http.MavenHttpRepository
import org.junit.Rule
import spock.lang.Issue
class ConfigurationCacheDependencyResolutionIntegrationTest extends AbstractConfigurationCacheIntegrationTest implements ArtifactTransformTestFixture {
@Rule
HttpServer httpServer = new HttpServer()
def remoteRepo = new MavenHttpRepository(httpServer, mavenRepo)
def setup() {
// So that dependency resolution results from previous executions do not interfere
requireOwnGradleUserHomeDir()
}
def setupBuildWithEachDependencyType() {
httpServer.start()
taskTypeWithOutputFileProperty()
remoteRepo.module("group", "lib1", "6500").publish().allowAll()
settingsFile << """
include 'a', 'b'"""
buildFile << """
subprojects {
configurations { create("default") }
task producer(type: FileProducer) {
content = providers.gradleProperty("\${project.name}Content").orElse("content")
output = layout.buildDirectory.file("\${project.name}.out")
}
configurations.default.outgoing.artifact(producer.output)
}
repositories {
maven { url = uri('${remoteRepo.uri}') }
}
configurations {
implementation
}
task additionalFile(type: FileProducer) {
output = file("b.thing")
}
dependencies {
implementation project(':a')
implementation project(':b')
implementation "group:lib1:6500"
implementation files('a.thing', additionalFile.output)
}
"""
}
def "task input file collection can include project dependencies, external dependencies, prebuilt file dependencies and task output file dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithEachDependencyType()
taskTypeLogsInputFileCollectionContent()
buildFile << """
task resolve(type: ShowFilesTask) {
inFiles.from(configurations.implementation)
}
"""
given:
configurationCacheRun(":resolve")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":additionalFile", ":resolve")
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":additionalFile")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
outputContains("result = [a.thing, b.thing, a.out, b.out, lib1-6500.jar]")
when:
configurationCacheRun(":resolve", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":additionalFile", ":resolve")
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":additionalFile")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
outputContains("result = [a.thing, b.thing, a.out, b.out, lib1-6500.jar]")
}
def "task input artifact collection can include project dependencies, external dependencies, prebuilt file dependencies and task output file dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithEachDependencyType()
taskTypeLogsArtifactCollectionDetails()
buildFile << """
task resolve(type: ShowArtifactCollection) {
collection = configurations.implementation.incoming.artifacts
}
"""
given:
configurationCacheRun(":resolve")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":additionalFile", ":resolve")
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":additionalFile")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
outputContains("files = [a.thing, b.thing, a.out, b.out, lib1-6500.jar]")
outputContains("artifacts = [a.thing, b.thing, a.out (project :a), b.out (project :b), lib1-6500.jar (group:lib1:6500)]")
outputContains("variants = [{artifactType=thing}, {artifactType=thing}, {artifactType=out}, {artifactType=out}, {artifactType=jar, org.gradle.status=release}]")
when:
configurationCacheRun(":resolve", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":additionalFile", ":resolve")
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":additionalFile")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
outputContains("files = [a.thing, b.thing, a.out, b.out, lib1-6500.jar]")
outputContains("artifacts = [a.thing, b.thing, a.out (project :a), b.out (project :b), lib1-6500.jar (group:lib1:6500)]")
outputContains("variants = [{artifactType=thing}, {artifactType=thing}, {artifactType=out}, {artifactType=out}, {artifactType=jar, org.gradle.status=release}]")
}
def "task input property can include mapped configuration elements that contain project dependencies"() {
def configurationCache = newConfigurationCacheFixture()
taskTypeWithOutputFileProperty()
taskTypeWithInputListProperty()
settingsFile << """
include 'a', 'b'"""
buildFile << """
subprojects {
configurations { create("default") }
task producer(type: FileProducer) {
content = providers.gradleProperty("\${project.name}Content").orElse("0")
output = layout.buildDirectory.file("\${project.name}.out")
}
configurations.default.outgoing.artifact(producer.output)
}
configurations {
implementation
}
dependencies {
implementation project(':a')
implementation project(':b')
}
task resolve(type: InputTask) {
inValue = configurations.implementation.elements.map { files -> files.collect { it.asFile.text.toInteger() } }
outFile = file('out.txt')
}
"""
given:
configurationCacheRun(":resolve")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
result.assertTaskSkipped(":resolve")
file('out.txt').text == "10,10"
when:
configurationCacheRun(":resolve", "-PaContent=2")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
result.assertTaskNotSkipped(":resolve")
file('out.txt').text == "12,10"
}
def setupBuildWithArtifactTransformOfProjectDependencies(boolean legacy) {
settingsFile << """
include 'a', 'b'
"""
if (legacy) {
setupBuildWithLegacyColorTransformImplementation()
} else {
setupBuildWithColorTransformImplementation()
}
buildFile << """
dependencies {
implementation project(':a')
implementation project(':b')
}
"""
}
def "task input file collection can include the output of artifact transform of project dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformOfProjectDependencies(legacy)
when:
configurationCacheRun(":resolve")
then:
assertTransformed("a.jar", "b.jar")
outputContains("result = [a.jar.green, b.jar.green]")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
assertTransformed()
outputContains("result = [a.jar.green, b.jar.green]")
when:
configurationCacheRun(":resolve", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
assertTransformed("a.jar")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
outputContains("result = [a.jar.green, b.jar.green]")
where:
legacy << [true, false]
}
def "task input artifact collection can include the output of artifact transform of project dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformOfProjectDependencies(legacy)
when:
configurationCacheRun(":resolveArtifacts")
then:
assertTransformed("a.jar", "b.jar")
outputContains("files = [a.jar.green, b.jar.green]")
outputContains("artifacts = [a.jar.green (project :a), b.jar.green (project :b)]")
outputContains("variants = [{artifactType=jar, color=green}, {artifactType=jar, color=green}]")
when:
configurationCacheRun(":resolveArtifacts")
then: // everything up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolveArtifacts")
result.assertTaskOrder(":b:producer", ":resolveArtifacts")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
assertTransformed()
outputContains("files = [a.jar.green, b.jar.green]")
outputContains("artifacts = [a.jar.green (project :a), b.jar.green (project :b)]")
outputContains("variants = [{artifactType=jar, color=green}, {artifactType=jar, color=green}]")
when:
configurationCacheRun(":resolveArtifacts", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolveArtifacts")
result.assertTaskOrder(":b:producer", ":resolveArtifacts")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
assertTransformed("a.jar")
outputContains("files = [a.jar.green, b.jar.green]")
outputContains("artifacts = [a.jar.green (project :a), b.jar.green (project :b)]")
outputContains("variants = [{artifactType=jar, color=green}, {artifactType=jar, color=green}]")
where:
legacy << [true, false]
}
def setupBuildWithArtifactTransformsOfExternalDependencies(boolean legacy) {
httpServer.start()
withColorVariants(remoteRepo.module("group", "thing1", "1.2")).publish().allowAll()
withColorVariants(remoteRepo.module("group", "thing2", "1.2")).publish().allowAll()
if (legacy) {
setupBuildWithLegacyColorTransformImplementation()
} else {
setupBuildWithColorTransformImplementation()
}
buildFile << """
repositories {
maven {
url = uri('${remoteRepo.uri}')
metadataSources { gradleMetadata() }
}
}
dependencies {
implementation "group:thing1:1.2"
implementation "group:thing2:1.2"
}
"""
}
def "task input file collection can include the output of artifact transform of external dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfExternalDependencies(legacy)
when:
configurationCacheRun(":resolve")
then:
assertTransformed("thing1-1.2.jar", "thing2-1.2.jar")
outputContains("result = [thing1-1.2.jar.green, thing2-1.2.jar.green]")
when:
configurationCacheRun(":resolve")
then:
configurationCache.assertStateLoaded()
assertTransformed()
outputContains("result = [thing1-1.2.jar.green, thing2-1.2.jar.green]")
where:
legacy << [true, false]
}
def "task input artifact collection can include the output of artifact transform of external dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfExternalDependencies(legacy)
when:
configurationCacheRun(":resolveArtifacts")
then:
assertTransformed("thing1-1.2.jar", "thing2-1.2.jar")
outputContains("files = [thing1-1.2.jar.green, thing2-1.2.jar.green]")
outputContains("artifacts = [thing1-1.2.jar.green (group:thing1:1.2), thing2-1.2.jar.green (group:thing2:1.2)]")
outputContains("variants = [{artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}]")
when:
configurationCacheRun(":resolveArtifacts")
then:
configurationCache.assertStateLoaded()
assertTransformed()
outputContains("files = [thing1-1.2.jar.green, thing2-1.2.jar.green]")
outputContains("artifacts = [thing1-1.2.jar.green (group:thing1:1.2), thing2-1.2.jar.green (group:thing2:1.2)]")
outputContains("variants = [{artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}]")
where:
legacy << [true, false]
}
def "many tasks in the same project can consume the output of transform of external dependencies"() {
setupBuildWithArtifactTransformsOfExternalDependencies(false)
buildFile << """
for (i in 0..5) {
task "resolve\$i" {
def view = configurations.implementation.incoming.artifactView {
attributes.attribute(color, 'green')
}.files
inputs.files view
doLast {
println "result = \${view.files.name}"
}
}
}
"""
def fixture = newConfigurationCacheFixture()
when:
configurationCacheRun(":resolve0", ":resolve1", ":resolve2", ":resolve3", ":resolve4")
then:
fixture.assertStateStored()
assertTransformed("thing1-1.2.jar", "thing2-1.2.jar")
output.count("result = [thing1-1.2.jar.green, thing2-1.2.jar.green]") == 5
when:
configurationCacheRun(":resolve0", ":resolve1", ":resolve2", ":resolve3", ":resolve4")
then:
fixture.assertStateLoaded()
assertTransformed()
output.count("result = [thing1-1.2.jar.green, thing2-1.2.jar.green]") == 5
}
def setupBuildWithArtifactTransformsOfPrebuiltFileDependencies(boolean legacy) {
if (legacy) {
setupBuildWithLegacyColorTransformImplementation()
} else {
setupBuildWithColorTransformImplementation()
}
buildFile << """
dependencies.artifactTypes {
blue {
attributes.attribute(color, 'blue')
}
}
dependencies {
implementation files('root.blue')
}
"""
file('root.blue') << 'root'
}
def "task input file collection can include the output of artifact transforms of prebuilt file dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfPrebuiltFileDependencies(legacy)
when:
configurationCacheRun(":resolve")
then:
assertTransformed("root.blue")
outputContains("result = [root.blue.green]")
when:
configurationCacheRun(":resolve")
then: // everything up-to-date
configurationCache.assertStateLoaded()
assertTransformed()
outputContains("result = [root.blue.green]")
where:
legacy << [true, false]
}
def "task input artifact collection can include the output of artifact transforms of prebuilt file dependencies"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfPrebuiltFileDependencies(legacy)
when:
configurationCacheRun(":resolveArtifacts")
then:
assertTransformed("root.blue")
outputContains("files = [root.blue.green]")
outputContains("artifacts = [root.blue.green (root.blue)]")
outputContains("variants = [{artifactType=blue, color=green}]")
when:
configurationCacheRun(":resolveArtifacts")
then: // everything up-to-date
configurationCache.assertStateLoaded()
assertTransformed()
outputContains("files = [root.blue.green]")
outputContains("artifacts = [root.blue.green (root.blue)]")
outputContains("variants = [{artifactType=blue, color=green}]")
where:
legacy << [true, false]
}
def setupBuildWithArtifactTransformsOfFileDependenciesThatContainTaskOutputs(boolean legacy) {
settingsFile << """
rootProject.name = 'root'
include 'a'
"""
if (legacy) {
setupBuildWithLegacyColorTransformImplementation()
} else {
setupBuildWithColorTransformImplementation()
}
buildFile << """
allprojects {
task additionalFile(type: FileProducer) {
output = layout.buildDirectory.file("\${project.name}.additional.blue")
}
}
dependencies.artifactTypes {
blue {
attributes.attribute(color, 'blue')
}
}
dependencies {
implementation files(tasks.additionalFile.output, 'root.blue')
implementation project(':a')
}
project(':a') {
dependencies {
implementation files(tasks.additionalFile.output)
}
}
"""
file('root.blue') << 'root'
}
@Issue("https://github.com/gradle/gradle/issues/13200")
def "task input file collection can include the output of artifact transforms of file dependencies that include task outputs"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfFileDependenciesThatContainTaskOutputs(legacy)
when:
configurationCacheRun(":resolve")
then:
assertTransformed("root.blue", "root.additional.blue", "a.additional.blue", "a.jar")
outputContains("result = [root.additional.blue.green, root.blue.green, a.jar.green, a.additional.blue.green]")
when:
configurationCacheRun(":resolve")
then: // everything up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":a:additionalFile", ":resolve")
result.assertTaskOrder(":additionalFile", ":resolve")
assertTransformed()
outputContains("result = [root.additional.blue.green, root.blue.green, a.jar.green, a.additional.blue.green]")
where:
legacy << [true, false]
}
@Issue("https://github.com/gradle/gradle/issues/13200")
def "task input artifact collection can include the output of artifact transforms of file dependencies that include task outputs"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfFileDependenciesThatContainTaskOutputs(legacy)
when:
configurationCacheRun(":resolveArtifacts")
then:
assertTransformed("root.blue", "root.additional.blue", "a.additional.blue", "a.jar")
outputContains("files = [root.additional.blue.green, root.blue.green, a.jar.green, a.additional.blue.green]")
outputContains("artifacts = [root.additional.blue.green (root.additional.blue), root.blue.green (root.blue), a.jar.green (project :a), a.additional.blue.green (a.additional.blue)]")
outputContains("variants = [{artifactType=blue, color=green}, {artifactType=blue, color=green}, {artifactType=jar, color=green}, {artifactType=blue, color=green}]")
when:
configurationCacheRun(":resolveArtifacts")
then: // everything up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolveArtifacts")
result.assertTaskOrder(":a:additionalFile", ":resolveArtifacts")
result.assertTaskOrder(":additionalFile", ":resolveArtifacts")
assertTransformed()
outputContains("files = [root.additional.blue.green, root.blue.green, a.jar.green, a.additional.blue.green]")
outputContains("artifacts = [root.additional.blue.green (root.additional.blue), root.blue.green (root.blue), a.jar.green (project :a), a.additional.blue.green (a.additional.blue)]")
outputContains("variants = [{artifactType=blue, color=green}, {artifactType=blue, color=green}, {artifactType=jar, color=green}, {artifactType=blue, color=green}]")
where:
legacy << [true, false]
}
def "task input file collection can include the output of chained artifact transform of project dependencies"() {
def configurationCache = newConfigurationCacheFixture()
settingsFile << """
include 'a', 'b'
"""
setupBuildWithChainedColorTransform()
buildFile << """
dependencies {
implementation project(':a')
implementation project(':b')
}
"""
when:
configurationCacheRun(":resolve")
then:
assertTransformed("a.jar", "a.jar.red", "b.jar", "b.jar.red")
outputContains("result = [a.jar.red.green, b.jar.red.green]")
when:
configurationCacheRun(":resolve")
then: // everything up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
assertTransformed()
outputContains("result = [a.jar.red.green, b.jar.red.green")
when:
configurationCacheRun(":resolve", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
assertTransformed("a.jar", "a.jar.red")
outputContains("result = [a.jar.red.green, b.jar.red.green")
}
def "task input file collection can include the output of artifact transform of project dependencies which takes the output of another transform as input parameter"() {
def configurationCache = newConfigurationCacheFixture()
settingsFile << """
include 'a', 'b'
"""
setupBuildWithColorTransformWithAnotherTransformOutputAsInput()
buildFile << """
dependencies {
implementation project(':a')
implementation project(':b')
transform project(':a')
}
"""
when:
configurationCacheRun(":resolve")
then:
output.count("processing") == 3
outputContains("processing a.jar to make red")
outputContains("processing a.jar using [a.jar.red]")
outputContains("processing b.jar using [a.jar.red]")
outputContains("result = [a.jar.green, b.jar.green]")
when:
configurationCacheRun(":resolve")
then: // everything up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
output.count("processing") == 0
outputContains("result = [a.jar.green, b.jar.green]")
when:
configurationCacheRun(":resolve", "-PaContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskNotSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
output.count("processing") == 3
outputContains("processing a.jar to make red")
outputContains("processing a.jar using [a.jar.red]")
outputContains("processing b.jar using [a.jar.red]")
outputContains("result = [a.jar.green, b.jar.green]")
}
def "task input file collection can include output of artifact transform of project dependencies when transform takes upstream artifacts"() {
def configurationCache = newConfigurationCacheFixture()
settingsFile << """
include 'a', 'b', 'c'
"""
setupBuildWithColorTransformThatTakesUpstreamArtifacts()
buildFile << """
dependencies {
implementation project(':a')
}
project(':a') {
dependencies {
implementation project(':b')
implementation project(':c')
}
}
"""
when:
configurationCacheRun(":resolve")
then:
output.count("processing") == 3
outputContains("processing c.jar using []")
outputContains("processing b.jar using []")
outputContains("processing a.jar using [b.jar, c.jar]")
outputContains("result = [a.jar.green, b.jar.green, c.jar.green]")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskOrder(":c:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
result.assertTaskSkipped(":c:producer")
output.count("processing") == 0
outputContains("result = [a.jar.green, b.jar.green, c.jar.green]")
when:
configurationCacheRun(":resolve", "-PbContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskOrder(":c:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskNotSkipped(":b:producer")
result.assertTaskSkipped(":c:producer")
output.count("processing") == 2
outputContains("processing b.jar using []")
outputContains("processing a.jar using [b.jar, c.jar]")
outputContains("result = [a.jar.green, b.jar.green, c.jar.green]")
}
def "task input file collection can include output of artifact transform of external dependencies when transform takes upstream artifacts"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfExternalDependenciesThatTakeUpstreamDependencies()
when:
configurationCacheRun(":resolve")
then:
output.count("processing") == 3
outputContains("processing thing1-1.2.jar using []")
outputContains("processing thing2-1.2.jar using []")
outputContains("processing thing3-1.2.jar using [thing1-1.2.jar, thing2-1.2.jar]")
outputContains("result = [thing3-1.2.jar.green, thing1-1.2.jar.green, thing2-1.2.jar.green]")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
output.count("processing") == 0
outputContains("result = [thing3-1.2.jar.green, thing1-1.2.jar.green, thing2-1.2.jar.green]")
}
def "task input artifact collection can include output of artifact transform of external dependencies when transform takes upstream artifacts"() {
def configurationCache = newConfigurationCacheFixture()
setupBuildWithArtifactTransformsOfExternalDependenciesThatTakeUpstreamDependencies()
when:
configurationCacheRun(":resolveArtifacts")
then:
output.count("processing") == 3
outputContains("processing thing1-1.2.jar using []")
outputContains("processing thing2-1.2.jar using []")
outputContains("processing thing3-1.2.jar using [thing1-1.2.jar, thing2-1.2.jar]")
outputContains("files = [thing3-1.2.jar.green, thing1-1.2.jar.green, thing2-1.2.jar.green]")
outputContains("artifacts = [thing3-1.2.jar.green (group:thing3:1.2), thing1-1.2.jar.green (group:thing1:1.2), thing2-1.2.jar.green (group:thing2:1.2)]")
outputContains("variants = [{artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}]")
when:
configurationCacheRun(":resolveArtifacts")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
output.count("processing") == 0
outputContains("files = [thing3-1.2.jar.green, thing1-1.2.jar.green, thing2-1.2.jar.green]")
outputContains("artifacts = [thing3-1.2.jar.green (group:thing3:1.2), thing1-1.2.jar.green (group:thing1:1.2), thing2-1.2.jar.green (group:thing2:1.2)]")
outputContains("variants = [{artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}, {artifactType=jar, color=green, org.gradle.status=release}]")
}
private void setupBuildWithArtifactTransformsOfExternalDependenciesThatTakeUpstreamDependencies() {
httpServer.start()
def dep1 = withColorVariants(remoteRepo.module("group", "thing1", "1.2")).publish().allowAll()
def dep2 = withColorVariants(remoteRepo.module("group", "thing2", "1.2")).publish().allowAll()
withColorVariants(remoteRepo.module("group", "thing3", "1.2")).dependsOn(dep1).dependsOn(dep2).publish().allowAll()
setupBuildWithColorTransformThatTakesUpstreamArtifacts()
buildFile << """
dependencies {
implementation 'group:thing3:1.2'
}
repositories {
maven { url = '${remoteRepo.uri}' }
}
"""
}
@Issue("https://github.com/gradle/gradle/issues/13245")
def "task input file collection can include output of artifact transform of project dependencies when transform takes transformed upstream artifacts"() {
def configurationCache = newConfigurationCacheFixture()
settingsFile << """
include 'a', 'b', 'c'
"""
setupBuildWithChainedColorTransformThatTakesUpstreamArtifacts()
buildFile << """
dependencies {
implementation project(':a')
}
project(':a') {
dependencies {
implementation project(':b')
implementation project(':c')
}
}
"""
when:
configurationCacheRun(":resolve")
then:
output.count("processing") == 6
outputContains("processing a.jar")
outputContains("processing b.jar")
outputContains("processing c.jar")
outputContains("processing b.jar.red using []")
outputContains("processing c.jar.red using []")
outputContains("processing a.jar.red using [b.jar.red, c.jar.red]")
outputContains("result = [a.jar.red.green, b.jar.red.green, c.jar.red.green]")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskOrder(":c:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskSkipped(":b:producer")
result.assertTaskSkipped(":c:producer")
output.count("processing") == 0
outputContains("result = [a.jar.red.green, b.jar.red.green, c.jar.red.green]")
when:
configurationCacheRun(":resolve", "-PbContent=changed")
then:
configurationCache.assertStateLoaded()
result.assertTaskOrder(":a:producer", ":resolve")
result.assertTaskOrder(":b:producer", ":resolve")
result.assertTaskOrder(":c:producer", ":resolve")
result.assertTaskSkipped(":a:producer")
result.assertTaskNotSkipped(":b:producer")
result.assertTaskSkipped(":c:producer")
output.count("processing") == 3
outputContains("processing b.jar")
outputContains("processing b.jar.red using []")
outputContains("processing a.jar.red using [b.jar.red, c.jar.red]")
outputContains("result = [a.jar.red.green, b.jar.red.green, c.jar.red.green]")
}
@Issue("https://github.com/gradle/gradle/issues/13245")
def "task input file collection can include output of artifact transform of external dependencies when transform takes transformed upstream artifacts"() {
def configurationCache = newConfigurationCacheFixture()
httpServer.start()
def dep1 = withColorVariants(remoteRepo.module("group", "thing1", "1.2")).publish().allowAll()
def dep2 = withColorVariants(remoteRepo.module("group", "thing2", "1.2")).publish().allowAll()
withColorVariants(remoteRepo.module("group", "thing3", "1.2")).dependsOn(dep1).dependsOn(dep2).publish().allowAll()
setupBuildWithChainedColorTransformThatTakesUpstreamArtifacts()
buildFile << """
dependencies {
implementation 'group:thing3:1.2'
}
repositories {
maven { url = '${remoteRepo.uri}' }
}
"""
when:
configurationCacheRun(":resolve")
then:
output.count("processing") == 6
outputContains("processing thing1-1.2.jar")
outputContains("processing thing2-1.2.jar")
outputContains("processing thing2-1.2.jar")
outputContains("processing thing1-1.2.jar.red using []")
outputContains("processing thing2-1.2.jar.red using []")
outputContains("processing thing3-1.2.jar.red using [thing1-1.2.jar.red, thing2-1.2.jar.red]")
outputContains("result = [thing3-1.2.jar.red.green, thing1-1.2.jar.red.green, thing2-1.2.jar.red.green]")
when:
configurationCacheRun(":resolve")
then: // everything is up-to-date
configurationCache.assertStateLoaded()
output.count("processing") == 0
outputContains("result = [thing3-1.2.jar.red.green, thing1-1.2.jar.red.green, thing2-1.2.jar.red.green]")
}
@Issue("https://github.com/gradle/gradle/issues/14513")
def "task input file collection can include transformed outputs of file collection containing transform outputs"() {
setupBuildWithArtifactTransformOfProjectDependencies(false)
buildFile << """
abstract class MakeRed implements TransformAction {
@InputArtifact
abstract Provider getInputArtifact()
void transform(TransformOutputs outputs) {
def input = inputArtifact.get().asFile
println "converting \${input.name} to red"
assert input.file
def output = outputs.file(input.name + ".red")
output.text = input.text + ".red"
}
}
dependencies {
artifactTypes {
green {
attributes.attribute(color, 'green')
}
}
registerTransform(MakeRed) {
from.attribute(color, 'green')
to.attribute(color, 'red')
}
}
configurations {
transformed
}
def intermediateFiles = configurations.implementation.incoming.artifactView {
attributes.attribute(color, 'green')
}.files
dependencies {
transformed files(intermediateFiles)
}
def transformedFiles = configurations.transformed.incoming.artifactView {
attributes.attribute(color, 'red')
}.files
task resolveTransformed(type: ShowFileCollection) {
files.from(transformedFiles)
}
"""
def fixture = newConfigurationCacheFixture()
when:
configurationCacheRun("resolveTransformed")
then:
fixture.assertStateStored()
outputContains("processing [a.jar]")
outputContains("processing [b.jar]")
outputContains("converting a.jar.green to red")
outputContains("converting b.jar.green to red")
outputContains("result = [a.jar.green.red, b.jar.green.red]")
when:
configurationCacheRun("resolveTransformed")
then:
fixture.assertStateLoaded()
outputDoesNotContain("processing")
outputDoesNotContain("converting")
outputContains("result = [a.jar.green.red, b.jar.green.red]")
}
def "buildSrc output may require transform output"() {
withColorVariants(mavenRepo.module("test", "test", "12")).publish()
file("buildSrc/settings.gradle") << """
include 'producer'
"""
def buildSrcBuildFile = file("buildSrc/build.gradle")
setupBuildWithLegacyColorTransformImplementation(buildSrcBuildFile)
buildSrcBuildFile << """
repositories {
maven { url = '${mavenRepo.uri}' }
}
dependencies {
artifactTypes {
blue {
attributes.attribute(color, 'blue')
}
}
}
dependencies { implementation project(':producer') }
dependencies { implementation files('thing.blue') }
dependencies { implementation 'test:test:12' }
jar.dependsOn(resolve)
"""
file("buildSrc/thing.blue").createFile()
def fixture = newConfigurationCacheFixture()
when:
configurationCacheRun()
then:
fixture.assertStateStored()
result.assertTaskExecuted(":buildSrc:producer:producer")
result.assertTaskExecuted(":buildSrc:resolve")
result.assertTaskExecuted(":help")
assertTransformed("producer.jar", "test-12.jar", "thing.blue")
when:
configurationCacheRun()
then:
fixture.assertStateLoaded()
result.assertTasksExecuted(":help")
assertTransformed()
}
def "reports failure to transform prebuilt file dependency"() {
settingsFile << """
include 'a'
"""
setupBuildWithColorTransformAction()
buildFile << """
abstract class MakeGreen implements TransformAction {
@InputArtifact
abstract Provider getInputArtifact()
void transform(TransformOutputs outputs) {
def input = inputArtifact.get().asFile
println "processing \${input.name}"
throw new RuntimeException("broken: \${input.name}")
}
}
dependencies.artifactTypes {
blue {
attributes.attribute(color, 'blue')
}
}
dependencies {
implementation files('root.blue')
implementation project(':a')
}
project(':a') {
dependencies {
implementation files('a.blue')
}
}
"""
file('root.blue') << 'root'
file('a/a.blue') << 'a'
def configurationCache = newConfigurationCacheFixture()
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateStored() // transform spec is stored
output.count("processing") == 3
outputContains("processing root.blue")
outputContains("processing a.jar")
outputContains("processing a.blue")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform root.blue to match attributes {artifactType=blue, color=green}.")
it.assertHasCause("Failed to transform a.jar (project :a) to match attributes {artifactType=jar, color=green}.")
it.assertHasCause("Failed to transform a.blue to match attributes {artifactType=blue, color=green}.")
}
failure.assertHasFailures(1)
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateLoaded()
output.count("processing") == 2
outputContains("processing root.blue")
outputContains("processing a.jar")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform root.blue to match attributes {artifactType=blue, color=green}.")
// TODO - should collect all failures rather than stopping on first failure
}
failure.assertHasFailures(1)
}
def "reports failure to transform project dependency"() {
settingsFile << """
include 'a', 'b'
"""
setupBuildWithColorTransformAction()
buildFile << """
abstract class MakeGreen implements TransformAction {
@InputArtifact
abstract Provider getInputArtifact()
void transform(TransformOutputs outputs) {
def input = inputArtifact.get().asFile
println "processing \${input.name}"
throw new RuntimeException("broken: \${input.name}")
}
}
dependencies {
implementation project(':a')
implementation project(':b')
}
"""
def configurationCache = newConfigurationCacheFixture()
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateStored()
output.count("processing") == 2
outputContains("processing a.jar")
outputContains("processing b.jar")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform a.jar (project :a) to match attributes {artifactType=jar, color=green}.")
it.assertHasCause("Failed to transform b.jar (project :b) to match attributes {artifactType=jar, color=green}.")
}
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateLoaded()
output.count("processing") == 2
outputContains("processing a.jar")
outputContains("processing b.jar")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform a.jar (project :a) to match attributes {artifactType=jar, color=green}.")
// TODO - should collect all failures rather than stopping on first failure
}
}
def "reports failure to transform external dependency"() {
httpServer.start()
withColorVariants(remoteRepo.module("group", "thing1", "1.2")).publish().allowAll()
withColorVariants(remoteRepo.module("group", "thing2", "1.2")).publish().allowAll()
setupBuildWithColorTransformAction()
buildFile << """
abstract class MakeGreen implements TransformAction {
@InputArtifact
abstract Provider getInputArtifact()
void transform(TransformOutputs outputs) {
def input = inputArtifact.get().asFile
println "processing \${input.name}"
throw new RuntimeException("broken: \${input.name}")
}
}
repositories {
maven { url = '${remoteRepo.uri}' }
}
dependencies {
implementation 'group:thing1:1.2'
implementation 'group:thing2:1.2'
}
"""
def configurationCache = newConfigurationCacheFixture()
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateStored()
output.count("processing") == 2
outputContains("processing thing1-1.2.jar")
outputContains("processing thing2-1.2.jar")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform thing1-1.2.jar (group:thing1:1.2) to match attributes {artifactType=jar, color=green, org.gradle.status=release}.")
it.assertHasCause("Failed to transform thing2-1.2.jar (group:thing2:1.2) to match attributes {artifactType=jar, color=green, org.gradle.status=release}.")
}
when:
configurationCacheFails(":resolve")
then:
configurationCache.assertStateLoaded()
output.count("processing") == 1
outputContains("processing thing1-1.2.jar")
failure.assertHasFailure("Execution failed for task ':resolve'.") {
it.assertHasCause("Failed to transform thing1-1.2.jar (group:thing1:1.2) to match attributes {artifactType=jar, color=green, org.gradle.status=release}.")
// TODO - should collect all failures rather than stopping on first failure
}
}
def 'transform action is re-executed when input artifact changes'() {
given:
buildKotlinFile '''
abstract class Summarize : TransformAction {
@get:InputArtifact
abstract val inputArtifact: Provider
override fun transform(outputs: TransformOutputs) {
val inputFile = inputArtifact.get().asFile
println("Transforming ${inputFile.name}...")
outputs.file("${inputFile.nameWithoutExtension}-summary.txt").run {
writeText("${inputFile.name}: ${inputFile.length()}")
}
}
}
val summarized = Attribute.of("summarized", Boolean::class.javaObjectType)
dependencies {
attributesSchema {
attribute(summarized)
}
artifactTypes.create("txt") {
attributes.attribute(summarized, false)
}
registerTransform(Summarize::class) {
from.attribute(summarized, false)
to.attribute(summarized, true)
}
}
val sourceFiles by configurations.creating {
isCanBeConsumed = false
isCanBeResolved = false
}
val summarizedFiles by configurations.creating {
extendsFrom(sourceFiles)
isCanBeConsumed = false
isCanBeResolved = true
attributes {
attribute(summarized, true)
}
}
abstract class CombineSummaries : DefaultTask() {
@get:InputFiles
abstract val inputSummaries: ConfigurableFileCollection
@get:OutputFile
abstract val outputFile: RegularFileProperty
@TaskAction
fun summarize() {
outputFile.get().asFile.run {
parentFile.mkdirs()
writeText(summaryString())
}
}
private
fun summaryString() = inputSummaries.files.joinToString(separator = "\\n") { it.readText() }
}
tasks.register("summarize") {
inputSummaries.from(summarizedFiles)
outputFile.set(layout.buildDirectory.file("summary.txt"))
}
dependencies {
sourceFiles(files("input.txt"))
}
'''
def inputFile = file('input.txt').tap { write("the input file") }
def outputFile = file('build/summary.txt')
def expectedOutput = "input.txt: ${inputFile.length()}"
def configurationCache = newConfigurationCacheFixture()
when:
configurationCacheRun 'summarize'
then:
configurationCache.assertStateStored()
outputFile.text == expectedOutput
outputContains 'Transforming input.txt...'
result.assertTaskExecuted ':summarize'
when: 'input file changes'
inputFile.text = inputFile.text.reverse()
configurationCacheRun 'summarize'
then:
configurationCache.assertStateLoaded()
outputFile.text == expectedOutput
outputContains 'Transforming input.txt...'
result.assertTaskExecuted ':summarize'
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy