diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPlugin.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPlugin.groovy index d7f27a7..946790e 100644 --- a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPlugin.groovy +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPlugin.groovy @@ -76,7 +76,7 @@ class DockerPlugin implements Plugin { def extension = project.extensions.create(EXTENSION_NAME, DockerPluginExtension) extension.with { maintainer = '' - dockerBinary = DOCKER_BINARY + dockerBinary = [DOCKER_BINARY] registry = '' useApi = Boolean.FALSE hostUrl = '' diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPluginExtension.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPluginExtension.groovy index 9d1920e..1e1f6e2 100644 --- a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPluginExtension.groovy +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerPluginExtension.groovy @@ -21,7 +21,7 @@ class DockerPluginExtension { String registry // path to the docker binary - String dockerBinary + List dockerBinary // use docker REST api (with docker-java) Boolean useApi diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerTaskBase.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerTaskBase.groovy index 3350bdb..a54fb18 100644 --- a/src/main/groovy/se/transmode/gradle/plugins/docker/DockerTaskBase.groovy +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/DockerTaskBase.groovy @@ -41,8 +41,8 @@ abstract class DockerTaskBase extends DefaultTask { // Should we use Docker's remote API instead of the docker executable Boolean useApi - // Full path to the docker executable - String dockerBinary + // Full path to the docker executable, including any commandline options + List dockerBinary // URL of the remote Docker host (default: localhost) String hostUrl @@ -56,10 +56,19 @@ abstract class DockerTaskBase extends DefaultTask { applicationName = project.name } + void setDockerBinary(String binary) { + dockerBinary = [binary] + } + + void setDockerBinary(List binary) { + dockerBinary = binary + } + void setTagVersion(String version) { tagVersion = version; } + void setTagVersionToLatest() { tagVersion = LATEST_VERSION; } diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutor.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutor.groovy new file mode 100644 index 0000000..b98a830 --- /dev/null +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutor.groovy @@ -0,0 +1,7 @@ +package se.transmode.gradle.plugins.docker.client + +interface CommandExecutor { + + String executeAndWait(List cmdLine); + +} diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorImpl.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorImpl.groovy new file mode 100644 index 0000000..544967e --- /dev/null +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorImpl.groovy @@ -0,0 +1,18 @@ +package se.transmode.gradle.plugins.docker.client + +import com.google.common.base.Preconditions +import org.gradle.api.GradleException + +class CommandExecutorImpl implements CommandExecutor { + + String executeAndWait(List cmdLine) { + Preconditions.checkArgument((cmdLine && !cmdLine.isEmpty()), "Docker binary can not be empty or null.") + def process = cmdLine.execute() + process.waitForProcessOutput(System.out, System.err) + if (process.exitValue()) { + throw new GradleException("Docker execution failed\nCommand line [${cmdLine}]") + } + return "Done" + } + +} diff --git a/src/main/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClient.groovy b/src/main/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClient.groovy index b8a24fa..7306660 100644 --- a/src/main/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClient.groovy +++ b/src/main/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClient.groovy @@ -19,35 +19,37 @@ import org.gradle.api.GradleException class NativeDockerClient implements DockerClient { - private final String binary; + private final List binary + private CommandExecutor commandExecutor - NativeDockerClient(String binary) { - Preconditions.checkArgument(binary as Boolean, "Docker binary can not be empty or null.") - this.binary = binary + NativeDockerClient(List binary) { + Preconditions.checkArgument((binary && !binary.isEmpty()), "Docker binary can not be empty or null.") + this.binary = Collections.unmodifiableList(binary) + this.commandExecutor = new CommandExecutorImpl() + } + + void setCommandExecutor(CommandExecutor executor){ + this.commandExecutor = executor } @Override String buildImage(File buildDir, String tag, boolean pull) { Preconditions.checkArgument(tag as Boolean, "Image tag can not be empty or null.") - def cmdLine = [binary, "build", "--pull=${pull}", "-t", tag, buildDir.toString() ] - return executeAndWait(cmdLine) + List cmdLine = [] + cmdLine.addAll(binary) + cmdLine.addAll(["build", "--pull=${pull}", "-t", tag, buildDir.toString()]) + return commandExecutor.executeAndWait(cmdLine) } @Override String pushImage(String tag) { Preconditions.checkArgument(tag as Boolean, "Image tag can not be empty or null.") - def cmdLine = [binary, "push", tag] - return executeAndWait(cmdLine) + List cmdLine = [] + cmdLine.addAll(binary) + cmdLine.addAll(["push", tag]) + return commandExecutor.executeAndWait(cmdLine) } - private static String executeAndWait(List cmdLine) { - def process = cmdLine.execute() - process.waitForProcessOutput(System.out, System.err) - if (process.exitValue()) { - throw new GradleException("Docker execution failed\nCommand line [${cmdLine}]") - } - return "Done" - } @Override String run(String tag, String containerName, boolean detached, boolean autoRemove, @@ -66,21 +68,23 @@ class NativeDockerClient implements DockerClient { def detachedArg = detached ? '-d' : '' def removeArg = autoRemove ? '--rm' : '' - def List cmdLine = [binary, "run", detachedArg, removeArg, "--name" , containerName] + List cmdLine = [] + cmdLine.addAll(binary) + cmdLine.addAll(["run", detachedArg, removeArg, "--name" , containerName]) cmdLine = appendArguments(cmdLine, env, "--env", '=') cmdLine = appendArguments(cmdLine, ports, "--publish") cmdLine = appendArguments(cmdLine, volumes, "--volume") cmdLine = appendArguments(cmdLine, volumesFrom, "--volumes-from") cmdLine = appendArguments(cmdLine, links, "--link") cmdLine.add(tag) - return executeAndWait(cmdLine) + return commandExecutor.executeAndWait(cmdLine) } private static List appendArguments(List cmdLine, Map map, String option, String separator = ':') { // Add each entry in the map as the indicated argument map.each { key, value -> - cmdLine.add(option); + cmdLine.add(option) cmdLine.add("${key}${separator}${value}") } return cmdLine @@ -89,8 +93,8 @@ class NativeDockerClient implements DockerClient { private static List appendArguments(List cmdLine, List list, String option) { // Add each entry in the map as the indicated argument list.each { - cmdLine.add(option); - cmdLine.add(it); + cmdLine.add(option) + cmdLine.add(it) } return cmdLine } diff --git a/src/test/groovy/se/transmode/gradle/plugins/docker/DockerTaskBaseTest.groovy b/src/test/groovy/se/transmode/gradle/plugins/docker/DockerTaskBaseTest.groovy index 87657f8..1ff8e01 100644 --- a/src/test/groovy/se/transmode/gradle/plugins/docker/DockerTaskBaseTest.groovy +++ b/src/test/groovy/se/transmode/gradle/plugins/docker/DockerTaskBaseTest.groovy @@ -51,6 +51,13 @@ class DockerTaskBaseTest { return project } + @Test + public void setDockerBinaryWithArgs() { + def project = createProject() + project.dummyTask.dockerBinary = ['a', 'b'] + assertThat(project.dummyTask.dockerBinary.size , equalTo(2)) + } + @Test public void getNativeClient() { def project = createProject() diff --git a/src/test/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorTest.groovy b/src/test/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorTest.groovy new file mode 100644 index 0000000..1be1c40 --- /dev/null +++ b/src/test/groovy/se/transmode/gradle/plugins/docker/client/CommandExecutorTest.groovy @@ -0,0 +1,19 @@ +package se.transmode.gradle.plugins.docker.client + + +import org.junit.Test + + +class CommandExecutorTest { + + @Test(expected = IllegalArgumentException) + void testExecuteWithNullArg(){ + new CommandExecutorImpl().executeAndWait(null) + } + + @Test(expected = IllegalArgumentException) + void testExecuteWithEmptyArg(){ + new CommandExecutorImpl().executeAndWait([]) + } + +} diff --git a/src/test/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClientTest.groovy b/src/test/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClientTest.groovy new file mode 100644 index 0000000..762206d --- /dev/null +++ b/src/test/groovy/se/transmode/gradle/plugins/docker/client/NativeDockerClientTest.groovy @@ -0,0 +1,56 @@ +package se.transmode.gradle.plugins.docker.client + +import org.junit.Before +import org.junit.Test + +import static java.util.Collections.EMPTY_LIST +import static java.util.Collections.EMPTY_MAP +import static org.mockito.Mockito.* + + +class NativeDockerClientTest { + + NativeDockerClient client + CommandExecutor mockExecutor + + @Before + void before(){ + mockExecutor = mock(CommandExecutor.class) + } + + @Test(expected = IllegalArgumentException) + void testConstructorWithEmptyBinary(){ + new NativeDockerClient(EMPTY_LIST) + } + + @Test(expected = IllegalArgumentException) + void testConstructorWithNullBinary(){ + new NativeDockerClient(null) + } + + @Test + void testBuild(){ + client = new NativeDockerClient(["docker"]) + client.commandExecutor = mockExecutor + client.buildImage(new File(""), 'tag', false) + verify(mockExecutor).executeAndWait(anyList()) + + } + + @Test + void testPush(){ + client = new NativeDockerClient(["docker", "-H", "1.2.3"]) + client.commandExecutor = mockExecutor + client.pushImage( 'tag') + verify(mockExecutor).executeAndWait(["docker", "-H", "1.2.3", "push", "tag"]) + } + + @Test + void testRun(){ + client = new NativeDockerClient(["docker"]) + client.commandExecutor = mockExecutor + client.run('tag', 'cname',false, false, EMPTY_MAP, EMPTY_MAP, EMPTY_MAP, EMPTY_LIST, EMPTY_LIST) + verify(mockExecutor).executeAndWait(anyList()) + } + +}