diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/AbstractCommandLineOrderTaskIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/AbstractCommandLineOrderTaskIntegrationTest.groovy index 51c9b40d8f94..c80c38449293 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/api/AbstractCommandLineOrderTaskIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/api/AbstractCommandLineOrderTaskIntegrationTest.groovy @@ -137,6 +137,7 @@ abstract class AbstractCommandLineOrderTaskIntegrationTest extends AbstractInteg final Set localState = [] final Set inputFiles = [] boolean shouldBlock + String failMessage TaskFixture(ProjectFixture project, String path) { this.project = project @@ -206,6 +207,11 @@ abstract class AbstractCommandLineOrderTaskIntegrationTest extends AbstractInteg return this } + TaskFixture fail(String message = 'BOOM') { + failMessage = message + return this + } + String getConfig() { return """ tasks.register('${name}') { @@ -219,6 +225,7 @@ abstract class AbstractCommandLineOrderTaskIntegrationTest extends AbstractInteg ${inputFiles.collect { 'inputs.files ' + it }.join('\n\t\t\t\t')} doLast { ${shouldBlock ? server.callFromTaskAction(path) : ''} + ${failMessage ? "throw new RuntimeException('$failMessage')" : ''} } } """.stripIndent() diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/DestroyerTaskCommandLineOrderIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/DestroyerTaskCommandLineOrderIntegrationTest.groovy index 410f84d1119e..1feb64c043fd 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/api/DestroyerTaskCommandLineOrderIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/api/DestroyerTaskCommandLineOrderIntegrationTest.groovy @@ -16,7 +16,6 @@ package org.gradle.api - import org.gradle.integtests.fixtures.executer.TaskOrderSpecs import spock.lang.Issue @@ -448,4 +447,20 @@ class DestroyerTaskCommandLineOrderIntegrationTest extends AbstractCommandLineOr where: type << ProductionType.values() } + + def "build finishes with --continue even when producer task fails"() { + def clean = rootBuild.task('clean').destroys('build') + def compileJava = rootBuild.task('compileJava').outputs('build/classes/java').fail() + def compileGroovy = rootBuild.task('compileGroovy').outputs('build/classes/groovy').dependsOn(compileJava) + def classes = rootBuild.task('classes').dependsOn(compileJava).dependsOn(compileGroovy) + + writeAllFiles() + + when: + fails(clean.path, classes.path, '--continue') + then: + failure.assertHasDescription("Execution failed for task ':compileJava'.") + failure.assertHasFailures(1) + outputDoesNotContain('Unable to make progress running work.') + } } diff --git a/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalGroup.java b/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalGroup.java index 708db6cad9fb..15c90c7c1229 100644 --- a/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalGroup.java +++ b/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalGroup.java @@ -68,7 +68,6 @@ public OrdinalNode getProducerLocationsNode() { if (previous != null) { producerLocationsNode.addDependencySuccessor(previous.getProducerLocationsNode()); } - producerLocationsNode.require(); } return producerLocationsNode; } @@ -79,7 +78,6 @@ public OrdinalNode getDestroyerLocationsNode() { if (previous != null) { destroyerLocationsNode.addDependencySuccessor(previous.getDestroyerLocationsNode()); } - destroyerLocationsNode.require(); } return destroyerLocationsNode; } diff --git a/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalNodeAccess.java b/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalNodeAccess.java index ddd67fec715e..3fa63c182aba 100644 --- a/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalNodeAccess.java +++ b/subprojects/core/src/main/java/org/gradle/execution/plan/OrdinalNodeAccess.java @@ -59,6 +59,7 @@ void addProducerNode(OrdinalGroup ordinal, LocalTaskNode producer, Consumer ordinalNodeConsumer, OrdinalNode node) { if (requiredNodes.add(node)) { + node.require(); for (Node successor : node.getDependencySuccessors()) { if (successor instanceof OrdinalNode) { maybeSchedule(ordinalNodeConsumer, (OrdinalNode) successor);