diff --git a/src/Client.php b/src/Client.php index d7943d2..6285aab 100644 --- a/src/Client.php +++ b/src/Client.php @@ -1186,6 +1186,39 @@ public function imageSearch($term) )->then(array($this->parser, 'expectJson')); } + /** + * Create a new image from a container + * + * @param ?string $container The ID or name of the container to commit + * @param ?string $repo Repository name for the created image + * @param ?string $tag Tag name for the created image + * @param ?string $comment Commit message + * @param ?string $author Author of the image (e.g., John Hannibal Smith ) + * @param bool $pause Whether to pause the container before committing, default: true + * @param ?string $changes Dockerfile's instructions to apply while committing + * @param array $config The container configuration (body of the request) + * @return PromiseInterface + * @link https://docs.docker.com/engine/api/v1.41/#operation/ImageCommit + */ + public function containerCommit($container, $repo = null, $tag = null, $comment = null, $author = null, $pause = true, $changes = null, array $config = array()) + { + return $this->postJson( + $this->uri->expand( + 'commit{?container,repo,tag,comment,author,pause,changes}', + array( + 'container' => $container, + 'repo' => $repo, + 'tag' => $tag, + 'comment' => $comment, + 'author' => $author, + 'pause' => $pause, + 'changes' => $changes, + ) + ), + $config + )->then(array($this->parser, 'expectJson')); + } + /** * Sets up an exec instance in a running container id * diff --git a/tests/ClientTest.php b/tests/ClientTest.php index a4ef334..0ebdc18 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -601,6 +601,24 @@ public function testImageSearch() $this->expectPromiseResolveWith($json, $this->client->imageSearch('clue')); } + public function testCommit() + { + $json = array(); + $config = array(); + $this->expectRequestFlow('post', 'commit?container=123&pause=1', $this->createResponseJson($json), 'expectJson'); + + $this->expectPromiseResolveWith($json, $this->client->containerCommit('123', $config)); + } + + public function testCommitWithAllParams() + { + $json = array(); + $config = array(); + $this->expectRequestFlow('post', 'commit?container=123&repo=docker.io&tag=latest&comment=hello&author=batman&pause=1&changes=EXPOSE%208080', $this->createResponseJson($json), 'expectJson'); + + $this->expectPromiseResolveWith($json, $this->client->containerCommit('123', 'docker.io', 'latest', 'hello', 'batman', true, 'EXPOSE 8080', $config)); + } + public function testExecCreate() { $json = array(); diff --git a/tests/FunctionalClientTest.php b/tests/FunctionalClientTest.php index 1c1fc6e..d04bac8 100644 --- a/tests/FunctionalClientTest.php +++ b/tests/FunctionalClientTest.php @@ -435,7 +435,7 @@ public function testCreateConnectDisconnectAndRemoveNetwork() 'Image' => 'busybox', 'Cmd' => array('echo', 'test') ); - $networkName = uniqid('reactphp-docker'); + $networkName = uniqid('reactphp-docker', true); $promise = $this->client->containerCreate($containerConfig); $container = Block\await($promise, Loop::get()); @@ -473,9 +473,53 @@ public function testCreateConnectDisconnectAndRemoveNetwork() $ret = Block\await($promise, Loop::get()); // expects "create", "disconnect", "destroy" events ("connect" will be skipped because we don't start the container) - $this->assertEquals(3, count($ret)); + $this->assertCount(3, $ret); $this->assertEquals('create', $ret[0]['Action']); $this->assertEquals('disconnect', $ret[1]['Action']); $this->assertEquals('destroy', $ret[2]['Action']); } + + /** + * @depends testImageInspectCheckIfBusyboxExists + */ + public function testCreateAndCommitContainer() + { + $config = array( + 'Image' => 'busybox', + 'Cmd' => array('echo', 'test') + ); + + $promise = $this->client->containerCreate($config); + $container = Block\await($promise, Loop::get()); + + $this->assertNotNull($container['Id']); + $this->assertEmpty($container['Warnings']); + + $promise = $this->client->containerCommit($container['Id']); + $image = Block\await($promise, Loop::get()); + + $this->assertNotNull($image['Id']); + $this->assertArrayNotHasKey('message', $image); + + $promise = $this->client->containerRemove($container['Id'], false, true); + $ret = Block\await($promise, Loop::get()); + + $this->assertEquals('', $ret); + + $config = array( + 'Image' => $image['Id'], + 'Cmd' => array('echo', 'test') + ); + + $promise = $this->client->containerCreate($config); + $container = Block\await($promise, Loop::get()); + + $this->assertNotNull($container['Id']); + $this->assertEmpty($container['Warnings']); + + $promise = $this->client->containerRemove($container['Id'], false, true); + $ret = Block\await($promise, Loop::get()); + + $this->assertEquals('', $ret); + } }