diff --git a/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerPushImageFunctionalTest.groovy b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerPushImageFunctionalTest.groovy new file mode 100644 index 000000000..8f3be116d --- /dev/null +++ b/src/functTest/groovy/com/bmuschko/gradle/docker/tasks/image/DockerPushImageFunctionalTest.groovy @@ -0,0 +1,49 @@ +package com.bmuschko.gradle.docker.tasks.image + +import com.bmuschko.gradle.docker.AbstractGroovyDslFunctionalTest +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.TaskOutcome + +class DockerPushImageFunctionalTest extends AbstractGroovyDslFunctionalTest { + + def "fails on push error"() { + def image = createUniqueImageId() + + buildFile << """ + import com.bmuschko.gradle.docker.tasks.image.Dockerfile + import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage + import com.bmuschko.gradle.docker.tasks.image.DockerPushImage + import com.bmuschko.gradle.docker.tasks.image.DockerRemoveImage + + task dockerfile(type: Dockerfile) { + from '$TEST_IMAGE_WITH_TAG' + label(['maintainer': 'jane.doe@example.com']) + } + + task buildImage(type: DockerBuildImage) { + dependsOn dockerfile + inputDir = file("build/docker") + images.add("${image}") + } + + task removeImage(type: DockerRemoveImage) { + dependsOn buildImage + targetImageId "${image}" + force = true + } + + task pushAndRemoveImage(type: DockerPushImage) { + dependsOn buildImage + images.add("${image}") + finalizedBy removeImage + } + """ + + when: + BuildResult result = buildAndFail('pushAndRemoveImage') + + then: + result.task(':pushAndRemoveImage').outcome == TaskOutcome.FAILED + result.output.contains("Could not push image") + } +} diff --git a/src/main/java/com/bmuschko/gradle/docker/tasks/image/DockerPushImage.java b/src/main/java/com/bmuschko/gradle/docker/tasks/image/DockerPushImage.java index b98d54edc..961fcb4b5 100644 --- a/src/main/java/com/bmuschko/gradle/docker/tasks/image/DockerPushImage.java +++ b/src/main/java/com/bmuschko/gradle/docker/tasks/image/DockerPushImage.java @@ -20,6 +20,7 @@ import com.bmuschko.gradle.docker.tasks.RegistryCredentialsAware; import com.github.dockerjava.api.async.ResultCallback; import com.github.dockerjava.api.command.PushImageCmd; +import com.github.dockerjava.api.exception.DockerClientException; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.PushResponseItem; import org.gradle.api.Action; @@ -27,6 +28,8 @@ import org.gradle.api.provider.SetProperty; import org.gradle.api.tasks.Input; +import javax.annotation.Nullable; + public class DockerPushImage extends AbstractDockerRemoteApiTask implements RegistryCredentialsAware { /** @@ -80,14 +83,30 @@ public void registryCredentials(Action action } private ResultCallback.Adapter createCallback(final Action nextHandler) { + // Workaround to manually handle error logic - see https://github.com/docker-java/docker-java/issues/2140 return new ResultCallback.Adapter() { + @Nullable + private PushResponseItem latestItem = null; + @Override public void onNext(PushResponseItem item) { + this.latestItem = item; + if (nextHandler != null) { nextHandler.execute(item); } } + @Override + protected void throwFirstError() { + super.throwFirstError(); + + if (latestItem == null) { + throw new DockerClientException("Could not push image"); + } else if (latestItem.isErrorIndicated()) { + throw new DockerClientException("Could not push image: " + latestItem.getError()); + } + } }; } }